UNPKG

@saberhq/token-utils

Version:

Token-related math and transaction utilities for Solana.

200 lines 5.69 kB
import { PublicKey } from "@saberhq/solana-contrib"; import { NATIVE_MINT } from "@solana/spl-token"; import { deserializeMint } from "./layout.js"; /** * Magic value representing the raw, underlying Solana native asset. */ export const RAW_SOL_MINT = new PublicKey("RawSo11111111111111111111111111111111111112"); /** * Token information. */ export class Token { info; /** * The network that the Token is on. */ network; _mintAccount = null; constructor(info) { this.info = info; this.network = chainIdToNetwork(info.chainId) ?? "localnet"; } /** * The mint PublicKey of the token. * * Avoid using this value to print it to a string, as base58 * strings are relatively slow to create since they require the use * of hash functions. */ get mintAccount() { if (this._mintAccount) { return this._mintAccount; } this._mintAccount = new PublicKey(this.info.address); return this._mintAccount; } /** * If true, this token represents unwrapped, native, "raw" SOL. */ get isRawSOL() { return this.mintAccount.equals(RAW_SOL_MINT); } /** * The Base58 string representation of the mint address. */ get address() { return this.info.address; } /** * The chain ID of the token. */ get chainId() { return this.info.chainId; } /** * Number of decimals of the token. */ get decimals() { return this.info.decimals; } /** * The name of the token. */ get name() { return this.info.name; } /** * The symbol of the token. */ get symbol() { return this.info.symbol; } /** * The token's icon to render. */ get icon() { return this.info.logoURI; } equals(other) { return tokensEqual(this, other); } toString() { return `Token[mint=${this.address}, decimals=${this.decimals}, network=${this.network}]`; } toJSON() { return this.info; } /** * Returns true if the given tag is present. * @param tag The tag to check. * @returns */ hasTag(tag) { return !!this.info.tags?.includes(tag); } /** * Loads a token from a Mint. * @param mint * @param opts * @returns */ static fromMint = (mint, decimals, opts = {}) => new Token({ ...opts, // required address: mint.toString(), decimals, // optional name: opts.name ?? `Token ${mint.toString().slice(0, 4)}`, symbol: opts.symbol ?? mint.toString().slice(0, 5), chainId: opts.chainId ?? ChainId.Localnet, }); /** * Loads a token from a Connection. * * @param connection * @param mint * @param info */ static load = async (connection, mint, info = {}) => { if (typeof info.decimals === "number") { return Token.fromMint(mint, info.decimals, info); } const mintAccountInfo = await connection.getAccountInfo(mint); if (!mintAccountInfo) { return null; } const mintInfo = deserializeMint(mintAccountInfo.data); return Token.fromMint(mint, mintInfo.decimals, info); }; } /** * Checks if two tokens are equal. * @param a * @param b * @returns */ export const tokensEqual = (a, b) => a !== undefined && b !== undefined && a.address === b.address && a.network === b.network; const rawSol = { address: RAW_SOL_MINT.toString(), name: "Solana", symbol: "SOL", decimals: 9, logoURI: "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/So11111111111111111111111111111111111111112/logo.png", }; const wrappedSol = { address: NATIVE_MINT.toString(), name: "Wrapped SOL", symbol: "SOL", decimals: 9, logoURI: "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/So11111111111111111111111111111111111111112/logo.png", }; /** * Creates a Token for all networks. */ export const makeTokenForAllNetworks = (token) => ({ "mainnet-beta": new Token({ ...token, chainId: ChainId.MainnetBeta }), devnet: new Token({ ...token, chainId: ChainId.Devnet }), testnet: new Token({ ...token, chainId: ChainId.Testnet }), localnet: new Token({ ...token, chainId: ChainId.Localnet }), }); // comes from @solana/spl-token-registry, except we've added localnet export var ChainId; (function (ChainId) { ChainId[ChainId["MainnetBeta"] = 101] = "MainnetBeta"; ChainId[ChainId["Testnet"] = 102] = "Testnet"; ChainId[ChainId["Devnet"] = 103] = "Devnet"; ChainId[ChainId["Localnet"] = 104] = "Localnet"; })(ChainId || (ChainId = {})); export const NETWORK_TO_CHAIN_ID = { "mainnet-beta": ChainId.MainnetBeta, devnet: ChainId.Devnet, testnet: ChainId.Testnet, localnet: 104, }; export const CHAIN_ID_TO_NETWORK = Object.entries(NETWORK_TO_CHAIN_ID).reduce((acc, [network, env]) => ({ ...acc, [env]: network }), {}); /** * Gets the chain id associated with a network. * @param network * @returns */ export const networkToChainId = (network) => NETWORK_TO_CHAIN_ID[network]; /** * Gets the Network associated with a chain id. * @param network * @returns */ export const chainIdToNetwork = (env) => CHAIN_ID_TO_NETWORK[env]; /** * Raw Solana token. * * This is a magic value. This is not a real token. */ export const RAW_SOL = makeTokenForAllNetworks(rawSol); /** * Wrapped Solana token. */ export const WRAPPED_SOL = makeTokenForAllNetworks(wrappedSol); //# sourceMappingURL=token.js.map