UNPKG

viem

Version:

TypeScript Interface for Ethereum

202 lines • 6.95 kB
import { TokenId } from 'ox/tempo'; import { readContract } from '../../actions/public/readContract.js'; import { isAddressEqual } from '../../utils/address/isAddressEqual.js'; import { encodeFunctionData } from '../../utils/index.js'; import * as Abis from '../Abis.js'; /** * Resolves the token contract `address` and `decimals` from a `token`, which is * a token symbol declared on the client's `tokens` array, a TIP20 token id, or * a contract `address`. * * When `token` is a declared symbol, the `address` and `decimals` are read from * the client's declared `tokens` (`decimals` can be overridden via the explicit * `decimals`). When `token` is a token id or address, its `decimals` is inferred * from the client's declared `tokens` when the address matches a declared token, * otherwise taken from the explicit `decimals`. * * When `client` is omitted, `token` must be a token id or address (symbols * cannot be resolved), and `decimals` is only taken from the explicit * `decimals`. * * @param client - Client (optional). * @param parameters - Parameters. * @returns The resolved `address` and `decimals`. */ export function resolveToken(client, parameters) { const { decimals, token } = parameters; if (client && typeof token === 'string') { const declared = findDeclaredTokenBySymbol(client, token); if (declared) return { address: declared.address, decimals: decimals ?? declared.decimals, }; } const address = TokenId.toAddress(token); return { address, decimals: decimals ?? (client ? inferDecimals(client, address) : undefined), }; } /** * Finds the declared {@link ResolvedToken} on the client's `tokens` array matching * `token`, which is either a token symbol, a TIP20 token id, or a contract * `address`, resolved for the client's `chain.id`. Returns `undefined` when no * declared token matches, or the matching token has no address for the client's * chain. * * @param client - Client. * @param token - Token symbol (declared on the client's `tokens` array), TIP20 token id, or contract address. * @returns The matching declared token config, or `undefined`. */ export function findDeclaredToken(client, token) { const tokens = client.tokens; const chainId = client.chain?.id; if (!tokens || chainId === undefined) return undefined; if (typeof token === 'string') { const declared = findDeclaredTokenBySymbol(client, token); if (declared) return declared; } const address = TokenId.toAddress(token); for (const token_ of tokens) { const resolved = resolveTokenForChain(token_, chainId); if (resolved && isAddressEqual(resolved.address, address)) return resolved; } return undefined; } /** * Finds a declared token by `symbol` (case-insensitively) on the client's * `tokens` array, resolved for the client's `chain.id`. @internal */ function findDeclaredTokenBySymbol(client, symbol) { const tokens = client.tokens; const chainId = client.chain?.id; if (!tokens || chainId === undefined) return undefined; const lowerSymbol = symbol.toLowerCase(); for (const token of tokens) { if (token.symbol?.toLowerCase() === lowerSymbol) return resolveTokenForChain(token, chainId); } return undefined; } /** * Resolves a {@link Token} to a {@link ResolvedToken} for `chainId`, or * `undefined` when the token has no address for `chainId`. @internal */ function resolveTokenForChain(token, chainId) { const address = token.addresses[chainId]; if (!address) return undefined; return { address, currency: token.currency, decimals: token.decimals, name: token.name, popular: token.popular, symbol: token.symbol, }; } /** * Infers a token's `decimals` from the client's `tokens` array by matching * `address` against each token's address for the client's `chain.id`. * @internal */ function inferDecimals(client, address) { const tokens = client.tokens; const chainId = client.chain?.id; if (tokens && chainId !== undefined) for (const token of tokens) { const resolved = resolveTokenForChain(token, chainId); if (resolved && isAddressEqual(resolved.address, address)) return resolved.decimals; } return undefined; } /** * Resolves token decimals, fetching from the token contract when they are not * provided explicitly or declared on the chain. * @internal */ export async function resolveTokenWithDecimals(client, parameters) { const { address, decimals } = resolveToken(client, parameters); if (decimals !== undefined) return { address, decimals }; return { address, decimals: await readContract(client, { abi: Abis.tip20, address, functionName: 'decimals', }), }; } /** * Picks the transaction-override fields shared by Tempo write actions (including * Tempo-specific fields), so the action-specific args (`token`, `amount`, `to`, * etc.) don't leak into `estimateContractGas` / `simulateContract` requests. * @internal */ export function pickWriteParameters(parameters) { const { account, chain, feePayer, feeToken, gas, keyAuthorization, maxFeePerGas, maxPriorityFeePerGas, nonce, nonceKey, validAfter, validBefore, } = parameters; return { account, chain, feePayer, feeToken, gas, keyAuthorization, maxFeePerGas, maxPriorityFeePerGas, nonce, nonceKey, validAfter, validBefore, }; } /** * Splits {@link CallParameters} into `[client, args]`, with an `undefined` * client when the caller omitted it. * @internal */ export function resolveCallParameters(parameters) { if (parameters.length === 2) return parameters; return [undefined, parameters[0]]; } export function defineCall(call) { return { ...call, data: encodeFunctionData(call), to: call.address, }; } /** * Normalizes a value into a structured-clone compatible format. * * @see https://developer.mozilla.org/en-US/docs/Web/API/Window/structuredClone * @internal */ export function normalizeValue(value) { if (Array.isArray(value)) return value.map(normalizeValue); if (typeof value === 'function') return undefined; if (typeof value !== 'object' || value === null) return value; if (Object.getPrototypeOf(value) !== Object.prototype) try { return structuredClone(value); } catch { return undefined; } const normalized = {}; for (const [k, v] of Object.entries(value)) normalized[k] = normalizeValue(v); return normalized; } //# sourceMappingURL=utils.js.map