feat: add Solana USDT/USDC support and refine admin payouts UI
This commit is contained in:
@@ -4,57 +4,55 @@
|
||||
"id": "POLYGON",
|
||||
"name": "Polygon",
|
||||
"icon": "🟣",
|
||||
"rpc": "https://rpc.ankr.com/polygon",
|
||||
"rpc": "https://polygon-bor-rpc.publicnode.com",
|
||||
"chainId": 137,
|
||||
"tokens": [
|
||||
{ "symbol": "USDT", "address": "0xc2132D05D31C914a87C6611C10748AEb04B58e8F", "decimals": 6, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/usdt.png" },
|
||||
{ "symbol": "USDC", "address": "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359", "decimals": 6, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/usdc.png" },
|
||||
{ "symbol": "DAI", "address": "0x8f3Cf7ad23Cd3BaDDb9735AFf95930030000000", "decimals": 18, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/dai.png" },
|
||||
{ "symbol": "MATIC", "address": "NATIVE", "decimals": 18, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/matic.png" },
|
||||
{ "symbol": "WBTC", "address": "0x1bfd67037b42cf73acf2047067bd4f2c47d9bfd6", "decimals": 8, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/wbtc.png" },
|
||||
{ "symbol": "WETH", "address": "0x7ceb23fd6bc0ad59e62ac25578270cff1b9f619", "decimals": 18, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/eth.png" },
|
||||
{ "symbol": "SHIB", "address": "0x6f8a36397efed74758fdef2850935bb27d49e1ed", "decimals": 18, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/shib.png" },
|
||||
{ "symbol": "LINK", "address": "0xb0897686c545045aFc77CF20eC7A532E3120E0F1", "decimals": 18, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/link.png" },
|
||||
{ "symbol": "PEPE", "address": "0x98f6d546343544fae8e60aaead11a68e64c29df6", "decimals": 18, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/pepe.png" }
|
||||
{ "symbol": "USDT", "address": "0xc2132D05D31c914a87C6611C10748AEb04B58e8F", "decimals": 6, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/usdt.png" },
|
||||
{ "symbol": "USDC", "address": "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359", "decimals": 6, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/usdc.png" },
|
||||
{ "symbol": "DAI", "address": "0x8f3CF7aD23cD3cAddbf6764F01C21927E6AA0C45", "decimals": 18, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/dai.png" },
|
||||
{ "symbol": "WBTC", "address": "0x1BFD67037B42Cf73acF2047067bd4F2C47D9BfD6", "decimals": 8, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/wbtc.png" },
|
||||
{ "symbol": "WETH", "address": "0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619", "decimals": 18, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/eth.png" },
|
||||
{ "symbol": "LINK", "address": "0xb0897686c545045aFc77CF20eC7A532E3120E0F1", "decimals": 18, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/link.png" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "BSC",
|
||||
"name": "BNB Chain",
|
||||
"icon": "🟡",
|
||||
"rpc": "https://rpc.ankr.com/bsc",
|
||||
"rpc": "https://bsc-rpc.publicnode.com",
|
||||
"chainId": 56,
|
||||
"tokens": [
|
||||
{ "symbol": "BNB", "address": "NATIVE", "decimals": 18, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/bnb.png" },
|
||||
{ "symbol": "USDT", "address": "0x55d398326f99059fF775485246999027B3197955", "decimals": 18, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/usdt.png" },
|
||||
{ "symbol": "USDC", "address": "0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d", "decimals": 18, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/usdc.png" },
|
||||
{ "symbol": "BNB", "address": "NATIVE", "decimals": 18, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/bnb.png" },
|
||||
{ "symbol": "BTCCB", "address": "0x7130d2a12b9bcbfae4f2634d864a1ee1ce3ead9c", "decimals": 18, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/btc.png" },
|
||||
{ "symbol": "ETH", "address": "0x2170ed0880ac9a755fd29b2688956bd959f933f8", "decimals": 18, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/eth.png" },
|
||||
{ "symbol": "XRP", "address": "0x1d2f0da169059048e02d847144ee6dd583849764", "decimals": 18, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/xrp.png" },
|
||||
{ "symbol": "ADA", "address": "0x3ee2200efb3400fabb9aacf31297cbdd1d435d47", "decimals": 18, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/ada.png" },
|
||||
{ "symbol": "DOGE", "address": "0xba2ae4247dd5c32ed17016355e8eb10", "decimals": 8, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/doge.png" },
|
||||
{ "symbol": "DOT", "address": "0x7083609fce4d1d8dc0c979aab8c869ea2c873402", "decimals": 18, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/dot.png" },
|
||||
{ "symbol": "LTC", "address": "0x4338665c00995c36411f1233069cc04868f18731", "decimals": 18, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/ltc.png" }
|
||||
{ "symbol": "ETH", "address": "0x2170Ed0880ac9A755fd29B2688956BD959F933F8", "decimals": 18, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/eth.png" },
|
||||
{ "symbol": "BTCB", "address": "0x7130d2A12B9BCbFAe4f2634d864A1Ee1Ce3Ead9c", "decimals": 18, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/btc.png" },
|
||||
{ "symbol": "XRP", "address": "0x1D2f0Da169CEb9fC7B3144828DB6519f14a02304", "decimals": 18, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/xrp.png" },
|
||||
{ "symbol": "DOGE", "address": "0xbA2aE424d960c26247Dd6c32edC70B295c744C43", "decimals": 8, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/doge.png" },
|
||||
{ "symbol": "DOT", "address": "0x7083609fCE4d1d8Dc0C979AAb8c869Ea2C873402", "decimals": 18, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/dot.png" },
|
||||
{ "symbol": "ADA", "address": "0x3EE2200Efb3400fAbB9AacF31297cBdD1d435D47", "decimals": 18, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/ada.png" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "ETH",
|
||||
"name": "Ethereum",
|
||||
"icon": "🔵",
|
||||
"rpc": "https://rpc.ankr.com/eth",
|
||||
"rpc": "https://ethereum-rpc.publicnode.com",
|
||||
"chainId": 1,
|
||||
"tokens": [
|
||||
{ "symbol": "ETH", "address": "NATIVE", "decimals": 18, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/eth.png" },
|
||||
{ "symbol": "USDT", "address": "0xdAC17F958D2ee523a2206206994597C13D831ec7", "decimals": 6, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/usdt.png" },
|
||||
{ "symbol": "USDC", "address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", "decimals": 6, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/usdc.png" },
|
||||
{ "symbol": "DAI", "address": "0x6B175474E89094C44Da98b954EedeAC495271d0F", "decimals": 18, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/dai.png" },
|
||||
{ "symbol": "ETH", "address": "NATIVE", "decimals": 18, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/eth.png" },
|
||||
{ "symbol": "WBTC", "address": "0x2260fac5e5542a773aa44fbcfedf7c193bc2c599", "decimals": 8, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/wbtc.png" },
|
||||
{ "symbol": "SHIB", "address": "0x95ad61b0a150d79219dcf64e1e6cc01f0b64c4ce", "decimals": 18, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/shib.png" },
|
||||
{ "symbol": "LINK", "address": "0x514910771af9ca656af840dff83e8264ecf986ca", "decimals": 18, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/link.png" },
|
||||
{ "symbol": "UNI", "address": "0x1f9840a85d5af5bf1d1762f925bdaddc4201f984", "decimals": 18, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/uni.png" },
|
||||
{ "symbol": "PEPE", "address": "0x6982508145454ce325ddbe47a25d4ec3d2311933", "decimals": 18, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/pepe.png" }
|
||||
{ "symbol": "WBTC", "address": "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599", "decimals": 8, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/wbtc.png" },
|
||||
{ "symbol": "LINK", "address": "0x514910771AF9Ca656af840dff83E8264EcF986CA", "decimals": 18, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/link.png" },
|
||||
{ "symbol": "UNI", "address": "0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984", "decimals": 18, "logo": "https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/uni.png" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "SOLANA",
|
||||
"name": "Solana (Testnet/Devnet)",
|
||||
"name": "Solana (Devnet)",
|
||||
"icon": "🟢",
|
||||
"rpc": "https://api.devnet.solana.com",
|
||||
"tokens": [
|
||||
|
||||
@@ -36,7 +36,13 @@ export class CryptoEngine {
|
||||
} else if (this.network === 'BITCOIN') {
|
||||
// Bitcoin usually handled via Electrum OR simple Public API
|
||||
} else {
|
||||
this.provider = new ethers.JsonRpcProvider(this.config.rpc);
|
||||
const options = this.config.chainId
|
||||
? { chainId: this.config.chainId, name: this.config.name.toLowerCase() }
|
||||
: undefined;
|
||||
|
||||
this.provider = new ethers.JsonRpcProvider(this.config.rpc, options, {
|
||||
staticNetwork: !!this.config.chainId
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,6 +104,107 @@ export class CryptoEngine {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a specific amount from treasury to a destination address (for payouts)
|
||||
*/
|
||||
async sendPayout(
|
||||
senderPrivateKey: string,
|
||||
destinationAddress: string,
|
||||
amount: string,
|
||||
tokenSymbol: string = 'SOL'
|
||||
): Promise<{ success: boolean; txHash: string | null; error?: string }> {
|
||||
console.log(`[Payout] Sending ${amount} ${tokenSymbol} on ${this.network} to ${destinationAddress}`);
|
||||
|
||||
if (this.network === 'SOLANA') {
|
||||
return this.sendSolanaPayout(senderPrivateKey, destinationAddress, amount, tokenSymbol);
|
||||
} else {
|
||||
// EVM / TRON / BTC - placeholder for now
|
||||
console.warn(`[Payout] Real transfer not yet implemented for ${this.network}. Using mock.`);
|
||||
return { success: true, txHash: `mock_${this.network}_${Date.now()}` };
|
||||
}
|
||||
}
|
||||
|
||||
private async sendSolanaPayout(
|
||||
senderPrivateKey: string,
|
||||
destinationAddress: string,
|
||||
amount: string,
|
||||
tokenSymbol: string
|
||||
): Promise<{ success: boolean; txHash: string | null; error?: string }> {
|
||||
try {
|
||||
// Decode private key (support both base64 and base58)
|
||||
let secretKey: Uint8Array;
|
||||
try {
|
||||
secretKey = Uint8Array.from(Buffer.from(senderPrivateKey, 'base64'));
|
||||
if (secretKey.length !== 64) throw new Error('not base64');
|
||||
} catch {
|
||||
secretKey = bs58.decode(senderPrivateKey);
|
||||
}
|
||||
|
||||
const senderKeypair = Keypair.fromSecretKey(secretKey);
|
||||
const destPubKey = new PublicKey(destinationAddress);
|
||||
const parsedAmount = parseFloat(amount);
|
||||
|
||||
console.log(`[Payout SOL] From: ${senderKeypair.publicKey.toBase58()} -> To: ${destinationAddress} | ${parsedAmount} ${tokenSymbol}`);
|
||||
|
||||
if (tokenSymbol === 'SOL' || tokenSymbol === 'NATIVE') {
|
||||
const lamports = Math.floor(parsedAmount * LAMPORTS_PER_SOL);
|
||||
|
||||
const balance = await this.solConnection.getBalance(senderKeypair.publicKey);
|
||||
if (balance < lamports + 5000) {
|
||||
return { success: false, txHash: null, error: `Insufficient SOL. Have: ${balance / LAMPORTS_PER_SOL}, Need: ${parsedAmount}` };
|
||||
}
|
||||
|
||||
const transaction = new Transaction().add(
|
||||
SystemProgram.transfer({
|
||||
fromPubkey: senderKeypair.publicKey,
|
||||
toPubkey: destPubKey,
|
||||
lamports
|
||||
})
|
||||
);
|
||||
|
||||
const { blockhash } = await this.solConnection.getLatestBlockhash();
|
||||
transaction.recentBlockhash = blockhash;
|
||||
transaction.feePayer = senderKeypair.publicKey;
|
||||
transaction.sign(senderKeypair);
|
||||
|
||||
const txHash = await this.solConnection.sendRawTransaction(transaction.serialize());
|
||||
await this.solConnection.confirmTransaction(txHash);
|
||||
|
||||
console.log(`[Payout SOL] ✅ Sent ${parsedAmount} SOL | TX: ${txHash}`);
|
||||
return { success: true, txHash };
|
||||
} else {
|
||||
// SPL token payout
|
||||
const tokenConfig = this.getTokenConfig(tokenSymbol);
|
||||
if (!tokenConfig) return { success: false, txHash: null, error: `Token ${tokenSymbol} not found` };
|
||||
|
||||
const { createTransferInstruction, getAssociatedTokenAddress: getATA } = require('@solana/spl-token');
|
||||
const mintPubKey = new PublicKey(tokenConfig.address);
|
||||
const senderATA = await getATA(mintPubKey, senderKeypair.publicKey);
|
||||
const destATA = await getATA(mintPubKey, destPubKey);
|
||||
|
||||
const tokenAmount = Math.floor(parsedAmount * Math.pow(10, tokenConfig.decimals));
|
||||
|
||||
const transaction = new Transaction().add(
|
||||
createTransferInstruction(senderATA, destATA, senderKeypair.publicKey, tokenAmount)
|
||||
);
|
||||
|
||||
const { blockhash } = await this.solConnection.getLatestBlockhash();
|
||||
transaction.recentBlockhash = blockhash;
|
||||
transaction.feePayer = senderKeypair.publicKey;
|
||||
transaction.sign(senderKeypair);
|
||||
|
||||
const txHash = await this.solConnection.sendRawTransaction(transaction.serialize());
|
||||
await this.solConnection.confirmTransaction(txHash);
|
||||
|
||||
console.log(`[Payout SOL] ✅ Sent ${parsedAmount} ${tokenSymbol} | TX: ${txHash}`);
|
||||
return { success: true, txHash };
|
||||
}
|
||||
} catch (e: any) {
|
||||
console.error(`[Payout SOL] ❌ Error:`, e.message);
|
||||
return { success: false, txHash: null, error: e.message };
|
||||
}
|
||||
}
|
||||
|
||||
private async sweepEVM(
|
||||
tempWalletPrivateKey: string,
|
||||
platformAddress: string,
|
||||
@@ -137,15 +244,95 @@ export class CryptoEngine {
|
||||
}
|
||||
|
||||
private async sweepSolana(
|
||||
tempWalletPrivateKey: string,
|
||||
platformAddress: string,
|
||||
senderPrivateKey: string,
|
||||
destinationAddress: string,
|
||||
tokenSymbol: string
|
||||
) {
|
||||
console.log(`[Sweep SOLANA] Sweeping 100% to Platform Treasury: ${platformAddress}`);
|
||||
return {
|
||||
success: true,
|
||||
txHash: 'sol_mock_tx_' + Math.random().toString(36).substring(7)
|
||||
};
|
||||
console.log(`[Sweep SOLANA] Sending ${tokenSymbol} to ${destinationAddress}`);
|
||||
|
||||
try {
|
||||
// Decode private key (support both base64 and base58)
|
||||
let secretKey: Uint8Array;
|
||||
try {
|
||||
secretKey = Uint8Array.from(Buffer.from(senderPrivateKey, 'base64'));
|
||||
if (secretKey.length !== 64) throw new Error('not base64');
|
||||
} catch {
|
||||
secretKey = bs58.decode(senderPrivateKey);
|
||||
}
|
||||
|
||||
const senderKeypair = Keypair.fromSecretKey(secretKey);
|
||||
const destPubKey = new PublicKey(destinationAddress);
|
||||
|
||||
if (tokenSymbol === 'SOL' || tokenSymbol === 'NATIVE') {
|
||||
// Get balance and send almost all (leave 5000 lamports for rent)
|
||||
const balance = await this.solConnection.getBalance(senderKeypair.publicKey);
|
||||
const sendAmount = balance - 10000; // leave 0.00001 SOL for fees
|
||||
|
||||
if (sendAmount <= 0) {
|
||||
return { success: false, txHash: null, error: 'Insufficient SOL balance' };
|
||||
}
|
||||
|
||||
const transaction = new Transaction().add(
|
||||
SystemProgram.transfer({
|
||||
fromPubkey: senderKeypair.publicKey,
|
||||
toPubkey: destPubKey,
|
||||
lamports: sendAmount
|
||||
})
|
||||
);
|
||||
|
||||
const { blockhash } = await this.solConnection.getLatestBlockhash();
|
||||
transaction.recentBlockhash = blockhash;
|
||||
transaction.feePayer = senderKeypair.publicKey;
|
||||
transaction.sign(senderKeypair);
|
||||
|
||||
const txHash = await this.solConnection.sendRawTransaction(transaction.serialize());
|
||||
await this.solConnection.confirmTransaction(txHash);
|
||||
|
||||
console.log(`[Sweep SOLANA] ✅ Sent ${sendAmount / LAMPORTS_PER_SOL} SOL | TX: ${txHash}`);
|
||||
return { success: true, txHash };
|
||||
} else {
|
||||
// SPL Token transfer (USDT, USDC) - requires ATA
|
||||
const tokenConfig = this.getTokenConfig(tokenSymbol);
|
||||
if (!tokenConfig) throw new Error(`Token ${tokenSymbol} not found`);
|
||||
|
||||
const { createTransferInstruction, getAssociatedTokenAddress: getATA, getOrCreateAssociatedTokenAccount } = require('@solana/spl-token');
|
||||
const mintPubKey = new PublicKey(tokenConfig.address);
|
||||
|
||||
const senderATA = await getATA(mintPubKey, senderKeypair.publicKey);
|
||||
const destATA = await getATA(mintPubKey, destPubKey);
|
||||
|
||||
// Check sender token balance
|
||||
try {
|
||||
const accountInfo = await getAccount(this.solConnection, senderATA);
|
||||
const tokenBalance = Number(accountInfo.amount);
|
||||
|
||||
if (tokenBalance <= 0) {
|
||||
return { success: false, txHash: null, error: `No ${tokenSymbol} balance` };
|
||||
}
|
||||
|
||||
const transaction = new Transaction().add(
|
||||
createTransferInstruction(senderATA, destATA, senderKeypair.publicKey, tokenBalance)
|
||||
);
|
||||
|
||||
const { blockhash } = await this.solConnection.getLatestBlockhash();
|
||||
transaction.recentBlockhash = blockhash;
|
||||
transaction.feePayer = senderKeypair.publicKey;
|
||||
transaction.sign(senderKeypair);
|
||||
|
||||
const txHash = await this.solConnection.sendRawTransaction(transaction.serialize());
|
||||
await this.solConnection.confirmTransaction(txHash);
|
||||
|
||||
console.log(`[Sweep SOLANA] ✅ Sent ${tokenBalance} ${tokenSymbol} | TX: ${txHash}`);
|
||||
return { success: true, txHash };
|
||||
} catch (e: any) {
|
||||
console.error(`[Sweep SOLANA] Token transfer error:`, e.message);
|
||||
return { success: false, txHash: null, error: e.message };
|
||||
}
|
||||
}
|
||||
} catch (e: any) {
|
||||
console.error(`[Sweep SOLANA] Error:`, e.message);
|
||||
return { success: false, txHash: null, error: e.message };
|
||||
}
|
||||
}
|
||||
|
||||
private async sweepTron(
|
||||
@@ -172,6 +359,67 @@ export class CryptoEngine {
|
||||
};
|
||||
}
|
||||
|
||||
async getBalance(address: string, tokenSymbol: string = 'NATIVE'): Promise<string> {
|
||||
try {
|
||||
const tokenConfig = this.getTokenConfig(tokenSymbol);
|
||||
if (!tokenConfig) return "0.00";
|
||||
|
||||
if (this.network === 'SOLANA') {
|
||||
const pubKey = new PublicKey(address);
|
||||
if (tokenConfig.address === 'NATIVE') {
|
||||
const balance = await this.solConnection.getBalance(pubKey);
|
||||
return (balance / LAMPORTS_PER_SOL).toFixed(4);
|
||||
} else {
|
||||
const tokenMint = new PublicKey(tokenConfig.address);
|
||||
const ata = await getAssociatedTokenAddress(tokenMint, pubKey);
|
||||
try {
|
||||
const accountInfo = await getAccount(this.solConnection, ata);
|
||||
return (Number(accountInfo.amount) / Math.pow(10, tokenConfig.decimals)).toFixed(4);
|
||||
} catch (e) { return "0.00"; }
|
||||
}
|
||||
} else if (this.network === 'TRON') {
|
||||
try {
|
||||
if (tokenConfig.address === 'NATIVE') {
|
||||
const balance = await this.tronWeb.trx.getBalance(address);
|
||||
return (balance / 1000000).toFixed(2);
|
||||
} else {
|
||||
const contract = await this.tronWeb.contract().at(tokenConfig.address);
|
||||
const balance = await contract.balanceOf(address).call();
|
||||
return (Number(balance) / Math.pow(10, tokenConfig.decimals)).toFixed(2);
|
||||
}
|
||||
} catch (e: any) {
|
||||
console.warn(`[CryptoEngine] TRON balance check failed (likely API key or address issue):`, e.message);
|
||||
return "0.00";
|
||||
}
|
||||
} else if (this.network === 'BITCOIN') {
|
||||
try {
|
||||
const btcRes = await fetch(`https://blockchain.info/q/addressbalance/${address}`).then(r => r.text());
|
||||
return (parseInt(btcRes) / 1e8).toFixed(8);
|
||||
} catch (e) { return "0.00"; }
|
||||
} else {
|
||||
// EVM
|
||||
try {
|
||||
const safeAddress = ethers.getAddress(address);
|
||||
if (tokenConfig.address === 'NATIVE') {
|
||||
const balance = await this.provider.getBalance(safeAddress);
|
||||
return ethers.formatEther(balance);
|
||||
} else {
|
||||
const safeTokenAddr = ethers.getAddress(tokenConfig.address);
|
||||
const contract = new ethers.Contract(safeTokenAddr, ERC20_ABI, this.provider);
|
||||
const balance = await contract.balanceOf(safeAddress);
|
||||
return ethers.formatUnits(balance, tokenConfig.decimals);
|
||||
}
|
||||
} catch (e: any) {
|
||||
console.warn(`[CryptoEngine] EVM balance check failed for ${tokenSymbol}:`, e.message);
|
||||
return "0.00";
|
||||
}
|
||||
}
|
||||
} catch (e: any) {
|
||||
console.error(`[CryptoEngine] getBalance error for ${tokenSymbol}:`, e);
|
||||
return "0.00";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies if a specific amount has arrived at the address.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user