@shogun-sdk/money-legos
Version:
Shogun Money Legos: clients and types for quotes, memes, prices, balances, fees, validations, etc.
483 lines (443 loc) • 13.2 kB
text/typescript
import { NATIVE_TOKEN, SOL_NATIVE } from './addresses.js';
export const ETHEREUM_NETWORK = 'ethereum';
export const BASE_NETWORK = 'base';
export const ARBITRUM_NETWORK = 'arbitrum';
export const SOLANA_NETWORK = 'solana';
export const BSC_NETWORK = 'bsc';
export const BERACHAIN_NETWORK = 'berachain';
export const SONIC_NETWORK = 'sonic';
export const AVALANCHE_NETWORK = 'avalanche';
export const POLYGON_NETWORK = 'polygon';
export const HYPEREVM_NETWORK = 'hyperevm';
export const ETHEREUM_CHAIN_ID = 1;
export const ARBITRUM_CHAIN_ID = 42161;
export const BASE_CHAIN_ID = 8453;
export const BSC_CHAIN_ID = 56;
export const BERA_CHAIN_ID = 80094;
export const SOLANA_CHAIN_ID = 7565164;
export const SONIC_CHAIN_ID = 146;
export const AVALANCHE_CHAIN_ID = 43114;
export const POLYGON_CHAIN_ID = 137;
export const HYPEREVM_CHAIN_ID = 999;
export const SupportedChainIds = [
ETHEREUM_CHAIN_ID,
BASE_CHAIN_ID,
ARBITRUM_CHAIN_ID,
BSC_CHAIN_ID,
BERA_CHAIN_ID,
SOLANA_CHAIN_ID,
SONIC_CHAIN_ID,
AVALANCHE_CHAIN_ID,
POLYGON_CHAIN_ID,
HYPEREVM_CHAIN_ID
] as const;
export const getSupportedChains = () => {
return SupportedChainIds;
};
export type SupportedChainId = (typeof SupportedChainIds)[number];
export const SOLANA_BRIDGE_FEE_TOKEN = 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'; // USDC
export interface ChainConfig {
id: number;
name: string;
icon: string;
isEVM: boolean;
nativeCurrency?: {
name: string;
symbol: string;
decimals: number;
};
wrapped?: string;
symbol: string;
decimals: number;
tokenAddress: string;
}
export const NetworkById: Record<number, SupportedNetwork> = {
1: ETHEREUM_NETWORK,
8453: BASE_NETWORK,
42161: ARBITRUM_NETWORK,
56: BSC_NETWORK,
80094: BERACHAIN_NETWORK,
7565164: SOLANA_NETWORK,
146: SONIC_NETWORK,
43114: AVALANCHE_NETWORK,
137: POLYGON_NETWORK,
999: HYPEREVM_NETWORK
};
export const SupportedNetworks = [
ETHEREUM_NETWORK,
BASE_NETWORK,
ARBITRUM_NETWORK,
SOLANA_NETWORK,
BSC_NETWORK,
BERACHAIN_NETWORK,
SONIC_NETWORK,
AVALANCHE_NETWORK,
POLYGON_NETWORK,
HYPEREVM_NETWORK,
] as const;
export const NetworkIds = Object.keys(NetworkById).map(Number);
export type NetworkId = (typeof NetworkIds)[number];
export enum Networks {
ETHEREUM = 1,
ARBITRUM = 42161,
BASE = 8453,
BSC = 56,
SOLANA = 7565164,
BERACHAIN = 80094,
SONIC = 146,
AVALANCHE = 43114,
POLYGON = 137,
HYPEREVM = 999
}
export type SupportedNetwork = (typeof SupportedNetworks)[number];
export enum CodexNetworks {
ETHEREUM = 1,
ARBITRUM = 42161,
BASE = 8453,
BSC = 56,
SOLANA = 1399811149,
BERACHAIN = 80094,
SONIC = 146,
AVALANCHE = 43114,
POLYGON = 137,
HYPEREVM = 999
}
export const getNetworkId = (network: SupportedNetwork) => {
const chainMap = {
[ETHEREUM_NETWORK]: CodexNetworks.ETHEREUM.valueOf(),
[ARBITRUM_NETWORK]: CodexNetworks.ARBITRUM.valueOf(),
[BASE_NETWORK]: CodexNetworks.BASE.valueOf(),
[BSC_NETWORK]: CodexNetworks.BSC.valueOf(),
[SOLANA_NETWORK]: CodexNetworks.SOLANA.valueOf(),
[BERACHAIN_NETWORK]: CodexNetworks.BERACHAIN.valueOf(),
[SONIC_NETWORK]: CodexNetworks.SONIC.valueOf(),
[AVALANCHE_NETWORK]: CodexNetworks.AVALANCHE.valueOf(),
[POLYGON_NETWORK]: CodexNetworks.POLYGON.valueOf(),
[HYPEREVM_NETWORK]: CodexNetworks.HYPEREVM.valueOf(),
};
return chainMap[network]
? [chainMap[network]]
: [
CodexNetworks.ETHEREUM.valueOf(),
CodexNetworks.ARBITRUM.valueOf(),
CodexNetworks.BASE.valueOf(),
CodexNetworks.BSC.valueOf(),
CodexNetworks.SOLANA.valueOf(),
CodexNetworks.BERACHAIN.valueOf(),
CodexNetworks.SONIC.valueOf(),
CodexNetworks.AVALANCHE.valueOf(),
CodexNetworks.POLYGON.valueOf(),
CodexNetworks.HYPEREVM.valueOf(),
];
};
export const NATIVE_CURRENCY_EMV = { name: 'Ether', symbol: 'ETH', decimals: 18 };
// Function to get RPC URLs from environment variables with fallbacks
const mapRpcUrls = (chainId: number): string[] => {
// Try to get RPC URLs from environment variables
const envVarName = `RPC_URL_${chainId}`;
const nextPublicEnvVarName = `NEXT_PUBLIC_RPC_URL_${chainId}`;
// Check for Node.js environment variables
let envRpcUrl: string | undefined;
// Safely check for process.env
if (typeof process !== 'undefined' && process.env) {
// Check for regular environment variable
envRpcUrl = process.env[envVarName];
// If not found, check for NEXT_PUBLIC_ prefixed variable
if (!envRpcUrl) {
envRpcUrl = process.env[nextPublicEnvVarName];
}
}
let rpcUrls: string[] = [];
// If environment variable exists, use it
if (envRpcUrl) {
rpcUrls = [envRpcUrl];
}
// Fallback to public RPCs based on chain ID
switch (chainId) {
case 1: // Ethereum
return [...rpcUrls, 'https://eth.llamarpc.com'];
case 8453: // Base
return [...rpcUrls];
case 42161: // Arbitrum
return [...rpcUrls, 'https://arbitrum.meowrpc.com'];
case 80094: // Berachain
return [...rpcUrls, 'https://rpc.berachain.com'];
case 56: // BSC
return [
...rpcUrls,
'https://bsc-dataseed.defibit.io',
'https://bsc-dataseed.nariox.org',
'https://bsc.nodereal.io',
];
case SOLANA_CHAIN_ID: // Solana
return [
...rpcUrls,
'https://allys-hpupdc-fast-mainnet.helius-rpc.com',
'https://api.mainnet-beta.solana.com',
'https://solana-mainnet.rpc.extrnode.com',
'https://solana.public-rpc.com',
];
case SONIC_CHAIN_ID: // Sonic
return [
...rpcUrls,
'https://sonic-mainnet.g.alchemy.com/v2/q_3VoGSx6z9OWEbaQKmWAqreJn4Ngk6M',
];
case AVALANCHE_CHAIN_ID: // Avalanche
return [...rpcUrls];
case POLYGON_CHAIN_ID: // POLYGON
return [...rpcUrls, 'https://polygon-rpc.com'];
case HYPEREVM_CHAIN_ID: // HyperEVM
return [...rpcUrls, 'https://rpc.hyperliquid.xyz/evm'];
default:
return [];
}
};
// Custom RPC URLs set through initialization
let customRpcUrls: Record<number, string[]> = {};
// Initialize function to set custom RPC URLs
export const init = (config: { rpcUrls?: Record<number, string[]> } = {}) => {
if (config.rpcUrls) {
customRpcUrls = config.rpcUrls;
}
};
// Function to get RPC URLs with custom URLs taking precedence
const getRpcUrlsWithCustom = (chainId: number): string[] => {
let rpcUrls: string[] = [];
// If custom RPC URLs are set for this chain, use them
if (customRpcUrls[chainId] && customRpcUrls[chainId].length > 0) {
rpcUrls = customRpcUrls[chainId];
}
// Otherwise, fall back to environment variables and public RPCs
return Array.from(new Set([...rpcUrls, ...mapRpcUrls(chainId)]));
};
export const getRpcUrls = (): Record<number, { rpc: string[] }> => ({
[ETHEREUM_CHAIN_ID]: {
rpc: getRpcUrlsWithCustom(ETHEREUM_CHAIN_ID),
},
[BASE_CHAIN_ID]: {
rpc: getRpcUrlsWithCustom(BASE_CHAIN_ID),
},
[ARBITRUM_CHAIN_ID]: {
rpc: getRpcUrlsWithCustom(ARBITRUM_CHAIN_ID),
},
[BERA_CHAIN_ID]: {
rpc: getRpcUrlsWithCustom(BERA_CHAIN_ID),
},
[BSC_CHAIN_ID]: {
rpc: getRpcUrlsWithCustom(BSC_CHAIN_ID),
},
[SOLANA_CHAIN_ID]: {
rpc: getRpcUrlsWithCustom(SOLANA_CHAIN_ID),
},
[SONIC_CHAIN_ID]: {
rpc: getRpcUrlsWithCustom(SONIC_CHAIN_ID),
},
[AVALANCHE_CHAIN_ID]: {
rpc: getRpcUrlsWithCustom(AVALANCHE_CHAIN_ID),
},
[POLYGON_CHAIN_ID]: {
rpc: getRpcUrlsWithCustom(POLYGON_CHAIN_ID),
},
[HYPEREVM_CHAIN_ID]: {
rpc: getRpcUrlsWithCustom(HYPEREVM_CHAIN_ID),
},
});
// End of Selection
export const CHAIN_CONFIGS: ChainConfig[] = [
{
id: 1,
name: 'Ethereum',
icon: `/svgs/eth.svg`,
isEVM: true,
nativeCurrency: NATIVE_CURRENCY_EMV,
wrapped: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
symbol: 'ETH',
decimals: 18,
tokenAddress: NATIVE_TOKEN.ETH,
},
{
id: 8453,
name: 'Base',
icon: `/svgs/eth.svg`,
isEVM: true,
nativeCurrency: NATIVE_CURRENCY_EMV,
wrapped: '0x4200000000000000000000000000000000000006',
symbol: 'ETH',
decimals: 18,
tokenAddress: NATIVE_TOKEN.ETH,
},
{
id: 42161,
name: 'Arbitrum',
icon: `/svgs/eth.svg`,
isEVM: true,
nativeCurrency: NATIVE_CURRENCY_EMV,
wrapped: '0x82aF49447D8a07e3bd95BD0d56f35241523fBab1',
symbol: 'ETH',
decimals: 18,
tokenAddress: NATIVE_TOKEN.ETH,
},
{
id: 80094,
name: 'Berachain',
icon: `/svgs/bera.png`,
isEVM: true,
nativeCurrency: {
decimals: 18,
name: 'BERA Token',
symbol: 'BERA',
},
wrapped: '0x6969696969696969696969696969696969696969', // Using for price calculation for native asset
symbol: 'BERA',
decimals: 18,
tokenAddress: NATIVE_TOKEN.ETH,
},
{
id: 56,
name: 'BSC',
icon: `/svgs/56.svg`,
isEVM: true,
nativeCurrency: {
decimals: 18,
name: 'BNB',
symbol: 'BNB',
},
wrapped: '0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c', // Using for price calculation for native asset
symbol: 'BNB',
decimals: 18,
tokenAddress: NATIVE_TOKEN.ETH,
},
{
id: SOLANA_CHAIN_ID,
name: 'Solana',
icon: '/svgs/sol.svg',
nativeCurrency: {
name: 'SOLANA',
symbol: 'SOL',
decimals: 9,
},
isEVM: false,
wrapped: 'So11111111111111111111111111111111111111112',
tokenAddress: SOL_NATIVE,
symbol: 'SOL',
decimals: 9,
},
{
id: 146,
name: 'Sonic',
icon: `/svgs/146.svg`,
isEVM: true,
nativeCurrency: {
decimals: 18,
name: 'Sonic',
symbol: 'S',
},
wrapped: '0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38',
tokenAddress: NATIVE_TOKEN.ETH,
symbol: 'SONIC',
decimals: 18,
},
{
id: AVALANCHE_CHAIN_ID,
name: 'Avalanche',
icon: `/svgs/${AVALANCHE_CHAIN_ID}.svg`,
isEVM: true,
nativeCurrency: {
decimals: 18,
name: 'Avalanche',
symbol: 'AVAX',
},
wrapped: '0xb31f66aa3c1e785363f0875a1b74e27b85fd66c7',
symbol: 'AVAX',
decimals: 18,
tokenAddress: NATIVE_TOKEN.ETH,
},
{
id: POLYGON_CHAIN_ID,
name: 'POL',
icon: `/svgs/${POLYGON_CHAIN_ID}.svg`,
isEVM: true,
nativeCurrency: {
decimals: 18,
name: 'POL',
symbol: 'POL',
},
wrapped: '0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270',
symbol: 'POL',
decimals: 18,
tokenAddress: NATIVE_TOKEN.ETH,
},
{
id: HYPEREVM_CHAIN_ID,
name: 'HyperEVM',
icon: `/svgs/${HYPEREVM_CHAIN_ID}.svg`,
isEVM: true,
nativeCurrency: {
decimals: 18,
name: 'HYPE',
symbol: 'HYPE',
},
wrapped: '0x5555555555555555555555555555555555555555',
symbol: 'HYPE',
decimals: 18,
tokenAddress: NATIVE_TOKEN.ETH,
},
];
export const SUPPORTED_CHAIN_IDS = CHAIN_CONFIGS.map((chain) => chain.id);
export const EVM_CHAIN_IDS = CHAIN_CONFIGS.filter((chain) => chain.isEVM).map((chain) => chain.id);
export const NON_EVM_CHAIN_IDS = CHAIN_CONFIGS.filter((chain) => !chain.isEVM).map((chain) => chain.id);
export const CHAIN_MAP: Record<number, ChainConfig> = CHAIN_CONFIGS.reduce(
(acc, chain) => {
acc[chain.id] = chain;
return acc;
},
{} as Record<number, ChainConfig>,
);
export const CHAIN_MAP_BY_NETWORK: Record<SupportedNetwork, ChainConfig> = CHAIN_CONFIGS.reduce(
(acc, chain) => {
acc[NetworkById[chain.id] as SupportedNetwork] = chain;
return acc;
},
{} as Record<SupportedNetwork, ChainConfig>,
);
export const isEVMNetwork = (network: string): boolean => {
return (
network === ARBITRUM_NETWORK ||
network === BASE_NETWORK ||
network === ETHEREUM_NETWORK ||
network === BSC_NETWORK ||
network === BERACHAIN_NETWORK ||
network === SONIC_NETWORK ||
network === AVALANCHE_NETWORK ||
network === HYPEREVM_NETWORK
);
};
export const isEVMChain = (chainId: number): boolean => {
return EVM_CHAIN_IDS.includes(chainId);
};
export const isEVMChainExcludingBera = (chainId: number): boolean => {
return EVM_CHAIN_IDS.some((id) => id !== 80094 && id === chainId);
};
export const isBeraChain = (chainId: number) => {
return chainId === 80094;
};
export const isSolanaChain = (chainId: number): boolean => {
return SOLANA_CHAIN_ID === chainId;
};
export const getChainConfig = (chainId: number): ChainConfig | undefined => {
return CHAIN_MAP[chainId];
};
export const WRAPPED_NATIVE_ADDRESSES = Object.values(CHAIN_MAP).map((chain) => {
return chain.wrapped?.toLowerCase() || '';
});
export const isWrappedNativeAddress = (tokenAddress: string): boolean => {
return !!tokenAddress && WRAPPED_NATIVE_ADDRESSES.includes(tokenAddress.toLowerCase());
};
export const getWrappedNativeTokenByChainId = (chainId: SupportedChainId) => {
return CHAIN_MAP[chainId]?.wrapped;
};
const NATIVE_ADDRESSES = Object.values(CHAIN_MAP).map((chain) => chain.tokenAddress.toLowerCase());
export const isNativeAddress = (tokenAddress: string): boolean => {
const normalizedTokenAddress = tokenAddress.toLowerCase();
return !!tokenAddress && NATIVE_ADDRESSES.includes(normalizedTokenAddress);
};