UNPKG

@b3dotfun/anyspend-sdk

Version:

React Hooks and UI Components for AnySpend by B3

343 lines (315 loc) 11.2 kB
import { ChainType, IBaseChain, IEVMChain, ISolanaChain, Token } from "@b3dotfun/anyspend-sdk/types"; import invariant from "invariant"; import { Account, Chain, createPublicClient, createWalletClient, defineChain, http, parseEther, PublicClient, Transport, WalletClient } from "viem"; import { arbitrum, avalanche, b3, b3Sepolia, base, baseSepolia, bsc, mainnet, optimism, polygon, sepolia } from "viem/chains"; import { RELAY_SOLANA_MAINNET_CHAIN_ID } from "../constants"; import { getAvaxToken, getBnbToken, getEthToken, getPolToken, getSolanaToken } from "./token"; function getCustomEvmChain(chain: Chain, rpcUrl: string): Chain { return defineChain({ ...chain, rpcUrls: { default: { http: [rpcUrl] } } }); } // export const b4testnet = defineChain({ // id: 19934, // name: "B4 Testnet", // network: "b4-testnet", // nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 }, // rpcUrls: { default: { http: ["https://19934.rpc.thirdweb.com/c2dce731fe7fa39edc1d0ea5a6a5e11e"] } }, // }); export const EVM_MAINNET: Record<number, IEVMChain> = { [mainnet.id]: { id: mainnet.id, name: mainnet.name, type: ChainType.EVM, logoUrl: "https://assets.relay.link/icons/square/1/light.png", nativeRequired: parseEther("0.001"), canDepositNative: true, defaultToken: getEthToken(mainnet.id), nativeToken: getEthToken(mainnet.id), viem: getCustomEvmChain( mainnet, "https://quick-chaotic-film.quiknode.pro/39a7aae6a7078f9f36c435e6f34c071c641cf863/" ), pollingInterval: 4000, // 4 seconds for Ethereum mainnet zapperEnum: "ETHEREUM_MAINNET", coingeckoName: "eth" }, [arbitrum.id]: { id: arbitrum.id, name: "Arbitrum", type: ChainType.EVM, logoUrl: "https://assets.relay.link/icons/square/42161/light.png", nativeRequired: parseEther("0.0001"), canDepositNative: true, defaultToken: getEthToken(arbitrum.id), nativeToken: getEthToken(arbitrum.id), viem: getCustomEvmChain( arbitrum, "https://proportionate-twilight-patina.arbitrum-mainnet.quiknode.pro/60e4825626515233a0f566f5915601af6043127b/" ), pollingInterval: 500, // 500ms for Arbitrum's fast blocks zapperEnum: "ARBITRUM_MAINNET", coingeckoName: "arbitrum" }, [base.id]: { id: base.id, name: base.name, logoUrl: "https://assets.relay.link/icons/square/8453/light.png", type: ChainType.EVM, nativeRequired: parseEther("0.0001"), canDepositNative: true, defaultToken: getEthToken(base.id), nativeToken: getEthToken(base.id), viem: getCustomEvmChain( base, "https://sly-indulgent-bird.base-mainnet.quiknode.pro/4e31fab6845eb29a2764723a43896999fe962e48/" ), pollingInterval: 1000, // 1 second for Base zapperEnum: "BASE_MAINNET", coingeckoName: "base" }, [optimism.id]: { id: optimism.id, name: optimism.name, logoUrl: "https://assets.relay.link/icons/square/10/light.png", type: ChainType.EVM, nativeRequired: parseEther("0.0001"), canDepositNative: true, defaultToken: getEthToken(optimism.id), nativeToken: getEthToken(optimism.id), viem: getCustomEvmChain( optimism, "https://black-cosmopolitan-hexagon.optimism.quiknode.pro/18382925841f9d09f9e76eef954bf189aa234523/" ), pollingInterval: 1000, // 1 second for Optimism zapperEnum: "OPTIMISM_MAINNET", coingeckoName: "optimism" }, [polygon.id]: { id: polygon.id, name: polygon.name, logoUrl: "https://assets.relay.link/icons/square/137/light.png", type: ChainType.EVM, nativeRequired: parseEther("0.1"), canDepositNative: true, defaultToken: getPolToken(), nativeToken: getPolToken(), viem: getCustomEvmChain( polygon, "https://purple-young-field.matic.quiknode.pro/ca54f365c1a4c7f970223eb8087e0fc579feba12/" ), pollingInterval: 1000, // 1 second for Polygon zapperEnum: "POLYGON_MAINNET", coingeckoName: "polygon" }, [avalanche.id]: { id: avalanche.id, name: avalanche.name, logoUrl: "https://assets.relay.link/icons/square/43114/light.png", type: ChainType.EVM, nativeRequired: parseEther("0.005"), canDepositNative: true, defaultToken: getAvaxToken(), nativeToken: getAvaxToken(), viem: getCustomEvmChain( avalanche, "https://burned-billowing-pond.avalanche-mainnet.quiknode.pro/24289978a524a18ef42e568e04fe8cad8c7b6720/ext/bc/C/rpc/" ), pollingInterval: 1000, // 1 second for Avalanche zapperEnum: "AVALANCHE_MAINNET", coingeckoName: "avalanche" }, [bsc.id]: { id: bsc.id, name: bsc.name, logoUrl: "https://avatars.githubusercontent.com/u/45615063?s=280&v=4", type: ChainType.EVM, nativeRequired: parseEther("0.00001"), canDepositNative: false, defaultToken: getBnbToken(), nativeToken: getBnbToken(), viem: getCustomEvmChain(bsc, "https://bsc-rpc.publicnode.com"), pollingInterval: 1000, // 1 second for BSC zapperEnum: "BSC_MAINNET", coingeckoName: "bsc" }, [b3.id]: { id: b3.id, name: b3.name, logoUrl: "https://assets.relay.link/icons/square/8333/light.png", type: ChainType.EVM, nativeRequired: parseEther("0.0001"), canDepositNative: true, defaultToken: getEthToken(b3.id), nativeToken: getEthToken(b3.id), viem: getCustomEvmChain( b3, "https://late-dimensional-yard.b3-mainnet.quiknode.pro/461dbdbd44158cd7a7a764a58ffb01a67eef77f2/" ), pollingInterval: 1000, // 1 second for B3 zapperEnum: "B3_MAINNET", coingeckoName: "b3" } }; export const EVM_TESTNET: Record<number, IEVMChain> = { [sepolia.id]: { id: sepolia.id, name: sepolia.name, logoUrl: "https://assets.relay.link/icons/square/1/light.png", type: ChainType.EVM, nativeRequired: parseEther("0.00001"), canDepositNative: true, defaultToken: getEthToken(sepolia.id), nativeToken: getEthToken(sepolia.id), viem: sepolia, pollingInterval: 1000 // 1 second for Sepolia }, [baseSepolia.id]: { id: baseSepolia.id, name: baseSepolia.name, logoUrl: "https://assets.relay.link/icons/square/8453/light.png", type: ChainType.EVM, nativeRequired: parseEther("0.00001"), canDepositNative: true, defaultToken: getEthToken(baseSepolia.id), nativeToken: getEthToken(baseSepolia.id), viem: baseSepolia, pollingInterval: 1000 // 1 second for Base Sepolia }, [b3Sepolia.id]: { id: b3Sepolia.id, name: b3Sepolia.name, logoUrl: "https://assets.relay.link/icons/square/8333/light.png", type: ChainType.EVM, nativeRequired: parseEther("0.00001"), canDepositNative: true, defaultToken: getEthToken(b3Sepolia.id), nativeToken: getEthToken(b3Sepolia.id), viem: b3Sepolia, pollingInterval: 1000 // 1 second for B3 Sepolia } // [b4testnet.id]: { // id: b4testnet.id, // logoUrl: "https://cdn.b3.fun/b4-logo.png", // type: ChainType.EVM, // viem: b4testnet, // requireNativeBalance: parseEther("0.00001"), // supportDepositNative: true, // }, }; export const SOLANA_MAINNET: ISolanaChain = { id: RELAY_SOLANA_MAINNET_CHAIN_ID, name: "Solana", logoUrl: "https://assets.relay.link/icons/square/792703809/light.png", type: ChainType.SOLANA, nativeRequired: BigInt(10000000), // 0.01 SOL canDepositNative: true, defaultToken: getSolanaToken(), nativeToken: getSolanaToken() }; export const EVM_CHAINS: Record<number, IEVMChain> = { ...EVM_MAINNET, ...EVM_TESTNET }; export const SOLANA_CHAINS: Record<number, ISolanaChain> = { [RELAY_SOLANA_MAINNET_CHAIN_ID]: SOLANA_MAINNET }; export const ALL_CHAINS: Record<number, IBaseChain> = { ...EVM_CHAINS, ...SOLANA_CHAINS }; export function getSolanaChains(network: "mainnet" | "testnet"): ISolanaChain { invariant(network === "mainnet", "Solana chain is only supported on mainnet"); return SOLANA_MAINNET; } export function getAllEvmChains(network: "mainnet" | "testnet"): Record<number, IEVMChain> { return network === "mainnet" ? EVM_MAINNET : EVM_TESTNET; } export function getChainType(chainId: number): ChainType { invariant(ALL_CHAINS[chainId], `Chain ${chainId} is not supported`); return ALL_CHAINS[chainId].type; } export function chainIdToPublicClient(chainId: number): PublicClient { invariant(EVM_CHAINS[chainId], `Chain ${chainId} is not an EVM chain`); return createPublicClient({ chain: EVM_CHAINS[chainId].viem, transport: http(), pollingInterval: EVM_CHAINS[chainId].pollingInterval }); } export function chainIdToWalletClient(chainId: number, account?: Account): WalletClient<Transport, Chain> { invariant(EVM_CHAINS[chainId], `Chain ${chainId} is not an EVM chain`); return createWalletClient({ chain: EVM_CHAINS[chainId].viem, transport: http(), account, pollingInterval: EVM_CHAINS[chainId].pollingInterval }); } export function getNativeRequired(chainId: number): bigint { invariant(ALL_CHAINS[chainId], `Chain ${chainId} is not supported`); return ALL_CHAINS[chainId].nativeRequired; } export function canDepositNative(chainId: number): boolean { invariant(ALL_CHAINS[chainId], `Chain ${chainId} is not supported`); return ALL_CHAINS[chainId].canDepositNative; } export function isMainnet(chainId: number): boolean { return EVM_MAINNET[chainId] !== undefined || RELAY_SOLANA_MAINNET_CHAIN_ID === chainId; } export function isTestnet(chainId: number): boolean { return EVM_TESTNET[chainId] !== undefined; } export function getDefaultToken(chainId: number): Token { invariant(ALL_CHAINS[chainId], `Chain ${chainId} is not supported`); return ALL_CHAINS[chainId].defaultToken; } export function getChainName(chainId: number): string { invariant(ALL_CHAINS[chainId], `Chain ${chainId} is not supported`); return EVM_CHAINS[chainId] ? EVM_CHAINS[chainId].viem.name : "Solana"; } export function getPaymentUrl(address: string, amount: bigint, currency: string) { if (currency === "ETH") { return `ethereum:${address}?value=${amount.toString()}`; } return `ethereum:${address}`; } export function getExplorerTxUrl(chainId: number, txHash: string) { if (EVM_CHAINS[chainId]) { return EVM_CHAINS[chainId].viem.blockExplorers?.default.url + "/tx/" + txHash; } return "https://solscan.io/tx/" + txHash; } export function getExplorerAddressUrl(chainId: number, address: string) { if (EVM_CHAINS[chainId]) { return EVM_CHAINS[chainId].viem.blockExplorers?.default.url + "/address/" + address; } return "https://solscan.io/account/" + address; } export function getMulticall3Address(chainId: number): string { const chainType = getChainType(chainId); invariant(chainType === ChainType.EVM, "chainType must be EVM"); const multicall3 = EVM_CHAINS[chainId].viem.contracts?.multicall3; invariant(multicall3, `multicall3 of chain ${chainId} undefined`); return multicall3.address; } export function getNativeToken(chainId: number): Token { invariant(ALL_CHAINS[chainId], `Chain ${chainId} undefined`); return ALL_CHAINS[chainId].nativeToken; } export function isEvmChain(chainId: number): boolean { return Boolean(EVM_CHAINS[chainId]); }