UNPKG

@bitte-ai/agent-sdk

Version:

Agent SDK for Bitte Protocol

121 lines (120 loc) 4.39 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.safeTxServiceUrlFor = safeTxServiceUrlFor; exports.getSafeBalances = getSafeBalances; exports.flatSafeBalances = flatSafeBalances; exports.zerionToTokenBalance = zerionToTokenBalance; exports.zerionToTokenBalances = zerionToTokenBalances; const viem_1 = require("viem"); const zerion_sdk_1 = require("zerion-sdk"); const misc_1 = require("../misc"); const client_1 = require("./client"); const SAFE_NETWORKS = { 1: "mainnet", 10: "optimism", 56: "binance", 100: "gnosis-chain", 137: "polygon", 8453: "base", 42161: "arbitrum", 43114: "avalanche", 11155111: "sepolia", }; function safeTxServiceUrlFor(chainId) { const network = SAFE_NETWORKS[chainId]; if (!network) { console.warn(`Unsupported Safe Transaction Service chainId=${chainId}`); return undefined; } return `https://safe-transaction-${network}.safe.global`; } async function getSafeBalances(chainId, address, zerionKey) { const client = await (0, client_1.getClientForChain)(chainId); const codeAt = await client.getCode({ address }); if (!codeAt) { // Not a Safe - Get balances from Zerion. return getZerionBalances(chainId, address, zerionKey); } const baseUrl = safeTxServiceUrlFor(chainId); if (!baseUrl) { console.warn(`Chain ID ${chainId} not supported by Safe Transaction Service`); return []; } const trusted = false; // Avalanche USDC not trusted: 0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E const exclude_spam = chainId === 11155111 ? false : true; const url = `${baseUrl}/api/v1/safes/${(0, viem_1.checksumAddress)(address)}/balances/?trusted=${trusted}&exclude_spam=${exclude_spam}`; try { const response = await fetch(url, { headers: { accept: "application/json", }, }); if (!response.ok) { if (response.status === 404) { console.warn(`Safe not found for ${address}`); } throw new Error(`HTTP error! status: ${response.status}`); } const data = await response.json(); return data; } catch (error) { console.warn("Error fetching Safe balances:", error); return getZerionBalances(chainId, address, zerionKey); } } async function getZerionBalances(chainId, address, zerionKey) { if (!zerionKey) { return []; } console.info("Zerion Key provided - using Zerion"); // Not a Safe, try Zerion try { const zerion = new zerion_sdk_1.ZerionAPI(zerionKey); // TODO(bh2smith): This is not super efficient, but it works for now. // Zerion API has its own network filter (but its not by chainID). const balances = await zerion.ui.getUserBalances(address, { options: { supportedChains: [chainId] }, }); return zerionToTokenBalances(balances.tokens); } catch (error) { console.error("Error fetching Zerion balances:", error); return []; } } async function flatSafeBalances(chainId, address) { const balances = await getSafeBalances(chainId, address); // Flatten the balance Response return { balances: balances.map((b) => ({ token: b.tokenAddress, balance: b.balance, symbol: b.token?.symbol || null, decimals: b.token?.decimals || 18, logoUri: b.token?.logoUri || null, })), }; } // TODO(bh2smith): Move this into Zerion SDK function zerionToTokenBalance(userToken) { const { meta, balances } = userToken; return { tokenAddress: meta.contractAddress || null, token: { name: meta.name, symbol: meta.symbol, decimals: meta.decimals, logoUri: meta.tokenIcon || "", }, balance: (0, viem_1.parseUnits)((0, misc_1.scientificToDecimal)(balances.balance), meta.decimals).toString(), fiatBalance: balances.usdBalance.toFixed(2), fiatConversion: (balances.price || 0).toFixed(2), }; } // Helper function to convert array of UserTokens to TokenBalances function zerionToTokenBalances(userTokens) { return userTokens .filter((token) => !token.meta.isSpam) // Filter out spam tokens .map(zerionToTokenBalance); }