@agentek/tools
Version:
Blockchain tools for AI agents
88 lines • 3.63 kB
JavaScript
import { parseUnits } from "viem";
import { assertOkResponse } from "../utils/fetch.js";
let _tokenListCache = null;
async function loadTokenList() {
const now = Date.now();
if (_tokenListCache && now - _tokenListCache.fetchedAt < 5 * 60_000)
return _tokenListCache.tokens;
const res = await fetch("https://assets.zamm.finance/tokenlist.json", {
signal: AbortSignal.timeout(12_000),
});
await assertOkResponse(res, "Failed to fetch tokenlist");
const json = await res.json();
const tokens = Array.isArray(json?.tokens) ? json.tokens : [];
_tokenListCache = { fetchedAt: now, tokens };
return tokens;
}
export async function resolveInputToToken(input, chainId) {
if (typeof input !== "string") {
const enriched = await enrichFromListByAddress(input.address, chainId, input.id);
if (enriched)
return enriched;
return {
address: input.address,
id: input.id,
standard: input.id !== undefined ? "ERC6909" : "ERC20",
decimals: input.id !== undefined ? 0 : 18,
};
}
const sym = input.trim().toUpperCase();
const entry = await findTokenListEntryBySymbol(sym, chainId);
if (!entry)
throw new Error(`Symbol "${sym}" not found on chainId ${chainId}.`);
const standard = entry.extensions?.standard === "ERC6909" ? "ERC6909" : "ERC20";
const idStr = entry.extensions?.id;
const id = idStr !== undefined ? BigInt(idStr) : undefined;
const decimals = typeof entry.decimals === "number" ? entry.decimals : standard === "ERC6909" ? 0 : 18;
return {
address: entry.address,
id,
standard,
decimals,
symbol: entry.symbol,
};
}
async function findTokenListEntryBySymbol(symbol, chainId) {
const list = await loadTokenList();
const candidates = list.filter((t) => t.chainId === chainId && t.symbol?.toUpperCase() === symbol.toUpperCase());
candidates.sort((a, b) => {
const aIs20 = a.extensions?.standard !== "ERC6909";
const bIs20 = b.extensions?.standard !== "ERC6909";
return Number(bIs20) - Number(aIs20); // prefer ERC20
});
return candidates[0];
}
export async function enrichFromListByAddress(address, chainId, id) {
const list = await loadTokenList();
const entry = list.find((t) => t.chainId === chainId && t.address.toLowerCase() === address.toLowerCase());
if (!entry)
return null;
const standard = entry.extensions?.standard === "ERC6909" || id !== undefined ? "ERC6909" : "ERC20";
const decimals = typeof entry.decimals === "number" ? entry.decimals : standard === "ERC6909" ? 0 : 18;
const entryId = entry.extensions?.id !== undefined ? BigInt(entry.extensions.id) : undefined;
return {
address,
id: id ?? entryId,
standard,
decimals,
symbol: entry.symbol,
};
}
export function toBaseUnits(amountStr, token) {
if (!/^\d+(\.\d+)?$/.test(amountStr))
throw new Error(`Invalid amount "${amountStr}". Use a numeric value.`);
if (token.standard === "ERC20") {
return parseUnits(amountStr, token.decimals ?? 18);
}
if ((token.decimals ?? 0) > 0) {
return parseUnits(amountStr, token.decimals);
}
if (amountStr.includes(".")) {
throw new Error(`Amount "${amountStr}" must be an integer for ERC6909 token id ${token.id ?? "(unspecified)"}`);
}
return BigInt(amountStr);
}
export function asToken(t) {
return t.id !== undefined ? { address: t.address, id: t.id } : { address: t.address };
}
//# sourceMappingURL=utils.js.map