Files
cryptowallet/apps/api/src/lib/token-registry.ts
ZOMBIIIIIII 53635806d6 swaggerready
2026-05-14 01:11:20 +03:00

162 lines
7.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Реестр известных токенов per-chain. Используется в getBalance для
* параллельного запроса баланса всех токенов адреса.
*
* Адреса контрактов / mint'ы — из публичных on-chain данных и используются
* также в swap-proxy роутах (BSC TOKEN_MAP, SOL ALLOWED_MINTS).
*/
import type { ChainCode } from './address-validators';
export interface EvmToken {
symbol: string;
contractAddress: string;
decimals: number;
coingeckoId?: string;
}
export interface TrxToken {
symbol: string;
contractAddress: string; // T...base58
decimals: number;
coingeckoId?: string;
}
export interface SolToken {
symbol: string;
mint: string; // SPL mint pubkey (base58)
decimals: number;
coingeckoId?: string;
}
/**
* CoinGecko coin IDs для native монет каждой chain.
* Используется в `price-oracle.service.ts` для USD-цен в `/balance`.
*/
export const NATIVE_COINGECKO_IDS: Record<ChainCode, string> = {
BTC: 'bitcoin',
ETH: 'ethereum',
BSC: 'binancecoin',
TRX: 'tron',
SOL: 'solana',
};
export const ETH_TOKENS: EvmToken[] = [
{ symbol: 'USDT', contractAddress: '0xdAC17F958D2ee523a2206206994597C13D831ec7', decimals: 6, coingeckoId: 'tether' },
{ symbol: 'USDC', contractAddress: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', decimals: 6, coingeckoId: 'usd-coin' },
{ symbol: 'DAI', contractAddress: '0x6B175474E89094C44Da98b954EedeAC495271d0F', decimals: 18, coingeckoId: 'dai' },
{ symbol: 'WBTC', contractAddress: '0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599', decimals: 8, coingeckoId: 'wrapped-bitcoin' },
{ symbol: 'LINK', contractAddress: '0x514910771AF9Ca656af840dff83E8264EcF986CA', decimals: 18, coingeckoId: 'chainlink' },
{ symbol: 'UNI', contractAddress: '0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984', decimals: 18, coingeckoId: 'uniswap' },
];
export const BSC_TOKENS: EvmToken[] = [
{ symbol: 'USDT', contractAddress: '0x55d398326f99059fF775485246999027B3197955', decimals: 18, coingeckoId: 'tether' },
{ symbol: 'USDC', contractAddress: '0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d', decimals: 18, coingeckoId: 'usd-coin' },
{ symbol: 'DOGE', contractAddress: '0xbA2aE424d960c26247Dd6c32edC70B295c744C43', decimals: 8, coingeckoId: 'dogecoin' },
{ symbol: 'WBNB', contractAddress: '0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c', decimals: 18, coingeckoId: 'wbnb' },
{ symbol: 'BUSD', contractAddress: '0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56', decimals: 18, coingeckoId: 'binance-usd' },
];
export const TRX_TOKENS: TrxToken[] = [
{ symbol: 'USDT', contractAddress: 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t', decimals: 6, coingeckoId: 'tether' },
{ symbol: 'USDC', contractAddress: 'TEkxiTehnzSmSe2XqrBj4w32RUN966rdz8', decimals: 6, coingeckoId: 'usd-coin' },
];
export const SOL_TOKENS: SolToken[] = [
{ symbol: 'USDT', mint: 'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB', decimals: 6, coingeckoId: 'tether' },
{ symbol: 'USDC', mint: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', decimals: 6, coingeckoId: 'usd-coin' },
{ symbol: 'PUMP', mint: 'pumpCmXqMfrsAkQ5r49WcJnRayYRqmXz6ae8H7H9Dfn', decimals: 6, coingeckoId: 'pump-fun' },
{ symbol: 'JUP', mint: 'JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN', decimals: 6, coingeckoId: 'jupiter-exchange-solana' },
{ symbol: 'WIF', mint: 'EKpQGSJtjMFqKZ9KQanSqYXRcF8fBopzLHYxdM65zcjm', decimals: 6, coingeckoId: 'dogwifcoin' },
{ symbol: 'POPCAT', mint: '7GCihgDB8fe6KNjn2MYtkzZcRjQy3t9GHdC8uHYmW2hr', decimals: 9, coingeckoId: 'popcat' },
{ symbol: 'TRUMP', mint: '6p6xgHyF7AeE6TZkSmFsko444wqoP15icUSqi2jfGiPN', decimals: 6, coingeckoId: 'official-trump' },
{ symbol: 'PYTH', mint: 'HZ1JovNiVvGrGNiiYvEozEVgZ58xaU3RKwX8eACQBCt3', decimals: 6, coingeckoId: 'pyth-network' },
{ symbol: 'JTO', mint: 'jtojtomepa8beP8AuQc6eXt5FriJwfFMwQx2v2f9mCL', decimals: 9, coingeckoId: 'jito-governance-token' },
{ symbol: 'W', mint: '85VBFQZC9TZkfaptBWjvUw7YbZjy52A6mjtPGjstQAmQ', decimals: 6, coingeckoId: 'wormhole' },
{ symbol: 'BONK', mint: 'DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263', decimals: 5, coingeckoId: 'bonk' },
{ symbol: 'ORCA', mint: 'orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE', decimals: 6, coingeckoId: 'orca' },
{ symbol: 'PENGU', mint: '2zMMhcVQEXDtdE6vsFS7S7D5oUodfJHE8vd1gnBouauv', decimals: 6, coingeckoId: 'pudgy-penguins' },
{ symbol: 'RAY', mint: '4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R', decimals: 6, coingeckoId: 'raydium' },
];
export function getEvmTokens(chain: ChainCode): EvmToken[] {
if (chain === 'ETH') return ETH_TOKENS;
if (chain === 'BSC') return BSC_TOKENS;
return [];
}
export function getTrxTokens(): TrxToken[] {
return TRX_TOKENS;
}
export function getSolTokens(): SolToken[] {
return SOL_TOKENS;
}
/**
* Universal lookup для send flow. Returns address+decimals или null если token не в registry.
* Symbol comparison case-insensitive.
*
* Usage:
* const info = getTokenInfo('BSC', 'USDC');
* // → { address: '0x8AC76a51...', decimals: 18 }
*
* const info = getTokenInfo('SOL', 'USDT');
* // → { address: 'Es9vMFrza...', decimals: 6 } (mint address)
*/
export function getTokenInfo(chain: ChainCode, symbol: string): { address: string; decimals: number } | null {
const upper = String(symbol).toUpperCase();
if (chain === 'ETH' || chain === 'BSC') {
const t = getEvmTokens(chain).find((x) => x.symbol.toUpperCase() === upper);
return t ? { address: t.contractAddress, decimals: t.decimals } : null;
}
if (chain === 'TRX') {
const t = TRX_TOKENS.find((x) => x.symbol.toUpperCase() === upper);
return t ? { address: t.contractAddress, decimals: t.decimals } : null;
}
if (chain === 'SOL') {
const t = SOL_TOKENS.find((x) => x.symbol.toUpperCase() === upper);
return t ? { address: t.mint, decimals: t.decimals } : null;
}
return null;
}
/**
* Resolves the CoinGecko coin id for a given (chain, symbol) pair.
*
* Если `symbol` совпадает с самим именем chain (BTC/ETH/BSC/TRX/SOL) — возвращает
* native id (`NATIVE_COINGECKO_IDS[chain]`).
* В остальных случаях ищет токен в реестре сети и возвращает его `coingeckoId`.
*
* Возвращает `null` если:
* - chain неизвестен;
* - symbol не найден в реестре сети;
* - токен найден, но `coingeckoId` для него не задан.
*
* Используется исключительно как whitelist для price oracle (см. S1 в плане):
* никакой свободный user-input не попадает в CoinGecko URL.
*/
export function getCoingeckoId(chain: ChainCode, symbol: string): string | null {
if (!chain) return null;
const upper = String(symbol || '').toUpperCase();
if (!upper) return null;
// Native — symbol === chain code (BTC, ETH, ...).
if (upper === chain) return NATIVE_COINGECKO_IDS[chain] ?? null;
if (chain === 'ETH' || chain === 'BSC') {
const t = getEvmTokens(chain).find((x) => x.symbol.toUpperCase() === upper);
return t?.coingeckoId ?? null;
}
if (chain === 'TRX') {
const t = TRX_TOKENS.find((x) => x.symbol.toUpperCase() === upper);
return t?.coingeckoId ?? null;
}
if (chain === 'SOL') {
const t = SOL_TOKENS.find((x) => x.symbol.toUpperCase() === upper);
return t?.coingeckoId ?? null;
}
return null;
}