@ab-org/predicate-market-sdk 2.0.0 → 2.0.1-beta.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.
@@ -0,0 +1,527 @@
1
+ import { getChainInfo, getFundingTokenAddress, DEFAULT_FUNDING_CHAIN_ID } from './chunk-F2UPP3YC.js';
2
+ import { getChains, createOrder } from './chunk-TPMI3XWV.js';
3
+ import { tryAutoReconnect } from './chunk-26RFAFJG.js';
4
+ import { getEnv } from './chunk-SHLNBZBY.js';
5
+ import { sessionStore, createSessionCapabilityPolicy } from '@ab-org/sdk-core';
6
+ import { toHex, fromHex, parseGwei, formatUnits } from 'viem';
7
+
8
+ function requireSession() {
9
+ const session = sessionStore.getState().session;
10
+ if (!session) throw new Error("Login required");
11
+ return session;
12
+ }
13
+ var createDepositController = (custody, marketData) => {
14
+ let status = { phase: "idle" };
15
+ const notify = (next, cb) => {
16
+ status = next;
17
+ cb?.(status);
18
+ };
19
+ const open = async (config) => {
20
+ const session = requireSession();
21
+ const chain = config?.preferredChain ?? session.chainContext?.settlementChain ?? session.chain ?? "AB_CORE";
22
+ const token = config?.preferredToken || getEnv("FUNDING_TOKEN_SYMBOL") || "USDT";
23
+ try {
24
+ const { address } = await marketData.getDepositAddress(token, chain);
25
+ const depositId = `${chain}:${token}:${Date.now()}`;
26
+ notify({ phase: "address-issued", depositId, address }, config?.onStatusChange);
27
+ notify({ phase: "confirming", depositId }, config?.onStatusChange);
28
+ const { status: finalStatus, txHash } = await custody.getDepositStatus(depositId);
29
+ notify(
30
+ finalStatus === "SETTLED" ? { phase: "settled", depositId, txHash } : { phase: "failed", reason: finalStatus },
31
+ config?.onStatusChange
32
+ );
33
+ } catch (error) {
34
+ notify({ phase: "failed", reason: error.message }, config?.onStatusChange);
35
+ }
36
+ };
37
+ return {
38
+ get status() {
39
+ return status;
40
+ },
41
+ open,
42
+ fetchTokens() {
43
+ requireSession();
44
+ return marketData.getSupportedTokens("deposit");
45
+ },
46
+ fetchChains(token) {
47
+ requireSession();
48
+ return marketData.getSupportedChains(token, "deposit");
49
+ },
50
+ fetchQuote(token, chain, amount) {
51
+ requireSession();
52
+ return marketData.getQuote({ token, chain, amount, direction: "deposit" });
53
+ },
54
+ fetchDepositAddress(token, chain) {
55
+ requireSession();
56
+ return marketData.getDepositAddress(token, chain);
57
+ }
58
+ };
59
+ };
60
+ function requireSession2() {
61
+ const session = sessionStore.getState().session;
62
+ if (!session) throw new Error("Login required");
63
+ return session;
64
+ }
65
+ var createWithdrawController = (custody, marketData) => {
66
+ let status = { phase: "idle" };
67
+ const update = (next, cb) => {
68
+ status = next;
69
+ cb?.(status);
70
+ };
71
+ const open = async (config) => {
72
+ const session = requireSession2();
73
+ const token = config?.defaultToken || getEnv("FUNDING_TOKEN_SYMBOL") || "USDT";
74
+ const chain = config?.defaultChain ?? session.chainContext?.settlementChain ?? session.chain ?? "AB_CORE";
75
+ const targetAddress = config?.targetAddress;
76
+ if (!targetAddress) throw new Error("targetAddress required for withdraw");
77
+ try {
78
+ const { requestId } = await custody.requestWithdraw({
79
+ amount: config?.defaultAmount ?? "0",
80
+ token,
81
+ chain,
82
+ targetAddress
83
+ });
84
+ update({ phase: "requested", requestId }, config?.onStatusChange);
85
+ update({ phase: "processing", requestId }, config?.onStatusChange);
86
+ const { status: finalStatus, txHash } = await custody.getWithdrawStatus(requestId);
87
+ update(
88
+ finalStatus === "SETTLED" ? { phase: "settled", requestId, txHash } : { phase: "failed", reason: finalStatus },
89
+ config?.onStatusChange
90
+ );
91
+ } catch (error) {
92
+ update({ phase: "failed", reason: error.message }, config?.onStatusChange);
93
+ }
94
+ };
95
+ return {
96
+ get status() {
97
+ return status;
98
+ },
99
+ open,
100
+ fetchTokens() {
101
+ requireSession2();
102
+ return marketData.getSupportedTokens("withdraw");
103
+ },
104
+ fetchChains(token) {
105
+ requireSession2();
106
+ return marketData.getSupportedChains(token, "withdraw");
107
+ },
108
+ fetchQuote(token, chain, amount) {
109
+ requireSession2();
110
+ return marketData.getQuote({ token, chain, amount, direction: "withdraw" });
111
+ }
112
+ };
113
+ };
114
+ var cachedChains = null;
115
+ async function fetchChainsFromApi() {
116
+ if (cachedChains) return cachedChains;
117
+ try {
118
+ const { chains } = await getChains();
119
+ if (chains.length > 0) {
120
+ cachedChains = chains;
121
+ return chains;
122
+ }
123
+ return [];
124
+ } catch {
125
+ return [];
126
+ }
127
+ }
128
+ function chainToChainInfo(chain) {
129
+ return {
130
+ id: chain.chain_id,
131
+ name: chain.network
132
+ };
133
+ }
134
+ function findTokenInChains(chains, chainId, tokenSymbol) {
135
+ const chain = chains.find((c) => c.chain_id === chainId);
136
+ return chain?.tokens.find((t) => t.symbol === tokenSymbol);
137
+ }
138
+ function formatMinimumDepositDisplay(token, tokenSymbol) {
139
+ const raw = token.minimum_deposit?.trim();
140
+ if (raw == null || raw === "") return void 0;
141
+ try {
142
+ return `${formatUnits(BigInt(raw), token.decimals)} ${tokenSymbol}`;
143
+ } catch {
144
+ return `${raw} ${tokenSymbol}`;
145
+ }
146
+ }
147
+ function deriveTokensFromChains(chains) {
148
+ const bySymbol = /* @__PURE__ */ new Map();
149
+ for (const chain of chains) {
150
+ for (const t of chain.tokens) {
151
+ if (!bySymbol.has(t.symbol)) {
152
+ bySymbol.set(t.symbol, {
153
+ symbol: t.symbol,
154
+ name: t.symbol,
155
+ decimals: t.decimals
156
+ });
157
+ }
158
+ }
159
+ }
160
+ return Array.from(bySymbol.values());
161
+ }
162
+ function computeDefaultQuote(request) {
163
+ const isStable = ["USDT", "USDC", "USD1"].includes(request.token);
164
+ const slippage = isStable ? "0.3" : "1.0";
165
+ const feeRate = request.direction === "withdraw" ? 1e-3 : 0;
166
+ const amount = Number(request.amount) || 0;
167
+ const fee = (amount * feeRate).toFixed(2);
168
+ const estimatedAmount = (amount - Number(fee)).toFixed(6);
169
+ return {
170
+ quoteId: `quote-${Date.now()}`,
171
+ estimatedAmount: amount > 0 ? estimatedAmount : "0",
172
+ slippage,
173
+ fee,
174
+ feeToken: request.token,
175
+ exchangeRate: "1.0",
176
+ expiresAt: Date.now() + 3e4
177
+ };
178
+ }
179
+ function createMarketDataProvider() {
180
+ return {
181
+ async getSupportedTokens(_direction) {
182
+ const chains = await fetchChainsFromApi();
183
+ const tokens = deriveTokensFromChains(chains);
184
+ return tokens.length > 0 ? tokens : [];
185
+ },
186
+ async getSupportedChains(token, _direction) {
187
+ const chains = await fetchChainsFromApi();
188
+ const forToken = chains.filter((c) => c.tokens.some((t) => t.symbol === token));
189
+ const list = forToken.length > 0 ? forToken : chains;
190
+ return list.map(chainToChainInfo);
191
+ },
192
+ async getQuote(request) {
193
+ return computeDefaultQuote(request);
194
+ },
195
+ async getDepositAddress(token, chain) {
196
+ const session = sessionStore.getState().session;
197
+ const chains = await fetchChainsFromApi();
198
+ const meta = findTokenInChains(chains, chain, token);
199
+ const minimumDeposit = meta != null ? formatMinimumDepositDisplay(meta, token) : void 0;
200
+ return {
201
+ address: session?.address ?? "",
202
+ minimumDeposit
203
+ };
204
+ }
205
+ };
206
+ }
207
+
208
+ // src/modules/balanceQuery.ts
209
+ var ERC20_BALANCE_OF_SELECTOR = "0x70a08231";
210
+ function padAddress(address) {
211
+ return address.toLowerCase().replace("0x", "").padStart(64, "0");
212
+ }
213
+ function formatUnits2(value, decimals) {
214
+ const divisor = 10n ** BigInt(decimals);
215
+ const intPart = value / divisor;
216
+ const fracPart = value % divisor;
217
+ if (fracPart === 0n) return intPart.toString();
218
+ const fracStr = fracPart.toString().padStart(decimals, "0").replace(/0+$/, "");
219
+ return `${intPart}.${fracStr}`;
220
+ }
221
+ function formatBalanceDisplay(value, decimals) {
222
+ const full = formatUnits2(value, decimals);
223
+ const n = Number(full);
224
+ return Number.isNaN(n) ? full : n.toFixed(2);
225
+ }
226
+ async function fetchErc20Balance(rpcUrl, tokenAddress, walletAddress) {
227
+ const data = `${ERC20_BALANCE_OF_SELECTOR}${padAddress(walletAddress)}`;
228
+ const response = await fetch(rpcUrl, {
229
+ method: "POST",
230
+ headers: { "Content-Type": "application/json" },
231
+ body: JSON.stringify({
232
+ jsonrpc: "2.0",
233
+ id: 1,
234
+ method: "eth_call",
235
+ params: [{ to: tokenAddress, data }, "latest"]
236
+ })
237
+ });
238
+ const json = await response.json();
239
+ if (json.error) throw new Error(json.error.message ?? "RPC error");
240
+ return BigInt(json.result ?? "0x0");
241
+ }
242
+ async function fetchFundingTokenBalance(walletAddress, options) {
243
+ const chain = getChainInfo(options?.chainId);
244
+ const rpcUrl = options?.rpcUrl ?? chain.rpcUrls[0];
245
+ const tokenAddress = options?.tokenAddress ?? getFundingTokenAddress(options?.chainId);
246
+ const decimals = options?.decimals ?? chain.nativeCurrencyDecimals;
247
+ const FUNDING_TOKEN_SYMBOL = getEnv("FUNDING_TOKEN_SYMBOL");
248
+ const displaySymbol = options?.displaySymbol ?? (FUNDING_TOKEN_SYMBOL || "Funding");
249
+ const raw = await fetchErc20Balance(rpcUrl, tokenAddress, walletAddress);
250
+ return {
251
+ raw,
252
+ formatted: formatBalanceDisplay(raw, decimals),
253
+ symbol: displaySymbol
254
+ };
255
+ }
256
+ var MAX_WITHDRAW_GAS_LIMIT = 500000n;
257
+ var ERC20_TRANSFER_SELECTOR = "0xa9059cbb";
258
+ function padHex256(value) {
259
+ return value.toString(16).padStart(64, "0");
260
+ }
261
+ function padAddress2(address) {
262
+ return address.toLowerCase().replace("0x", "").padStart(64, "0");
263
+ }
264
+ function parseUnits(value, decimals) {
265
+ if (!value || value === "0") return 0n;
266
+ const [intPart = "0", fracPart = ""] = value.split(".");
267
+ const padded = fracPart.padEnd(decimals, "0").slice(0, decimals);
268
+ return BigInt(intPart) * 10n ** BigInt(decimals) + BigInt(padded);
269
+ }
270
+ function encodeTransferData(to, amountWei) {
271
+ return `${ERC20_TRANSFER_SELECTOR}${padAddress2(to)}${padHex256(amountWei)}`;
272
+ }
273
+ function isUnsupportedMethodError(error) {
274
+ const message = error instanceof Error ? error.message : String(error);
275
+ return /unsupported rpc method|unsupported method|method not found|does not support/i.test(
276
+ message
277
+ );
278
+ }
279
+ function toHexQuantity(value) {
280
+ if (typeof value === "string") {
281
+ if (/^0x[0-9a-fA-F]+$/.test(value)) {
282
+ return value;
283
+ }
284
+ if (/^\d+$/.test(value)) {
285
+ return toHex(BigInt(value));
286
+ }
287
+ }
288
+ if (typeof value === "number") {
289
+ return toHex(BigInt(value));
290
+ }
291
+ if (typeof value === "bigint") {
292
+ return toHex(value);
293
+ }
294
+ throw new Error(`Invalid EVM quantity: ${String(value)}`);
295
+ }
296
+ async function callRpc(rpcUrl, method, params) {
297
+ const response = await fetch(rpcUrl, {
298
+ method: "POST",
299
+ headers: { "Content-Type": "application/json" },
300
+ body: JSON.stringify({
301
+ jsonrpc: "2.0",
302
+ id: Date.now(),
303
+ method,
304
+ params
305
+ })
306
+ });
307
+ const json = await response.json();
308
+ if (!response.ok || json.error) {
309
+ throw new Error(json.error?.message ?? `${method} failed`);
310
+ }
311
+ return json.result;
312
+ }
313
+ async function requestHexQuantity(provider, rpcUrl, method, params) {
314
+ try {
315
+ const result = await provider.request({ method, params });
316
+ return toHexQuantity(result);
317
+ } catch (error) {
318
+ if (!isUnsupportedMethodError(error)) {
319
+ throw error;
320
+ }
321
+ return toHexQuantity(await callRpc(rpcUrl, method, params));
322
+ }
323
+ }
324
+ async function ensureFundingEvmChain(provider, chainId) {
325
+ const hex = `0x${chainId.toString(16)}`;
326
+ try {
327
+ await provider.request({ method: "wallet_switchEthereumChain", params: [{ chainId: hex }] });
328
+ } catch {
329
+ }
330
+ }
331
+ function getDstTokenAddress(chains, chainId, tokenSymbol) {
332
+ const chain = chains.find((c) => c.chain_id === chainId);
333
+ return chain?.tokens.find((t) => t.symbol === tokenSymbol)?.address;
334
+ }
335
+ function createFundingWithdrawExecutor(options) {
336
+ const fundingChain = getChainInfo(options?.chainId);
337
+ const chainIdNum = Number(fundingChain.chainId);
338
+ const rpcUrl = options?.rpcUrl ?? fundingChain.rpcUrls[0];
339
+ const tokenAddress = options?.tokenAddress ?? getFundingTokenAddress(options?.chainId);
340
+ const decimals = options?.decimals ?? fundingChain.nativeCurrencyDecimals;
341
+ const maxAmountWei = options?.maxAmountWei;
342
+ const fundingLegTokenSymbol = options?.fundingLegTokenSymbol || getEnv("FUNDING_TOKEN_SYMBOL") || "USDT";
343
+ return async (request) => {
344
+ const amountWei = parseUnits(request.amount, decimals);
345
+ const amountWeiStr = amountWei.toString();
346
+ if (maxAmountWei != null && amountWei > BigInt(maxAmountWei)) {
347
+ throw new Error("Withdraw amount exceeds the single-transaction limit");
348
+ }
349
+ let session = sessionStore.getState().session;
350
+ if (!session) throw new Error("Login required");
351
+ let { provider } = session;
352
+ try {
353
+ await provider.request({ method: "eth_chainId", params: [] });
354
+ } catch (err) {
355
+ const msg = err.message ?? "";
356
+ if (msg.includes("restored from cache") || msg.includes("Reconnect your wallet")) {
357
+ const reconnected = await tryAutoReconnect();
358
+ if (reconnected) {
359
+ session = reconnected;
360
+ provider = reconnected.provider;
361
+ } else {
362
+ sessionStore.clearSession();
363
+ throw new Error("Session expired. Please sign in again.");
364
+ }
365
+ }
366
+ }
367
+ const chainsRes = await getChains();
368
+ const chains = chainsRes?.chains ?? [];
369
+ const dstTokenAddress = getDstTokenAddress(chains, request.chain, request.token);
370
+ if (!dstTokenAddress) {
371
+ throw new Error(`Unsupported token ${request.token} on chain ${request.chain}`);
372
+ }
373
+ const sourceTokenSymbol = fundingLegTokenSymbol;
374
+ const orderRes = await createOrder({
375
+ intent_id: `withdraw-${Date.now()}`,
376
+ order_type: "NATIVE_SWAP",
377
+ order_payload: {
378
+ chain_id: fundingChain.chainId,
379
+ token_address: tokenAddress,
380
+ token_amount: amountWeiStr,
381
+ dst_chain_id: request.chain,
382
+ dst_token_address: dstTokenAddress,
383
+ recipient: request.toAddress
384
+ },
385
+ payment_pairs: [
386
+ {
387
+ token_symbol: sourceTokenSymbol,
388
+ token_amount: amountWeiStr,
389
+ token_address: tokenAddress,
390
+ user_address: session.address,
391
+ chain_id: fundingChain.chainId
392
+ }
393
+ ]
394
+ });
395
+ const oneTimeAddress = orderRes.payment_sessions?.[0]?.one_time_wallet_address;
396
+ if (!oneTimeAddress) {
397
+ throw new Error("Order created but no one-time wallet address returned");
398
+ }
399
+ await ensureFundingEvmChain(provider, chainIdNum);
400
+ const data = encodeTransferData(oneTimeAddress, amountWei);
401
+ const nonce = await requestHexQuantity(
402
+ provider,
403
+ rpcUrl,
404
+ "eth_getTransactionCount",
405
+ [session.address, "latest"]
406
+ );
407
+ const tx = {
408
+ from: session.address,
409
+ to: tokenAddress,
410
+ value: "0x0",
411
+ nonce,
412
+ data,
413
+ chainId: toHex(chainIdNum)
414
+ };
415
+ const estimatedGasHex = await requestHexQuantity(
416
+ provider,
417
+ rpcUrl,
418
+ "eth_estimateGas",
419
+ [tx]
420
+ );
421
+ const estimatedGas = fromHex(estimatedGasHex, "bigint");
422
+ const gas = toHex(
423
+ estimatedGas > MAX_WITHDRAW_GAS_LIMIT ? MAX_WITHDRAW_GAS_LIMIT : estimatedGas
424
+ );
425
+ const transaction = {
426
+ ...tx,
427
+ gas,
428
+ maxFeePerGas: toHex(parseGwei("5")),
429
+ maxPriorityFeePerGas: toHex(parseGwei("1"))
430
+ };
431
+ let txHash;
432
+ try {
433
+ txHash = await provider.request({
434
+ method: "eth_sendTransaction",
435
+ params: [transaction]
436
+ });
437
+ } catch (error) {
438
+ if (!isUnsupportedMethodError(error)) {
439
+ throw error;
440
+ }
441
+ const signedTx = await provider.request({
442
+ method: "eth_signTransaction",
443
+ params: [transaction]
444
+ });
445
+ txHash = await callRpc(rpcUrl, "eth_sendRawTransaction", [signedTx]);
446
+ }
447
+ return { txHash, orderId: orderRes.order_id, fundingChainId: fundingChain.chainId };
448
+ };
449
+ }
450
+
451
+ // src/modules/withdrawDirect.ts
452
+ function isUsdtWithdrawDirect(chainId, tokenAddress, chains) {
453
+ if (chainId !== String(DEFAULT_FUNDING_CHAIN_ID)) return false;
454
+ const addr = tokenAddress.trim();
455
+ if (!addr) return false;
456
+ const chain = chains.find((c) => c.chain_id === chainId);
457
+ const token = chain?.tokens.find((t) => t.address.toLowerCase() === addr.toLowerCase());
458
+ return token?.is_usd_stable === true;
459
+ }
460
+ function findTokenDataFromChains(chains, chainId, opts) {
461
+ const chain = chains.find((c) => c.chain_id === chainId);
462
+ if (!chain?.tokens.length) return void 0;
463
+ const sym = opts.symbol.trim();
464
+ const addr = opts.tokenAddress?.trim().toLowerCase();
465
+ return chain.tokens.find((t) => {
466
+ if (addr && t.address.toLowerCase() === addr) return true;
467
+ if (sym.length > 0 && t.symbol === sym) return true;
468
+ return false;
469
+ });
470
+ }
471
+ var createPolicy = (overrides, options) => createSessionCapabilityPolicy({
472
+ appId: options?.appId,
473
+ origin: options?.origin,
474
+ expiresAt: options?.expiresAt,
475
+ ...overrides
476
+ });
477
+ var withActionMetadata = (action, policy) => ({
478
+ ...policy,
479
+ metadata: {
480
+ ...policy.metadata ?? {},
481
+ action
482
+ }
483
+ });
484
+ var createPredicateMarketPolicyAdapter = (options) => ({
485
+ deposit(token, chain, maxAmount) {
486
+ return withActionMetadata(
487
+ "deposit",
488
+ createPolicy(
489
+ {
490
+ methods: ["eth_sendTransaction"],
491
+ chains: [chain],
492
+ tokens: [token],
493
+ maxAmount
494
+ },
495
+ options
496
+ )
497
+ );
498
+ },
499
+ withdraw(token, chain, maxAmount) {
500
+ return withActionMetadata(
501
+ "withdraw",
502
+ createPolicy(
503
+ {
504
+ methods: ["eth_sendTransaction"],
505
+ chains: [chain],
506
+ tokens: [token],
507
+ maxAmount
508
+ },
509
+ options
510
+ )
511
+ );
512
+ },
513
+ trade(chain, capabilities = ["eth_sendTransaction"]) {
514
+ return withActionMetadata(
515
+ "trade",
516
+ createPolicy(
517
+ {
518
+ methods: capabilities,
519
+ chains: [chain]
520
+ },
521
+ options
522
+ )
523
+ );
524
+ }
525
+ });
526
+
527
+ export { createDepositController, createFundingWithdrawExecutor, createMarketDataProvider, createPredicateMarketPolicyAdapter, createWithdrawController, fetchErc20Balance, fetchFundingTokenBalance, findTokenDataFromChains, isUsdtWithdrawDirect, parseUnits };
@@ -0,0 +1,14 @@
1
+ import { getEnv, getChainInfo } from './chunk-YX56ZGDB.js';
2
+
3
+ // ../sign_in_sdk/src/config.ts
4
+ var stage = getEnv("STAGE") || "dev";
5
+ var clientIds = {
6
+ google: getEnv("GOOGLE_CLIENT_ID"),
7
+ x: getEnv("X_CLIENT_ID")
8
+ };
9
+ var chainConfig = {
10
+ chainType: "evm",
11
+ chainId: getChainInfo().chainId
12
+ };
13
+
14
+ export { chainConfig, clientIds, stage };
@@ -0,0 +1,6 @@
1
+ // src/core.ts
2
+ function tryAutoReconnect() {
3
+ return import('./autoReconnect-6YV7YSSL.js').then(({ tryAutoReconnect: reconnect }) => reconnect());
4
+ }
5
+
6
+ export { tryAutoReconnect };
@@ -0,0 +1,88 @@
1
+ import { getEnv } from './chunk-SHLNBZBY.js';
2
+
3
+ // src/constants/chains.ts
4
+ var TENDERLY_BSC_3131 = {
5
+ chainId: "3131",
6
+ name: "BSC_TENDERLY",
7
+ chainName: "BSC_TENDERLY",
8
+ nativeCurrencyName: "BSC",
9
+ nativeCurrencySymbol: "BSC",
10
+ nativeCurrencyDecimals: 18,
11
+ rpcUrls: [
12
+ "https://virtual.binance.eu.rpc.tenderly.co/e643ea28-32eb-4fb9-8116-90be24f7defa"
13
+ ],
14
+ blockExplorerUrl: "https://dashboard.tenderly.co/explorer/vnet/6593bc72-f548-497d-bff9-5be061436a48",
15
+ platformType: "EVM",
16
+ icon: "https://static.tomo.inc/token/bsc_new.svg",
17
+ defaultFundingTokenAddress: "0x55d398326f99059fF775485246999027B3197955"
18
+ };
19
+ var BSC_MAINNET_56 = {
20
+ chainId: "56",
21
+ name: "BSC",
22
+ chainName: "BNB Smart Chain",
23
+ nativeCurrencyName: "BNB",
24
+ nativeCurrencySymbol: "BNB",
25
+ nativeCurrencyDecimals: 18,
26
+ rpcUrls: ["https://bsc-dataseed.binance.org", "https://bsc-dataseed1.defibit.io"],
27
+ blockExplorerUrl: "https://bscscan.com",
28
+ platformType: "EVM",
29
+ icon: "https://static.tomo.inc/token/bsc_new.svg",
30
+ defaultFundingTokenAddress: "0x55d398326f99059fF775485246999027B3197955"
31
+ };
32
+ var CHAIN_REGISTRY = {
33
+ [TENDERLY_BSC_3131.chainId]: TENDERLY_BSC_3131,
34
+ [BSC_MAINNET_56.chainId]: BSC_MAINNET_56
35
+ };
36
+ var DEFAULT_FUNDING_CHAIN_ID = getEnv("FUNDING_CHAIN_ID") || "3131";
37
+ function normalizeFundingChainId(chainId) {
38
+ if (chainId === void 0 || chainId === null) return DEFAULT_FUNDING_CHAIN_ID;
39
+ const normalized = String(chainId).trim();
40
+ return normalized === "" ? DEFAULT_FUNDING_CHAIN_ID : normalized;
41
+ }
42
+ function getChainInfo(chainId) {
43
+ const id = normalizeFundingChainId(chainId);
44
+ const info = CHAIN_REGISTRY[id];
45
+ if (!info) {
46
+ throw new Error(
47
+ `Unsupported funding chainId "${id}". Supported: ${Object.keys(CHAIN_REGISTRY).sort().join(", ")}`
48
+ );
49
+ }
50
+ return info;
51
+ }
52
+ function pickEnvFundingTokenAddress() {
53
+ const candidates = [["NEXT_PUBLIC_FUNDING_TOKEN_ADDRESS", "FUNDING_TOKEN_ADDRESS"]];
54
+ const processEnv = globalThis.process?.env;
55
+ if (processEnv) {
56
+ for (const [pub, priv] of candidates) {
57
+ const publicValue = processEnv[pub];
58
+ const privateValue = processEnv[priv];
59
+ if (publicValue != null && publicValue !== "") return publicValue;
60
+ if (privateValue != null && privateValue !== "") return privateValue;
61
+ }
62
+ }
63
+ try {
64
+ const metaEnv = import.meta.env;
65
+ if (metaEnv) {
66
+ for (const [pub, priv] of candidates) {
67
+ const publicValue = metaEnv[pub];
68
+ const privateValue = metaEnv[priv];
69
+ if (publicValue != null && publicValue !== "") return publicValue;
70
+ if (privateValue != null && privateValue !== "") return privateValue;
71
+ }
72
+ }
73
+ } catch {
74
+ }
75
+ return void 0;
76
+ }
77
+ function getFundingTokenAddress(chainId) {
78
+ const fromEnv = pickEnvFundingTokenAddress();
79
+ if (fromEnv && /^0x[0-9a-fA-F]{40}$/.test(fromEnv)) return fromEnv;
80
+ return getChainInfo(chainId).defaultFundingTokenAddress;
81
+ }
82
+ var DEFAULT_FUNDING_TOKEN_ADDRESS = getFundingTokenAddress(DEFAULT_FUNDING_CHAIN_ID);
83
+ var ClientIds = {
84
+ google: getEnv("GOOGLE_CLIENT_ID"),
85
+ x: getEnv("X_CLIENT_ID")
86
+ };
87
+
88
+ export { ClientIds, DEFAULT_FUNDING_CHAIN_ID, DEFAULT_FUNDING_TOKEN_ADDRESS, getChainInfo, getFundingTokenAddress };