UNPKG

@jagad/icsi

Version:

Internet Computer Subaccount Indexer Library - TypeScript SDK for ICP multi-token subaccount management, transaction tracking, and automated sweeping with webhook support

175 lines (174 loc) 6.58 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Tokens = void 0; exports.getTokenConfig = getTokenConfig; exports.getDepositAddresses = getDepositAddresses; exports.getBalances = getBalances; exports.getTransactionsByTokenType = getTransactionsByTokenType; const query_1 = require("./query"); const update_1 = require("./update"); exports.Tokens = { ICP: { ICP: null }, CKUSDC: { CKUSDC: null }, CKUSDT: { CKUSDT: null }, CKBTC: { CKBTC: null }, }; function getTokenConfig(tokenType) { if ('ICP' in tokenType) { return { canisterId: process.env.ICP_CANISTER_ID || 'ryjl3-tyaaa-aaaaa-aaaba-cai', symbol: 'ICP', decimals: 8, }; } else if ('CKUSDC' in tokenType) { return { canisterId: process.env.CKUSDC_CANISTER_ID || 'xevnm-gaaaa-aaaar-qafnq-cai', symbol: 'CKUSDC', decimals: 6, }; } else if ('CKUSDT' in tokenType) { return { canisterId: process.env.CKUSDT_CANISTER_ID || 'cngnf-vqaaa-aaaar-qag4q-cai', symbol: 'CKUSDT', decimals: 6, }; } else if ('CKBTC' in tokenType) { return { canisterId: process.env.CKBTC_CANISTER_ID || 'mxzaz-hqaaa-aaaar-qaada-cai', symbol: 'CKBTC', decimals: 8, }; } throw new Error('Unknown token type'); } async function getDepositAddresses(agent, canisterId) { const addresses = []; // Get registered tokens const tokensResult = await (0, query_1.getRegisteredTokens)(agent, canisterId); if ('Err' in tokensResult) { throw new Error(`Failed to get registered tokens: ${tokensResult.Err}`); } const tokens = tokensResult.Ok; for (const [tokenType, tokenName] of tokens) { try { // Get nonce for subaccount creation const index = await (0, query_1.getNonce)(agent, canisterId); // Try to create subaccount (might already exist) await (0, update_1.addSubaccountForToken)(agent, canisterId, tokenType).catch(() => { // Ignore if already exists }); // Get subaccount ID const subaccountId = await (0, query_1.getSubaccountId)(agent, canisterId, index, tokenType); // Get ICRC account (deposit address) const icrcAccount = await (0, query_1.getIcrcAccount)(agent, canisterId, index); addresses.push({ tokenType, tokenName, subaccountId, depositAddress: icrcAccount, }); } catch (error) { console.error(`Error processing token ${tokenName}:`, error); } } return addresses; } async function getBalances(agent, canisterId) { const balances = []; // Get all transactions const transactionsResult = await (0, query_1.getUserVaultTransactions)(agent, canisterId, BigInt(0)); if ('Err' in transactionsResult) { throw new Error(`Failed to get transactions: ${transactionsResult.Err}`); } const transactions = transactionsResult.Ok; // Group by token type and calculate balances const balanceMap = new Map(); for (const tx of transactions) { const tokenKey = JSON.stringify(tx.token_type); // Only count non-swept transactions if (tx.sweep_status && 'NotSwept' in tx.sweep_status) { let amount = BigInt(0); if (tx.operation && tx.operation[0]) { if ('Mint' in tx.operation[0]) { amount = tx.operation[0].Mint.amount.e8s; } else if ('Transfer' in tx.operation[0]) { amount = tx.operation[0].Transfer.amount.e8s; } } const current = balanceMap.get(tokenKey) || { tokenType: tx.token_type, tokenName: '', amount: BigInt(0), }; current.amount += amount; balanceMap.set(tokenKey, current); } } // Get token names and decimals const tokensResult = await (0, query_1.getRegisteredTokens)(agent, canisterId); if ('Ok' in tokensResult) { for (const [tokenType, tokenName] of tokensResult.Ok) { const tokenKey = JSON.stringify(tokenType); const balance = balanceMap.get(tokenKey); if (balance && balance.amount > 0) { const config = getTokenConfig(tokenType); balances.push({ tokenType, tokenName, amount: balance.amount, decimals: config.decimals, }); } } } return balances; } async function getTransactionsByTokenType(agent, canisterId, tokenType) { // Validate token type if (!('ICP' in tokenType || 'CKUSDC' in tokenType || 'CKUSDT' in tokenType || 'CKBTC' in tokenType)) { throw new Error('Invalid token type'); } const transactionsResult = await (0, query_1.getUserVaultTransactions)(agent, canisterId, BigInt(0)); if ('Err' in transactionsResult) { throw new Error(`Failed to get transactions: ${transactionsResult.Err}`); } const allTransactions = transactionsResult.Ok; // Filter by token type const tokenKey = JSON.stringify(tokenType); const filteredTransactions = allTransactions.filter((tx) => JSON.stringify(tx.token_type) === tokenKey); // Map to a more user-friendly format return filteredTransactions.map((tx) => { let amount = BigInt(0); let from = ''; let to = ''; if (tx.operation && tx.operation[0]) { if ('Mint' in tx.operation[0]) { amount = tx.operation[0].Mint.amount.e8s; to = Buffer.from(tx.operation[0].Mint.to).toString('hex'); } else if ('Transfer' in tx.operation[0]) { amount = tx.operation[0].Transfer.amount.e8s; from = Buffer.from(tx.operation[0].Transfer.from).toString('hex'); to = Buffer.from(tx.operation[0].Transfer.to).toString('hex'); } } return { blockIndex: tx.index, amount: amount.toString(), from, to, timestamp: tx.created_at_time.timestamp_nanos, sweepStatus: tx.sweep_status, memo: tx.memo.toString(), txHash: tx.tx_hash, }; }); }