Monorepo for Aesthetic.Computer aesthetic.computer
4
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: multi-chain `wallets` command + raise kidlisp editor line limit

Add `node keeps.mjs wallets` to show balances across all chains
(XTZ, ETH, SOL, BTC, ADA) from vault wallets.json using public RPCs.

Raise kidlisp.com Monaco editor max lines from 16 to 64 so longer
pieces can be pasted in.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

+152 -2
+2 -2
system/public/kidlisp.com/index.html
··· 15662 15662 const isDarkMode = window.matchMedia('(prefers-color-scheme: dark)').matches; 15663 15663 const initialTheme = isDarkMode ? 'kidlisp-dark' : 'kidlisp-light'; 15664 15664 15665 - // Set max lines to 16 (fixed) 15666 - const maxLines = 16; 15665 + // Set max lines for editor 15666 + const maxLines = 64; 15667 15667 15668 15668 // Track if user has manually edited the editor (vs programmatic setValue) 15669 15669 let editorUserModified = false;
+150
tezos/keeps.mjs
··· 934 934 } 935 935 936 936 // ============================================================================ 937 + // Multi-Chain Wallet Balances 938 + // ============================================================================ 939 + 940 + async function getAllWalletBalances() { 941 + const walletsPath = path.join(CONFIG.paths.vault, 'wallets/wallets.json'); 942 + if (!fs.existsSync(walletsPath)) { 943 + console.error('❌ wallets.json not found in vault'); 944 + process.exit(1); 945 + } 946 + const { wallets } = JSON.parse(fs.readFileSync(walletsPath, 'utf8')); 947 + 948 + console.log('\n╔══════════════════════════════════════════════════════════════╗'); 949 + console.log('║ 🌐 All Wallet Balances ║'); 950 + console.log('╚══════════════════════════════════════════════════════════════╝\n'); 951 + 952 + // Group wallets by chain 953 + const chains = {}; 954 + for (const [key, w] of Object.entries(wallets)) { 955 + (chains[w.chain] ||= []).push({ key, ...w }); 956 + } 957 + 958 + // --- Tezos --- 959 + if (chains.tezos) { 960 + console.log('── Tezos ──────────────────────────────────────────────────────'); 961 + const tezos = new TezosToolkit(CONFIG.mainnet.rpc); 962 + for (const w of chains.tezos) { 963 + try { 964 + const bal = await tezos.tz.getBalance(w.address); 965 + const xtz = (bal.toNumber() / 1_000_000).toFixed(6); 966 + const label = w.domain || w.name; 967 + console.log(` ${label.padEnd(22)} ${xtz.padStart(14)} XTZ ${w.address}`); 968 + } catch (e) { 969 + console.log(` ${(w.domain || w.name).padEnd(22)} ${'error'.padStart(14)} ${w.address} (${e.message})`); 970 + } 971 + } 972 + // Also show keeps contract balance 973 + try { 974 + const contractAddr = fs.readFileSync( 975 + CONFIG.paths.contractAddresses.mainnet, 'utf8' 976 + ).trim(); 977 + const bal = await tezos.tz.getBalance(contractAddr); 978 + const xtz = (bal.toNumber() / 1_000_000).toFixed(6); 979 + console.log(` ${'keeps contract'.padEnd(22)} ${xtz.padStart(14)} XTZ ${contractAddr}`); 980 + } catch (e) { /* skip */ } 981 + console.log(); 982 + } 983 + 984 + // --- Ethereum --- 985 + if (chains.ethereum) { 986 + console.log('── Ethereum ───────────────────────────────────────────────────'); 987 + for (const w of chains.ethereum) { 988 + try { 989 + const resp = await fetch('https://ethereum-rpc.publicnode.com', { 990 + method: 'POST', 991 + headers: { 'Content-Type': 'application/json' }, 992 + body: JSON.stringify({ jsonrpc: '2.0', method: 'eth_getBalance', params: [w.address, 'latest'], id: 1 }), 993 + }); 994 + const data = await resp.json(); 995 + const eth = (Number(BigInt(data.result)) / 1e18).toFixed(6); 996 + const label = w.domain || w.name; 997 + console.log(` ${label.padEnd(22)} ${eth.padStart(14)} ETH ${w.address}`); 998 + } catch (e) { 999 + console.log(` ${(w.domain || w.name).padEnd(22)} ${'error'.padStart(14)} ${w.address}`); 1000 + } 1001 + } 1002 + console.log(); 1003 + } 1004 + 1005 + // --- Solana --- 1006 + if (chains.solana) { 1007 + console.log('── Solana ─────────────────────────────────────────────────────'); 1008 + for (const w of chains.solana) { 1009 + try { 1010 + const resp = await fetch('https://solana-rpc.publicnode.com', { 1011 + method: 'POST', 1012 + headers: { 'Content-Type': 'application/json' }, 1013 + body: JSON.stringify({ jsonrpc: '2.0', id: 1, method: 'getBalance', params: [w.address] }), 1014 + }); 1015 + const data = await resp.json(); 1016 + const sol = (data.result.value / 1e9).toFixed(6); 1017 + const label = w.name; 1018 + console.log(` ${label.padEnd(22)} ${sol.padStart(14)} SOL ${w.address}`); 1019 + } catch (e) { 1020 + console.log(` ${(w.domain || w.name).padEnd(22)} ${'error'.padStart(14)} ${w.address}`); 1021 + } 1022 + } 1023 + console.log(); 1024 + } 1025 + 1026 + // --- Bitcoin --- 1027 + if (chains.bitcoin) { 1028 + console.log('── Bitcoin ────────────────────────────────────────────────────'); 1029 + for (const w of chains.bitcoin) { 1030 + // Check both taproot and segwit addresses 1031 + const addr = w.address_taproot || w.address_segwit || w.address; 1032 + if (!addr) { 1033 + console.log(` ${w.name.padEnd(22)} ${'no address'.padStart(14)} (needs derivation)`); 1034 + continue; 1035 + } 1036 + try { 1037 + const resp = await fetch(`https://blockstream.info/api/address/${addr}`); 1038 + const data = await resp.json(); 1039 + // funded = total received, spent = total sent; chain_stats for confirmed 1040 + const confirmed = data.chain_stats || {}; 1041 + const satoshis = (confirmed.funded_txo_sum || 0) - (confirmed.spent_txo_sum || 0); 1042 + const btc = (satoshis / 1e8).toFixed(8); 1043 + const label = w.name; 1044 + console.log(` ${label.padEnd(22)} ${btc.padStart(14)} BTC ${addr}`); 1045 + } catch (e) { 1046 + console.log(` ${w.name.padEnd(22)} ${'error'.padStart(14)} ${addr}`); 1047 + } 1048 + } 1049 + console.log(); 1050 + } 1051 + 1052 + // --- Cardano --- 1053 + if (chains.cardano) { 1054 + console.log('── Cardano ────────────────────────────────────────────────────'); 1055 + for (const w of chains.cardano) { 1056 + if (!w.address) { 1057 + console.log(` ${w.name.padEnd(22)} ${'no address'.padStart(14)} (derive from mnemonic with cardano-serialization-lib)`); 1058 + continue; 1059 + } 1060 + try { 1061 + const resp = await fetch('https://api.koios.rest/api/v1/address_info', { 1062 + method: 'POST', 1063 + headers: { 'Content-Type': 'application/json' }, 1064 + body: JSON.stringify({ _addresses: [w.address] }), 1065 + }); 1066 + const data = await resp.json(); 1067 + const lovelace = data[0]?.balance || '0'; 1068 + const ada = (Number(lovelace) / 1e6).toFixed(6); 1069 + console.log(` ${w.name.padEnd(22)} ${ada.padStart(14)} ADA ${w.address}`); 1070 + } catch (e) { 1071 + console.log(` ${w.name.padEnd(22)} ${'error'.padStart(14)} ${w.address}`); 1072 + } 1073 + } 1074 + console.log(); 1075 + } 1076 + 1077 + console.log('🔗 Explorers: tzkt.io | etherscan.io | solscan.io | blockstream.info | cardanoscan.io\n'); 1078 + } 1079 + 1080 + // ============================================================================ 937 1081 // Wallet Balance 938 1082 // ============================================================================ 939 1083 ··· 4078 4222 await getBalance(getNetwork(1)); 4079 4223 break; 4080 4224 4225 + case 'wallets': 4226 + await getAllWalletBalances(); 4227 + break; 4228 + 4081 4229 case 'tokens': { 4082 4230 const limitFlag = flags.find(f => f.startsWith('--limit=')); 4083 4231 const limit = limitFlag ? Number.parseInt(limitFlag.split('=')[1], 10) : undefined; ··· 4509 4657 sync-secrets [network] Sync active contract/profile to Mongo secrets 4510 4658 status [network] Show contract status 4511 4659 balance [network] Check wallet balance 4660 + wallets Show all wallet balances (XTZ, ETH, SOL, BTC, ADA) 4512 4661 tokens [network] List tokens held by current wallet 4513 4662 market [network] Show Objkt listings/offers/sales snapshot 4514 4663 upload <piece> Upload bundle to IPFS ··· 4635 4784 syncCurrentContractToSecrets, 4636 4785 getContractStatus, 4637 4786 getBalance, 4787 + getAllWalletBalances, 4638 4788 listOwnedTokens, 4639 4789 showMarketSnapshot, 4640 4790 listTokenForSale,