@ab-org/predicate-market-sdk 0.0.1 → 0.1.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.
@@ -1,13 +1,15 @@
1
1
  /**
2
- * Merchant API client (BaseUrl: https://merchant.tomo.services)
2
+ * Merchant API client
3
3
  * 基于 axios 封装,类型与文档一致。
4
4
  */
5
5
  import { getEnv } from "../utils/env.js";
6
6
  import axios from "axios";
7
- const DEFAULT_MERCHANT_BASE_URL = "https://merchant.tomo.services";
8
7
  // ─── Axios 实例与请求封装 ─────────────────────────────────────────────────────
9
8
  function createClient() {
10
- const BASE_URL = getEnv("MERCHANT_BASE_URL") || DEFAULT_MERCHANT_BASE_URL;
9
+ const BASE_URL = getEnv("MERCHANT_BASE_URL");
10
+ if (!BASE_URL) {
11
+ throw new Error('MERCHANT_BASE_URL is not set');
12
+ }
11
13
  return axios.create({
12
14
  baseURL: BASE_URL,
13
15
  timeout: 30000,
@@ -24,7 +26,7 @@ function unwrap(res) {
24
26
  // 单例 client,可通过 configureMerchantApi 修改 baseURL
25
27
  let apiClient = createClient();
26
28
  /**
27
- * 配置 Merchant API 的 baseURL(可选,默认 https://merchant.tomo.services)
29
+ * 配置 Merchant API 的 baseURL
28
30
  */
29
31
  export function configureMerchantApi() {
30
32
  apiClient = createClient();
@@ -8,13 +8,20 @@ export interface Erc20BalanceResult {
8
8
  * No external library dependency – uses the global `fetch`.
9
9
  */
10
10
  export declare function fetchErc20Balance(rpcUrl: string, tokenAddress: string, walletAddress: string): Promise<bigint>;
11
- export interface BscUsd1BalanceOptions {
11
+ export interface FundingTokenBalanceOptions {
12
12
  rpcUrl?: string;
13
13
  tokenAddress?: string;
14
14
  decimals?: number;
15
+ /**
16
+ * Funding chain id (e.g. `"3131"` Tenderly BSC, `"56"` mainnet).
17
+ * When omitted, defaults to `3131` via {@link getChainInfo}.
18
+ */
19
+ chainId?: string | number | null;
20
+ /** Label for {@link Erc20BalanceResult.symbol} (default `"Funding"`). */
21
+ displaySymbol?: string;
15
22
  }
16
23
  /**
17
- * Convenience wrapper fetches the USD1 balance on BSC for a given wallet.
18
- * All parameters have sensible defaults and can be overridden.
24
+ * Fetches the configured funding ERC-20 balance on the selected funding chain.
25
+ * Defaults: chain `3131`, RPC from {@link getChainInfo}, token from {@link getFundingTokenAddress} / env.
19
26
  */
20
- export declare function fetchBscUsd1Balance(walletAddress: string, options?: BscUsd1BalanceOptions): Promise<Erc20BalanceResult>;
27
+ export declare function fetchFundingTokenBalance(walletAddress: string, options?: FundingTokenBalanceOptions): Promise<Erc20BalanceResult>;
@@ -1,7 +1,6 @@
1
- import { testBsc, BSC_USD1_ADDRESS } from "../constants/chains.js";
1
+ import { getEnv } from "../utils/env";
2
+ import { getFundingTokenAddress, getChainInfo } from "../constants/chains.js";
2
3
  const ERC20_BALANCE_OF_SELECTOR = "0x70a08231";
3
- const USD1_DECIMALS = testBsc.nativeCurrencyDecimals;
4
- const BSC_RPC_URL = testBsc.rpcUrls[0];
5
4
  function padAddress(address) {
6
5
  return address.toLowerCase().replace("0x", "").padStart(64, "0");
7
6
  }
@@ -42,17 +41,20 @@ export async function fetchErc20Balance(rpcUrl, tokenAddress, walletAddress) {
42
41
  return BigInt(json.result ?? "0x0");
43
42
  }
44
43
  /**
45
- * Convenience wrapper fetches the USD1 balance on BSC for a given wallet.
46
- * All parameters have sensible defaults and can be overridden.
44
+ * Fetches the configured funding ERC-20 balance on the selected funding chain.
45
+ * Defaults: chain `3131`, RPC from {@link getChainInfo}, token from {@link getFundingTokenAddress} / env.
47
46
  */
48
- export async function fetchBscUsd1Balance(walletAddress, options) {
49
- const rpcUrl = options?.rpcUrl ?? BSC_RPC_URL;
50
- const tokenAddress = options?.tokenAddress ?? BSC_USD1_ADDRESS;
51
- const decimals = options?.decimals ?? USD1_DECIMALS;
47
+ export async function fetchFundingTokenBalance(walletAddress, options) {
48
+ const chain = getChainInfo(options?.chainId);
49
+ const rpcUrl = options?.rpcUrl ?? chain.rpcUrls[0];
50
+ const tokenAddress = options?.tokenAddress ?? getFundingTokenAddress(options?.chainId);
51
+ const decimals = options?.decimals ?? chain.nativeCurrencyDecimals;
52
+ const FUNDING_TOKEN_SYMBOL = getEnv("FUNDING_TOKEN_SYMBOL");
53
+ const displaySymbol = options?.displaySymbol ?? (FUNDING_TOKEN_SYMBOL || "Funding");
52
54
  const raw = await fetchErc20Balance(rpcUrl, tokenAddress, walletAddress);
53
55
  return {
54
56
  raw,
55
57
  formatted: formatBalanceDisplay(raw, decimals),
56
- symbol: "USD1",
58
+ symbol: displaySymbol,
57
59
  };
58
60
  }
@@ -1,8 +1,8 @@
1
1
  import type { MarketDataProvider } from "../types.js";
2
2
  /**
3
- * Market data provider backed by merchant API.
4
- * - getSupportedTokens / getSupportedChains: from GET https://merchant.tomo.services/chains
5
- * - getQuote: mock (no quote API yet)
6
- * - getDepositAddress: from session (no deposit-address API in this service)
3
+ * Default `MarketDataProvider` backed by the merchant chains API.
4
+ * - getSupportedTokens / getSupportedChains: from GET `{merchantBase}/chains`
5
+ * - getQuote: local estimate until a dedicated quote API exists
6
+ * - getDepositAddress: 当前 session 钱包地址 + `token`/`chain` 匹配的 `GET /chains` 中 `minimum_deposit`(按 decimals 格式化)
7
7
  */
8
- export declare function createMockMarketDataProvider(): MarketDataProvider;
8
+ export declare function createMarketDataProvider(): MarketDataProvider;
@@ -1,45 +1,20 @@
1
1
  import { sessionStore } from "@ab-org/sdk-core";
2
- import { getEnv } from "../utils/env.js";
3
- const DEFAULT_MERCHANT_BASE_URL = "https://merchant.tomo.services";
2
+ import { formatUnits } from "viem";
3
+ import { getChains } from "./api.js";
4
4
  let cachedChains = null;
5
- /** Fallback when chains API fails (network error, 4xx/5xx, parse error, missing base URL). */
6
- const MOCK_CHAINS_FALLBACK = [
7
- {
8
- chain_id: "56",
9
- network: "BSC",
10
- tokens: [
11
- { symbol: "USD1", address: "0x", decimals: 18 },
12
- { symbol: "USDT", address: "0x", decimals: 6 },
13
- { symbol: "USDC", address: "0x", decimals: 6 },
14
- ],
15
- },
16
- {
17
- chain_id: "ETH",
18
- network: "Ethereum",
19
- tokens: [
20
- { symbol: "USDT", address: "0x", decimals: 6 },
21
- { symbol: "USDC", address: "0x", decimals: 6 },
22
- ],
23
- },
24
- ];
25
5
  async function fetchChainsFromApi() {
26
6
  if (cachedChains)
27
7
  return cachedChains;
28
8
  try {
29
- const CHAINS_API_BASE = getEnv("MERCHANT_BASE_URL") || DEFAULT_MERCHANT_BASE_URL;
30
- const res = await fetch(`${CHAINS_API_BASE}/chains`);
31
- if (!res.ok)
32
- throw new Error(`Chains API error: ${res.status} ${res.statusText}`);
33
- const json = (await res.json());
34
- const chains = json.data?.chains ?? [];
9
+ const { chains } = await getChains();
35
10
  if (chains.length > 0) {
36
11
  cachedChains = chains;
37
12
  return chains;
38
13
  }
39
- return MOCK_CHAINS_FALLBACK;
14
+ return [];
40
15
  }
41
16
  catch {
42
- return MOCK_CHAINS_FALLBACK;
17
+ return [];
43
18
  }
44
19
  }
45
20
  function chainToChainInfo(chain) {
@@ -48,6 +23,22 @@ function chainToChainInfo(chain) {
48
23
  name: chain.network,
49
24
  };
50
25
  }
26
+ function findTokenInChains(chains, chainId, tokenSymbol) {
27
+ const chain = chains.find((c) => c.chain_id === chainId);
28
+ return chain?.tokens.find((t) => t.symbol === tokenSymbol);
29
+ }
30
+ /** `minimum_deposit` 为链上最小单位整数字符串,按 `decimals` 转成可读金额并拼 token 符号 */
31
+ function formatMinimumDepositDisplay(token, tokenSymbol) {
32
+ const raw = token.minimum_deposit?.trim();
33
+ if (raw == null || raw === "")
34
+ return undefined;
35
+ try {
36
+ return `${formatUnits(BigInt(raw), token.decimals)} ${tokenSymbol}`;
37
+ }
38
+ catch {
39
+ return `${raw} ${tokenSymbol}`;
40
+ }
41
+ }
51
42
  function deriveTokensFromChains(chains) {
52
43
  const bySymbol = new Map();
53
44
  for (const chain of chains) {
@@ -63,7 +54,7 @@ function deriveTokensFromChains(chains) {
63
54
  }
64
55
  return Array.from(bySymbol.values());
65
56
  }
66
- function computeMockQuote(request) {
57
+ function computeDefaultQuote(request) {
67
58
  const isStable = ["USDT", "USDC", "USD1"].includes(request.token);
68
59
  const slippage = isStable ? "0.3" : "1.0";
69
60
  const feeRate = request.direction === "withdraw" ? 0.001 : 0;
@@ -81,12 +72,12 @@ function computeMockQuote(request) {
81
72
  };
82
73
  }
83
74
  /**
84
- * Market data provider backed by merchant API.
85
- * - getSupportedTokens / getSupportedChains: from GET https://merchant.tomo.services/chains
86
- * - getQuote: mock (no quote API yet)
87
- * - getDepositAddress: from session (no deposit-address API in this service)
75
+ * Default `MarketDataProvider` backed by the merchant chains API.
76
+ * - getSupportedTokens / getSupportedChains: from GET `{merchantBase}/chains`
77
+ * - getQuote: local estimate until a dedicated quote API exists
78
+ * - getDepositAddress: 当前 session 钱包地址 + `token`/`chain` 匹配的 `GET /chains` 中 `minimum_deposit`(按 decimals 格式化)
88
79
  */
89
- export function createMockMarketDataProvider() {
80
+ export function createMarketDataProvider() {
90
81
  return {
91
82
  async getSupportedTokens(_direction) {
92
83
  const chains = await fetchChainsFromApi();
@@ -100,13 +91,16 @@ export function createMockMarketDataProvider() {
100
91
  return list.map(chainToChainInfo);
101
92
  },
102
93
  async getQuote(request) {
103
- return computeMockQuote(request);
94
+ return computeDefaultQuote(request);
104
95
  },
105
- async getDepositAddress(_token, _chain) {
96
+ async getDepositAddress(token, chain) {
106
97
  const session = sessionStore.getState().session;
98
+ const chains = await fetchChainsFromApi();
99
+ const meta = findTokenInChains(chains, chain, token);
100
+ const minimumDeposit = meta != null ? formatMinimumDepositDisplay(meta, token) : undefined;
107
101
  return {
108
102
  address: session?.address ?? "",
109
- minimumDeposit: "15.00",
103
+ minimumDeposit,
110
104
  };
111
105
  },
112
106
  };
@@ -0,0 +1,14 @@
1
+ import type { ChainData, TokenData } from "./api.js";
2
+ /**
3
+ * funding 链(与 {@link DEFAULT_FUNDING_CHAIN_ID} 一致)上,且 `tokenAddress` 在 Merchant `GET /chains`
4
+ * 中对应条目的 `is_usd_stable === true` 时,由业务层自行完成提现并构造 `withdrawDirectResult`;
5
+ * 其余情况走默认 funding 提现执行器与订单轮询。
6
+ */
7
+ export declare function isUsdtWithdrawDirect(chainId: string, tokenAddress: string, chains: ChainData[]): boolean;
8
+ /**
9
+ * 从 `getChains()` 返回的 `chains` 中,按当前选择的链 id + token symbol 或合约地址解析 `TokenData`。
10
+ */
11
+ export declare function findTokenDataFromChains(chains: ChainData[], chainId: string, opts: {
12
+ symbol: string;
13
+ tokenAddress?: string;
14
+ }): TokenData | undefined;
@@ -0,0 +1,33 @@
1
+ import { DEFAULT_FUNDING_CHAIN_ID } from "../constants/chains.js";
2
+ /**
3
+ * funding 链(与 {@link DEFAULT_FUNDING_CHAIN_ID} 一致)上,且 `tokenAddress` 在 Merchant `GET /chains`
4
+ * 中对应条目的 `is_usd_stable === true` 时,由业务层自行完成提现并构造 `withdrawDirectResult`;
5
+ * 其余情况走默认 funding 提现执行器与订单轮询。
6
+ */
7
+ export function isUsdtWithdrawDirect(chainId, tokenAddress, chains) {
8
+ if (chainId !== String(DEFAULT_FUNDING_CHAIN_ID))
9
+ return false;
10
+ const addr = tokenAddress.trim();
11
+ if (!addr)
12
+ return false;
13
+ const chain = chains.find((c) => c.chain_id === chainId);
14
+ const token = chain?.tokens.find((t) => t.address.toLowerCase() === addr.toLowerCase());
15
+ return token?.is_usd_stable === true;
16
+ }
17
+ /**
18
+ * 从 `getChains()` 返回的 `chains` 中,按当前选择的链 id + token symbol 或合约地址解析 `TokenData`。
19
+ */
20
+ export function findTokenDataFromChains(chains, chainId, opts) {
21
+ const chain = chains.find((c) => c.chain_id === chainId);
22
+ if (!chain?.tokens.length)
23
+ return undefined;
24
+ const sym = opts.symbol.trim();
25
+ const addr = opts.tokenAddress?.trim().toLowerCase();
26
+ return chain.tokens.find((t) => {
27
+ if (addr && t.address.toLowerCase() === addr)
28
+ return true;
29
+ if (sym.length > 0 && t.symbol === sym)
30
+ return true;
31
+ return false;
32
+ });
33
+ }
@@ -9,7 +9,7 @@ export interface WithdrawRequest {
9
9
  chain: string;
10
10
  }
11
11
  export interface WithdrawResult {
12
- /** BSC 上转入一次性地址的 funding tx hash */
12
+ /** Funding 链上转入一次性地址的 tx hash */
13
13
  txHash: string;
14
14
  /** 提现订单 ID,用于轮询 getWithdrawOrder(orderId) */
15
15
  orderId: string;
@@ -30,18 +30,27 @@ export type WithdrawExecutor = (request: WithdrawRequest) => Promise<WithdrawRes
30
30
  * "100.1" → 100100000000000000000n
31
31
  */
32
32
  export declare function parseUnits(value: string, decimals: number): bigint;
33
- export interface BscUsd1WithdrawExecutorOptions {
34
- /** 源代币 USD1 合约地址(提现场景下为 BSC 上的 USD1) */
33
+ export interface FundingWithdrawExecutorOptions {
34
+ /** 源链 funding ERC-20 合约地址;默认 {@link getFundingTokenAddress} / env */
35
35
  tokenAddress?: string;
36
36
  decimals?: number;
37
- chainId?: number;
37
+ /**
38
+ * Funding EVM chain id(如 `3131` Tenderly、`56` 主网)。未传时默认 `3131`。
39
+ */
40
+ chainId?: number | string;
41
+ /** 覆盖 {@link getChainInfo} 提供的 JSON-RPC URL */
42
+ rpcUrl?: string;
38
43
  /** 系统配置的单笔限额(wei 字符串),若提供则校验 request.amount 不得超过此值 */
39
44
  maxAmountWei?: string;
45
+ /**
46
+ * 与商户订单接口约定的 funding 侧 token symbol(默认 `USD1`,按后端协议)。
47
+ */
48
+ fundingLegTokenSymbol?: string;
40
49
  }
41
50
  /**
42
51
  * Factory that returns a `WithdrawExecutor` implementing the flow in withdraw.md:
43
52
  * 1) Create NATIVE_SWAP order → get one-time wallet address (OTW);
44
- * 2) Sign ERC-20 transfer of USD1 on BSC to the OTW (not to user);
53
+ * 2) Sign ERC-20 transfer of the funding token on the funding chain to the OTW (not to user);
45
54
  * 3) Broadcast tx and return { txHash, orderId } for the client to poll getWithdrawOrder(orderId).
46
55
  */
47
- export declare function createBscUsd1WithdrawExecutor(options?: BscUsd1WithdrawExecutorOptions): WithdrawExecutor;
56
+ export declare function createFundingWithdrawExecutor(options?: FundingWithdrawExecutorOptions): WithdrawExecutor;
@@ -2,12 +2,10 @@ import { sessionStore } from "@ab-org/sdk-core";
2
2
  import { tryAutoReconnect } from "../auth/autoReconnect.js";
3
3
  import { getChains, createOrder } from "./api.js";
4
4
  import { fromHex, parseGwei, toHex } from "viem";
5
- import { testBsc, BSC_USD1_ADDRESS } from "../constants/chains.js";
5
+ import { getFundingTokenAddress, getChainInfo } from "../constants/chains.js";
6
6
  const MAX_WITHDRAW_GAS_LIMIT = 500000n;
7
- const BSC_RPC_URL = testBsc.rpcUrls[0];
8
7
  /* ─── Internal helpers ────────────────────────── */
9
8
  const ERC20_TRANSFER_SELECTOR = "0xa9059cbb";
10
- const USD1_DECIMALS = testBsc.nativeCurrencyDecimals;
11
9
  function padHex256(value) {
12
10
  return value.toString(16).padStart(64, "0");
13
11
  }
@@ -82,13 +80,13 @@ async function requestHexQuantity(provider, rpcUrl, method, params) {
82
80
  return toHexQuantity(await callRpc(rpcUrl, method, params));
83
81
  }
84
82
  }
85
- async function ensureBscChain(provider, chainId) {
83
+ async function ensureFundingEvmChain(provider, chainId) {
86
84
  const hex = `0x${chainId.toString(16)}`;
87
85
  try {
88
86
  await provider.request({ method: "wallet_switchEthereumChain", params: [{ chainId: hex }] });
89
87
  }
90
88
  catch {
91
- // Ignored – the wallet may already be on BSC or may not support switching.
89
+ // Ignored – the wallet may already be on the funding chain or may not support switching.
92
90
  }
93
91
  }
94
92
  function getDstTokenAddress(chains, chainId, tokenSymbol) {
@@ -98,14 +96,17 @@ function getDstTokenAddress(chains, chainId, tokenSymbol) {
98
96
  /**
99
97
  * Factory that returns a `WithdrawExecutor` implementing the flow in withdraw.md:
100
98
  * 1) Create NATIVE_SWAP order → get one-time wallet address (OTW);
101
- * 2) Sign ERC-20 transfer of USD1 on BSC to the OTW (not to user);
99
+ * 2) Sign ERC-20 transfer of the funding token on the funding chain to the OTW (not to user);
102
100
  * 3) Broadcast tx and return { txHash, orderId } for the client to poll getWithdrawOrder(orderId).
103
101
  */
104
- export function createBscUsd1WithdrawExecutor(options) {
105
- const tokenAddress = options?.tokenAddress ?? BSC_USD1_ADDRESS;
106
- const decimals = options?.decimals ?? USD1_DECIMALS;
102
+ export function createFundingWithdrawExecutor(options) {
103
+ const fundingChain = getChainInfo(options?.chainId);
104
+ const chainIdNum = Number(fundingChain.chainId);
105
+ const rpcUrl = options?.rpcUrl ?? fundingChain.rpcUrls[0];
106
+ const tokenAddress = options?.tokenAddress ?? getFundingTokenAddress(options?.chainId);
107
+ const decimals = options?.decimals ?? fundingChain.nativeCurrencyDecimals;
107
108
  const maxAmountWei = options?.maxAmountWei;
108
- const chainId = options?.chainId ?? Number(testBsc.chainId);
109
+ const fundingLegTokenSymbol = options?.fundingLegTokenSymbol ?? "USD1";
109
110
  return async (request) => {
110
111
  const amountWei = parseUnits(request.amount, decimals);
111
112
  const amountWeiStr = amountWei.toString();
@@ -139,13 +140,13 @@ export function createBscUsd1WithdrawExecutor(options) {
139
140
  if (!dstTokenAddress) {
140
141
  throw new Error(`Unsupported token ${request.token} on chain ${request.chain}`);
141
142
  }
142
- // 校验规则:源代币或目标代币中必须有一个是 USD1。提现场景下源代币(token_address)为 USD1;token_amount 已按 maxAmountWei 做单笔限额校验
143
- const sourceTokenSymbol = "USD1";
143
+ // 校验规则:源/目标代币需满足商户约定;提现场景下源链为 funding token;token_amount 已按 maxAmountWei 做单笔限额校验
144
+ const sourceTokenSymbol = fundingLegTokenSymbol;
144
145
  const orderRes = await createOrder({
145
146
  intent_id: `withdraw-${Date.now()}`,
146
147
  order_type: "NATIVE_SWAP",
147
148
  order_payload: {
148
- chain_id: String(chainId),
149
+ chain_id: fundingChain.chainId,
149
150
  token_address: tokenAddress,
150
151
  token_amount: amountWeiStr,
151
152
  dst_chain_id: request.chain,
@@ -158,7 +159,7 @@ export function createBscUsd1WithdrawExecutor(options) {
158
159
  token_amount: amountWeiStr,
159
160
  token_address: tokenAddress,
160
161
  user_address: session.address,
161
- chain_id: String(chainId),
162
+ chain_id: fundingChain.chainId,
162
163
  },
163
164
  ],
164
165
  });
@@ -166,18 +167,18 @@ export function createBscUsd1WithdrawExecutor(options) {
166
167
  if (!oneTimeAddress) {
167
168
  throw new Error("Order created but no one-time wallet address returned");
168
169
  }
169
- await ensureBscChain(provider, chainId);
170
+ await ensureFundingEvmChain(provider, chainIdNum);
170
171
  const data = encodeTransferData(oneTimeAddress, amountWei);
171
- const nonce = await requestHexQuantity(provider, BSC_RPC_URL, "eth_getTransactionCount", [session.address, "latest"]);
172
+ const nonce = await requestHexQuantity(provider, rpcUrl, "eth_getTransactionCount", [session.address, "latest"]);
172
173
  const tx = {
173
174
  from: session.address,
174
175
  to: tokenAddress,
175
176
  value: "0x0",
176
177
  nonce,
177
178
  data,
178
- chainId: toHex(chainId),
179
+ chainId: toHex(chainIdNum),
179
180
  };
180
- const estimatedGasHex = await requestHexQuantity(provider, BSC_RPC_URL, "eth_estimateGas", [tx]);
181
+ const estimatedGasHex = await requestHexQuantity(provider, rpcUrl, "eth_estimateGas", [tx]);
181
182
  const estimatedGas = fromHex(estimatedGasHex, "bigint");
182
183
  const gas = toHex(estimatedGas > MAX_WITHDRAW_GAS_LIMIT ? MAX_WITHDRAW_GAS_LIMIT : estimatedGas);
183
184
  const transaction = {
@@ -201,8 +202,8 @@ export function createBscUsd1WithdrawExecutor(options) {
201
202
  method: "eth_signTransaction",
202
203
  params: [transaction],
203
204
  });
204
- txHash = await callRpc(BSC_RPC_URL, "eth_sendRawTransaction", [signedTx]);
205
+ txHash = await callRpc(rpcUrl, "eth_sendRawTransaction", [signedTx]);
205
206
  }
206
- return { txHash, orderId: orderRes.order_id, fundingChainId: String(chainId) };
207
+ return { txHash, orderId: orderRes.order_id, fundingChainId: fundingChain.chainId };
207
208
  };
208
209
  }
@@ -9,6 +9,7 @@ import { LoginRequiredOverlay } from "./components/LoginRequiredOverlay.js";
9
9
  import { useSession } from "./hooks/useSession.js";
10
10
  import { colors, fonts, radii } from "./theme.js";
11
11
  import { getChains, quote, } from "../modules/api.js";
12
+ import { getEnv } from "../utils/env";
12
13
  /** 校验是否为合法的充值地址(传入值):非空且长度满足常见链地址格式 */
13
14
  function isValidDepositAddress(v) {
14
15
  return typeof v === "string" && v.trim().length >= 20;
@@ -43,8 +44,6 @@ const DefaultCryptoIcons = () => {
43
44
  }, children: t.label }, i))) }));
44
45
  };
45
46
  /* ─── Helpers: derive options from getChains ─── */
46
- /** Deposit 时不可选 USD1(充值是转入 USD1,源代币为 USDT/USDC 等) */
47
- const DEPOSIT_EXCLUDED_TOKEN = "USD1";
48
47
  function chainsToTokenOptions(chains) {
49
48
  const bySymbol = new Map();
50
49
  for (const c of chains) {
@@ -54,7 +53,6 @@ function chainsToTokenOptions(chains) {
54
53
  }
55
54
  }
56
55
  return Array.from(bySymbol.entries())
57
- .filter(([id]) => id !== DEPOSIT_EXCLUDED_TOKEN)
58
56
  .map(([id, { symbol }]) => ({
59
57
  id,
60
58
  label: symbol,
@@ -88,6 +86,8 @@ function getTokenAddressForChain(chains, chainId, tokenSymbol) {
88
86
  const chain = chains.find((c) => c.chain_id === chainId);
89
87
  return chain?.tokens.find((t) => t.symbol === tokenSymbol)?.address;
90
88
  }
89
+ /* ─── Main Component ─────────────────────────── */
90
+ const FUNDING_TOKEN_SYMBOL = getEnv("FUNDING_TOKEN_SYMBOL");
91
91
  export const DepositModal = ({ token, chain, tokenOptions: tokenOptionsProp, chainOptions: chainOptionsProp, depositAddress, minimumDeposit, qrCenterIcon, cryptoIcons, depositAmount, onShowToast, txHash, explorerTxUrl, onTokenSelect, onChainSelect, onCopyAddress, onBuyCrypto, onSignIn, onBack, onClose, }) => {
92
92
  const session = useSession();
93
93
  const [view, setView] = useState("entry");
@@ -98,9 +98,8 @@ export const DepositModal = ({ token, chain, tokenOptions: tokenOptionsProp, cha
98
98
  const [loadingQuote, setLoadingQuote] = useState(false);
99
99
  const [quoteRefreshKey, setQuoteRefreshKey] = useState(0);
100
100
  const tokenOptions = useMemo(() => {
101
- const excludeUsd1 = (opts) => opts.filter((o) => o.id !== DEPOSIT_EXCLUDED_TOKEN && o.label !== DEPOSIT_EXCLUDED_TOKEN);
102
101
  if (tokenOptionsProp?.length)
103
- return excludeUsd1(tokenOptionsProp);
102
+ return tokenOptionsProp;
104
103
  if (!apiChains?.length)
105
104
  return undefined;
106
105
  return chainsToTokenOptions(apiChains);
@@ -112,12 +111,6 @@ export const DepositModal = ({ token, chain, tokenOptions: tokenOptionsProp, cha
112
111
  return undefined;
113
112
  return chainsToChainOptionsForToken(apiChains, token);
114
113
  }, [chainOptionsProp, apiChains, token]);
115
- // 当前选中的是 USD1 时自动切到第一个可选 token(deposit 不允许选 USD1)
116
- useEffect(() => {
117
- if (token !== DEPOSIT_EXCLUDED_TOKEN || !tokenOptions?.length || !onTokenSelect)
118
- return;
119
- onTokenSelect(tokenOptions[0].id);
120
- }, [token, tokenOptions, onTokenSelect]);
121
114
  // 仅有一个 chain 选项时默认选中
122
115
  useEffect(() => {
123
116
  if (chainOptions?.length !== 1 || !onChainSelect)
@@ -166,7 +159,7 @@ export const DepositModal = ({ token, chain, tokenOptions: tokenOptionsProp, cha
166
159
  rate: "1",
167
160
  chain_id: Number(chain) || 56,
168
161
  deposit_address: "0x" + "0".repeat(39) + "1",
169
- usd1_amount: depositAmount ?? "0",
162
+ dst_token_amount: depositAmount ?? "0",
170
163
  expires_at: new Date(Date.now() + 60000).toISOString(),
171
164
  });
172
165
  })
@@ -227,7 +220,7 @@ export const DepositModal = ({ token, chain, tokenOptions: tokenOptionsProp, cha
227
220
  rate: "1",
228
221
  chain_id: Number(chain) || 56,
229
222
  deposit_address: "0x" + "0".repeat(39) + "1",
230
- usd1_amount: depositAmount ?? "0",
223
+ dst_token_amount: depositAmount ?? "0",
231
224
  expires_at: new Date(Date.now() + 60000).toISOString(),
232
225
  });
233
226
  })
@@ -302,7 +295,7 @@ const TransferView = ({ token, chain, tokenOptions, chainOptions, depositAddress
302
295
  display: "flex",
303
296
  flexDirection: "column",
304
297
  gap: 8,
305
- }, children: quoteLoading ? (_jsx("span", { style: { fontSize: 13, color: colors.textSecondary }, children: "Loading\u2026" })) : (_jsxs(_Fragment, { children: [_jsxs("span", { style: { fontSize: 13, color: colors.textSecondary }, children: ["1 ", quoteData.token_symbol, " = ", quoteData.rate, " USD1"] }), quoteData.expires_at && (_jsx(Countdown, { expiresAt: quoteData.expires_at, isExpired: quoteExpired, onExpired: onQuoteExpired })), quoteExpired && (_jsxs("div", { style: { display: "flex", alignItems: "center", gap: 8 }, children: [_jsx("span", { style: { fontSize: 13, color: "#f59e0b" }, children: "Quote expired, please refresh" }), onRefreshQuote && (_jsx("button", { type: "button", onClick: onRefreshQuote, style: {
298
+ }, children: quoteLoading ? (_jsx("span", { style: { fontSize: 13, color: colors.textSecondary }, children: "Loading\u2026" })) : (_jsxs(_Fragment, { children: [_jsxs("span", { style: { fontSize: 13, color: colors.textSecondary }, children: ["1 ", quoteData.token_symbol, " = ", quoteData.rate, " ", FUNDING_TOKEN_SYMBOL] }), quoteData.expires_at && (_jsx(Countdown, { expiresAt: quoteData.expires_at, isExpired: quoteExpired, onExpired: onQuoteExpired })), quoteExpired && (_jsxs("div", { style: { display: "flex", alignItems: "center", gap: 8 }, children: [_jsx("span", { style: { fontSize: 13, color: "#f59e0b" }, children: "Quote expired, please refresh" }), onRefreshQuote && (_jsx("button", { type: "button", onClick: onRefreshQuote, style: {
306
299
  padding: "4px 12px",
307
300
  fontSize: 12,
308
301
  borderRadius: radii.pill,
@@ -2,12 +2,14 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useState } from "react";
3
3
  import { sessionStore } from "@ab-org/sdk-core";
4
4
  import { getSDKConfig } from "../auth/config.js";
5
+ import { clearSocialAccountInstance as clearEmbeddedWalletAccount } from "../auth/walletAccount.js";
5
6
  import { resolveSocialProviders } from "./SignInModal.shared.js";
6
7
  import { SignInModalFooter, SignInModalFrame, SignInModalSocialSection, SignInModalWalletGrid, } from "./SignInModal.sections.js";
7
8
  import { useSignInModalController } from "./useSignInModalController.js";
8
9
  import { Toast } from "./components/Toast.js";
9
10
  export function clearSocialAccountInstance() {
10
11
  try {
12
+ clearEmbeddedWalletAccount();
11
13
  const storage = typeof localStorage !== "undefined" ? localStorage : null;
12
14
  const adapterId = storage?.getItem("ab:wallet:adapterId");
13
15
  const session = sessionStore.getState().session;
@@ -22,6 +24,7 @@ export function clearSocialAccountInstance() {
22
24
  storage?.removeItem("ab:wallet:adapterId");
23
25
  }
24
26
  catch {
27
+ clearEmbeddedWalletAccount();
25
28
  sessionStore.clearSession();
26
29
  }
27
30
  }
@@ -66,6 +66,20 @@ const IconFrame = ({ background, children, }) => (_jsx("div", { style: {
66
66
  justifyContent: "center",
67
67
  overflow: "hidden",
68
68
  }, children: children }));
69
+ const MetaMaskWalletIcon = () => (_jsx(IconFrame, { background: "#1A0F07", children: _jsxs("svg", { width: "32", height: "32", viewBox: "0 0 32 32", fill: "none", children: [_jsx("path", { d: "M8 6L15 11L12 14L8 6Z", fill: "#E17726" }), _jsx("path", { d: "M24 6L17 11L20 14L24 6Z", fill: "#E27625" }), _jsx("path", { d: "M11 19L15 22V17L11 19Z", fill: "#F6851B" }), _jsx("path", { d: "M21 19L17 22V17L21 19Z", fill: "#F6851B" }), _jsx("path", { d: "M12 14L15 11V17L11 19L12 14Z", fill: "#763D16" }), _jsx("path", { d: "M20 14L17 11V17L21 19L20 14Z", fill: "#763D16" })] }) }));
70
+ const OKXWalletIcon = () => (_jsx(IconFrame, { background: "#FFFFFF", children: _jsxs("svg", { width: "30", height: "30", viewBox: "0 0 30 30", fill: "none", children: [_jsx("rect", { x: "2", y: "2", width: "8", height: "8", rx: "2", fill: "#050608" }), _jsx("rect", { x: "11", y: "2", width: "8", height: "8", rx: "2", fill: "#050608" }), _jsx("rect", { x: "20", y: "2", width: "8", height: "8", rx: "2", fill: "#050608" }), _jsx("rect", { x: "2", y: "11", width: "8", height: "8", rx: "2", fill: "#050608" }), _jsx("rect", { x: "20", y: "11", width: "8", height: "8", rx: "2", fill: "#050608" }), _jsx("rect", { x: "2", y: "20", width: "8", height: "8", rx: "2", fill: "#050608" }), _jsx("rect", { x: "11", y: "20", width: "8", height: "8", rx: "2", fill: "#050608" }), _jsx("rect", { x: "20", y: "20", width: "8", height: "8", rx: "2", fill: "#050608" })] }) }));
71
+ const CoinbaseWalletIcon = () => (_jsx(IconFrame, { background: "#0052FF", children: _jsxs("svg", { width: "30", height: "30", viewBox: "0 0 30 30", fill: "none", children: [_jsx("circle", { cx: "15", cy: "15", r: "10", stroke: "white", strokeWidth: "4" }), _jsx("rect", { x: "9", y: "13", width: "12", height: "4", rx: "2", fill: "white" })] }) }));
72
+ const TrustWalletIcon = () => (_jsx(IconFrame, { background: "#3375FF", children: _jsxs("svg", { width: "28", height: "28", viewBox: "0 0 28 28", fill: "none", children: [_jsx("path", { d: "M14 4L21 6.6V12.8C21 17.1 18.1 20.9 14 22.4C9.9 20.9 7 17.1 7 12.8V6.6L14 4Z", fill: "white" }), _jsx("path", { d: "M14 8L17 9.1V12.3C17 14.7 15.7 16.8 14 17.6C12.3 16.8 11 14.7 11 12.3V9.1L14 8Z", fill: "#3375FF" })] }) }));
73
+ const PhantomWalletIcon = () => (_jsx(IconFrame, { background: "linear-gradient(135deg, #6C47FF 0%, #9B6BFF 100%)", children: _jsxs("svg", { width: "30", height: "30", viewBox: "0 0 30 30", fill: "none", children: [_jsx("path", { d: "M8 18.5C8 14.4 11.2 11 15.3 11H20.4C21.8 11 23 12.2 23 13.6C23 15 21.8 16.2 20.4 16.2H14.7", stroke: "white", strokeWidth: "3", strokeLinecap: "round" }), _jsx("path", { d: "M10.5 14H19.5", stroke: "white", strokeWidth: "3", strokeLinecap: "round" }), _jsx("circle", { cx: "12", cy: "20", r: "1.4", fill: "white" }), _jsx("circle", { cx: "18", cy: "20", r: "1.4", fill: "white" })] }) }));
74
+ const RabbyWalletIcon = () => (_jsx(IconFrame, { background: "#EBF2FF", children: _jsxs("svg", { width: "30", height: "30", viewBox: "0 0 30 30", fill: "none", children: [_jsx("path", { d: "M11 7L13.5 13", stroke: "#7084FF", strokeWidth: "3", strokeLinecap: "round" }), _jsx("path", { d: "M19 7L16.5 13", stroke: "#7084FF", strokeWidth: "3", strokeLinecap: "round" }), _jsx("rect", { x: "8", y: "12", width: "14", height: "11", rx: "6", fill: "#7084FF" }), _jsx("circle", { cx: "13", cy: "17", r: "1.4", fill: "white" }), _jsx("circle", { cx: "17", cy: "17", r: "1.4", fill: "white" }), _jsx("path", { d: "M13 20C13.6 20.4 14.3 20.6 15 20.6C15.7 20.6 16.4 20.4 17 20", stroke: "white", strokeWidth: "1.8", strokeLinecap: "round" })] }) }));
75
+ /** Rainbow icon from wallet-adaptor-base (rainbowWallet.svg) */
76
+ const RainbowWalletIcon = () => (_jsx(IconFrame, { background: "linear-gradient(180deg, #174299 0%, #001E59 100%)", children: _jsxs("svg", { width: "32", height: "32", viewBox: "0 0 120 120", fill: "none", style: { overflow: "hidden", borderRadius: 12 }, children: [_jsxs("defs", { children: [_jsxs("radialGradient", { id: "rainbow_r1", cx: "0", cy: "0", r: "1", gradientUnits: "userSpaceOnUse", gradientTransform: "translate(26 94) rotate(-90) scale(74)", children: [_jsx("stop", { offset: "0.770277", stopColor: "#FF4000" }), _jsx("stop", { offset: "1", stopColor: "#8754C9" })] }), _jsxs("linearGradient", { id: "rainbow_l2", x1: "83", y1: "97", x2: "100", y2: "97", gradientUnits: "userSpaceOnUse", children: [_jsx("stop", { stopColor: "#FF4000" }), _jsx("stop", { offset: "1", stopColor: "#8754C9" })] }), _jsxs("linearGradient", { id: "rainbow_l3", x1: "23", y1: "20", x2: "23", y2: "37", gradientUnits: "userSpaceOnUse", children: [_jsx("stop", { stopColor: "#8754C9" }), _jsx("stop", { offset: "1", stopColor: "#FF4000" })] }), _jsxs("radialGradient", { id: "rainbow_r4", cx: "0", cy: "0", r: "1", gradientUnits: "userSpaceOnUse", gradientTransform: "translate(26 94) rotate(-90) scale(58)", children: [_jsx("stop", { offset: "0.723929", stopColor: "#FFF700" }), _jsx("stop", { offset: "1", stopColor: "#FF9901" })] }), _jsxs("linearGradient", { id: "rainbow_l5", x1: "68", y1: "97", x2: "84", y2: "97", gradientUnits: "userSpaceOnUse", children: [_jsx("stop", { stopColor: "#FFF700" }), _jsx("stop", { offset: "1", stopColor: "#FF9901" })] }), _jsxs("linearGradient", { id: "rainbow_l6", x1: "23", y1: "52", x2: "23", y2: "36", gradientUnits: "userSpaceOnUse", children: [_jsx("stop", { stopColor: "#FFF700" }), _jsx("stop", { offset: "1", stopColor: "#FF9901" })] }), _jsxs("radialGradient", { id: "rainbow_r7", cx: "0", cy: "0", r: "1", gradientUnits: "userSpaceOnUse", gradientTransform: "translate(26 94) rotate(-90) scale(42)", children: [_jsx("stop", { offset: "0.59513", stopColor: "#00AAFF" }), _jsx("stop", { offset: "1", stopColor: "#01DA40" })] }), _jsxs("radialGradient", { id: "rainbow_r8", cx: "0", cy: "0", r: "1", gradientUnits: "userSpaceOnUse", gradientTransform: "translate(51 97) scale(17 45.3333)", children: [_jsx("stop", { stopColor: "#00AAFF" }), _jsx("stop", { offset: "1", stopColor: "#01DA40" })] }), _jsxs("radialGradient", { id: "rainbow_r9", cx: "0", cy: "0", r: "1", gradientUnits: "userSpaceOnUse", gradientTransform: "translate(23 69) rotate(-90) scale(17 322.37)", children: [_jsx("stop", { stopColor: "#00AAFF" }), _jsx("stop", { offset: "1", stopColor: "#01DA40" })] })] }), _jsx("path", { d: "M20 38H26C56.9279 38 82 63.0721 82 94V100H94C97.3137 100 100 97.3137 100 94C100 53.1309 66.8691 20 26 20C22.6863 20 20 22.6863 20 26V38Z", fill: "url(#rainbow_r1)" }), _jsx("path", { d: "M84 94H100C100 97.3137 97.3137 100 94 100H84V94Z", fill: "url(#rainbow_l2)" }), _jsx("path", { d: "M26 20L26 36H20L20 26C20 22.6863 22.6863 20 26 20Z", fill: "url(#rainbow_l3)" }), _jsx("path", { d: "M20 36H26C58.0325 36 84 61.9675 84 94V100H66V94C66 71.9086 48.0914 54 26 54H20V36Z", fill: "url(#rainbow_r4)" }), _jsx("path", { d: "M68 94H84V100H68V94Z", fill: "url(#rainbow_l5)" }), _jsx("path", { d: "M20 52L20 36L26 36L26 52H20Z", fill: "url(#rainbow_l6)" }), _jsx("path", { d: "M20 62C20 65.3137 22.6863 68 26 68C40.3594 68 52 79.6406 52 94C52 97.3137 54.6863 100 58 100H68V94C68 70.804 49.196 52 26 52H20V62Z", fill: "url(#rainbow_r7)" }), _jsx("path", { d: "M52 94H68V100H58C54.6863 100 52 97.3137 52 94Z", fill: "url(#rainbow_r8)" }), _jsx("path", { d: "M26 68C22.6863 68 20 65.3137 20 62L20 52L26 52L26 68Z", fill: "url(#rainbow_r9)" })] }) }));
77
+ /** Zerion icon from wallet-adaptor-base (zerionWallet.svg) */
78
+ const ZerionWalletIcon = () => (_jsx(IconFrame, { background: "#2962EF", children: _jsx("svg", { width: "28", height: "28", viewBox: "0 0 28 28", fill: "none", children: _jsx("path", { fill: "#fff", d: "M6.073 7c-.48 0-.665.593-.262.841l10.073 6.074a.577.577 0 0 0 .758-.139l4.43-5.814c.3-.404-.004-.962-.525-.962H6.073ZM21.904 21c.48 0 .67-.596.267-.844l-10.075-6.073a.569.569 0 0 0-.751.146l-4.437 5.813c-.301.404.012.958.534.958h14.462Z" }) }) }));
79
+ /** Brave Wallet icon from wallet-adaptor-base (braveWallet.svg), scaled */
80
+ const BraveWalletIcon = () => (_jsx(IconFrame, { background: "#FFF", children: _jsxs("svg", { width: "32", height: "32", viewBox: "-100 -100 2970 2970", fill: "none", style: { overflow: "hidden", borderRadius: 12 }, children: [_jsxs("defs", { children: [_jsxs("linearGradient", { id: "brave_a", y1: "51%", y2: "51%", children: [_jsx("stop", { offset: "0.4", stopColor: "#f50" }), _jsx("stop", { offset: "0.6", stopColor: "#ff2000" })] }), _jsxs("linearGradient", { id: "brave_b", x1: "2%", y1: "51%", x2: "51%", y2: "51%", children: [_jsx("stop", { offset: "0", stopColor: "#ff452a" }), _jsx("stop", { offset: "1", stopColor: "#ff2000" })] })] }), _jsx("path", { fill: "url(#brave_a)", d: "m2395 723 60-147-170-176c-92-92-288-38-288-38l-222-252H992L769 363s-196-53-288 37L311 575l60 147-75 218 250 953c52 204 87 283 234 387l457 310c44 27 98 74 147 74s103-47 147-74l457-310c147-104 182-183 234-387l250-953z" }), _jsx("path", { fill: "#fff", d: "M1935 524s287 347 287 420c0 75-36 94-72 133l-215 230c-20 20-63 54-38 113 25 60 60 134 20 210-40 77-110 128-155 120a820 820 0 0 1-190-90c-38-25-160-126-160-165s126-110 150-124c23-16 130-78 132-102s2-30-30-90-88-140-80-192c10-52 100-80 167-105l207-78c16-8 12-15-36-20-48-4-183-22-244-5s-163 43-173 57c-8 14-16 14-7 62l58 315c4 40 12 67-30 77-44 10-117 27-142 27s-99-17-142-27-35-37-30-77c4-40 48-268 57-315 10-48 1-48-7-62-10-14-113-40-174-57-60-17-196 1-244 6-48 4-52 10-36 20l207 77c66 25 158 53 167 105 10 53-47 132-80 192s-32 66-30 90 110 86 132 102c24 15 150 85 150 124s-119 140-159 165a820 820 0 0 1-190 90c-45 8-115-43-156-120-40-76-4-150 20-210 25-60-17-92-38-113l-215-230c-35-37-71-57-71-131s287-420 287-420l273 44c32 0 103-27 168-50 65-20 110-22 110-22s44 0 110 22 136 50 168 50c33 0 275-47 275-47zm-215 1328c18 10 7 32-10 44l-254 198c-20 20-52 50-73 50s-52-30-73-50a13200 13200 0 0 0-255-198c-16-12-27-33-10-44l150-80a870 870 0 0 1 188-73c15 0 110 34 187 73l150 80z" }), _jsx("path", { fill: "url(#brave_b)", d: "m1999 363-224-253H992L769 363s-196-53-288 37c0 0 260-23 350 123l276 47c32 0 103-27 168-50 65-20 110-22 110-22s44 0 110 22 136 50 168 50c33 0 275-47 275-47 90-146 350-123 350-123-92-92-288-38-288-38" })] }) }));
81
+ /** Bitget icon from wallet-adaptor-base (bitgetWallet.svg) */
82
+ const BitgetWalletIcon = () => (_jsx(IconFrame, { background: "#001F29", children: _jsx("svg", { width: "28", height: "28", viewBox: "0 0 512 512", fill: "none", children: _jsx("path", { d: "M219.948 95.7022C201.623 95.6929 183.33 95.6835 164.941 95.7116C153.822 95.7116 149.651 109.671 157.921 117.939L283.098 243.117C287.004 246.69 289.441 250.574 289.53 255.693C289.441 260.812 287.004 264.696 283.098 268.269L157.921 393.446C149.651 401.715 153.822 415.674 164.941 415.674C183.33 415.702 201.623 415.693 219.948 415.683C229.122 415.679 238.305 415.674 247.511 415.674C259.555 415.674 266.72 409.24 273.154 402.805L386.047 289.912C395.057 280.902 403.119 268.939 403.009 255.693C403.119 242.447 395.057 230.484 386.047 221.474L273.154 108.58C266.72 102.146 259.555 95.7116 247.511 95.7116C238.305 95.7116 229.122 95.7069 219.948 95.7022Z", fill: "#00F0FF" }) }) }));
69
83
  const walletIconTheme = {
70
84
  metamask: "#F6851B",
71
85
  okx: "#050608",
@@ -84,4 +98,29 @@ const WalletPlaceholder = ({ walletId, name }) => (_jsx(IconFrame, { background:
84
98
  color: walletIconTheme[walletId] ? "#FFFFFF" : colors.textSecondary,
85
99
  fontFamily: fonts.family,
86
100
  }, children: name.slice(0, 2).toUpperCase() }) }));
87
- export const DefaultWalletIcon = ({ walletId, name, }) => _jsx(WalletPlaceholder, { walletId: walletId, name: name });
101
+ export const DefaultWalletIcon = ({ walletId, name, }) => {
102
+ switch (walletId) {
103
+ case "metamask":
104
+ return _jsx(MetaMaskWalletIcon, {});
105
+ case "okx":
106
+ return _jsx(OKXWalletIcon, {});
107
+ case "coinbase":
108
+ return _jsx(CoinbaseWalletIcon, {});
109
+ case "trust":
110
+ return _jsx(TrustWalletIcon, {});
111
+ case "phantom":
112
+ return _jsx(PhantomWalletIcon, {});
113
+ case "rabby":
114
+ return _jsx(RabbyWalletIcon, {});
115
+ case "rainbow":
116
+ return _jsx(RainbowWalletIcon, {});
117
+ case "zerion":
118
+ return _jsx(ZerionWalletIcon, {});
119
+ case "brave":
120
+ return _jsx(BraveWalletIcon, {});
121
+ case "bitget":
122
+ return _jsx(BitgetWalletIcon, {});
123
+ default:
124
+ return _jsx(WalletPlaceholder, { walletId: walletId, name: name });
125
+ }
126
+ };