blumefi 2.2.0 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +4 -2
  2. package/cli.js +130 -8
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -38,6 +38,7 @@ blumefi pad launch <name> <symbol> [desc] # Launch a token on bonding curve
38
38
  blumefi pad buy <token> <xrp_amount> # Buy tokens with XRP
39
39
  blumefi pad sell <token> <amount|all> # Sell tokens for XRP
40
40
  blumefi pad info <token> # View token info and progress
41
+ blumefi pad search <query> # Search tokens by name or symbol
41
42
  blumefi pad tokens # List recent tokens
42
43
  ```
43
44
 
@@ -84,12 +85,13 @@ blumefi trade price # Get current XRP price
84
85
 
85
86
  Collateral is in RLUSD. Default leverage is 2x if not specified.
86
87
 
87
- ### Wallet & Network
88
+ ### Wallet & Account
88
89
 
89
90
  ```bash
90
91
  blumefi wallet new # Generate a new wallet
92
+ blumefi balance [address] # Show XRP and token balances
91
93
  blumefi faucet [address] # Get 25 testnet XRP
92
- blumefi status # Show network info, contracts, and balance
94
+ blumefi status # Show network info and contracts
93
95
  ```
94
96
 
95
97
  ### Options
package/cli.js CHANGED
@@ -403,8 +403,16 @@ async function cmdSwap(amountStr, fromToken, toToken) {
403
403
  const amountOutMin = amountOut * 99n / 100n
404
404
 
405
405
  const outFormatted = viem.formatUnits(amountOut, toDecimals)
406
- const fromLabel = fromToken.toUpperCase()
407
- const toLabel = toToken.toUpperCase()
406
+
407
+ // Resolve display labels — show symbol instead of raw address
408
+ let fromLabel = fromToken.toUpperCase()
409
+ let toLabel = toToken.toUpperCase()
410
+ if (fromToken.startsWith('0x')) {
411
+ try { fromLabel = await readContract({ address: from.address, abi: ERC20_ABI, functionName: 'symbol', args: [] }) } catch {}
412
+ }
413
+ if (toToken.startsWith('0x')) {
414
+ try { toLabel = await readContract({ address: to.address, abi: ERC20_ABI, functionName: 'symbol', args: [] }) } catch {}
415
+ }
408
416
 
409
417
  console.log(`\n Swap: ${amount} ${fromLabel} -> ~${parseFloat(outFormatted).toFixed(6)} ${toLabel}`)
410
418
  console.log(` Network: ${chain}`)
@@ -480,8 +488,17 @@ async function cmdSwapQuote(amountStr, fromToken, toToken) {
480
488
  const outFormatted = viem.formatUnits(amountOut, toDecimals)
481
489
  const rate = parseFloat(outFormatted) / parseFloat(amountStr)
482
490
 
483
- console.log(`\n Quote: ${amountStr} ${fromToken.toUpperCase()} -> ${parseFloat(outFormatted).toFixed(6)} ${toToken.toUpperCase()}`)
484
- console.log(` Rate: 1 ${fromToken.toUpperCase()} = ${rate.toFixed(6)} ${toToken.toUpperCase()}`)
491
+ let fromLabel = fromToken.toUpperCase()
492
+ let toLabel = toToken.toUpperCase()
493
+ if (fromToken.startsWith('0x')) {
494
+ try { fromLabel = await readContract({ address: from.address, abi: ERC20_ABI, functionName: 'symbol', args: [] }) } catch {}
495
+ }
496
+ if (toToken.startsWith('0x')) {
497
+ try { toLabel = await readContract({ address: to.address, abi: ERC20_ABI, functionName: 'symbol', args: [] }) } catch {}
498
+ }
499
+
500
+ console.log(`\n Quote: ${amountStr} ${fromLabel} -> ${parseFloat(outFormatted).toFixed(6)} ${toLabel}`)
501
+ console.log(` Rate: 1 ${fromLabel} = ${rate.toFixed(6)} ${toLabel}`)
485
502
  console.log(` Network: ${getChain()}`)
486
503
  console.log(`\n Execute: blumefi swap ${amountStr} ${fromToken} ${toToken}`)
487
504
  }
@@ -963,6 +980,44 @@ async function cmdPadInfo(tokenAddress) {
963
980
  }
964
981
  }
965
982
 
983
+ async function cmdPadSearch(query) {
984
+ if (!query) {
985
+ console.error('Usage: blumefi pad search <name or symbol>')
986
+ console.error(' blumefi pad search tulip')
987
+ process.exit(1)
988
+ }
989
+
990
+ const chain = getChain()
991
+ const q = query.toLowerCase()
992
+
993
+ try {
994
+ const data = await apiFetch(`/pad/tokens?chain=${chain}&limit=50&sort=recent`)
995
+ const tokens = data.data || data.tokens || data || []
996
+ if (!Array.isArray(tokens)) { console.log('No tokens found.'); return }
997
+
998
+ const matches = tokens.filter(t => {
999
+ const name = (t.name || '').toLowerCase()
1000
+ const symbol = (t.symbol || '').toLowerCase()
1001
+ return name.includes(q) || symbol.includes(q)
1002
+ })
1003
+
1004
+ if (!matches.length) { console.log(`\n No tokens matching "${query}" on ${chain}.`); return }
1005
+
1006
+ console.log(`\n Search: "${query}" on ${chain} — ${matches.length} match${matches.length === 1 ? '' : 'es'}\n`)
1007
+ for (const t of matches) {
1008
+ const name = t.name || '???'
1009
+ const symbol = t.symbol || '???'
1010
+ const graduated = t.graduated ? ' [GRADUATED]' : ''
1011
+ const reserve = t.reserveBalance ? ` ${parseFloat(t.reserveBalance).toFixed(1)} XRP` : ''
1012
+ console.log(` ${name} (${symbol})${graduated}${reserve}`)
1013
+ console.log(` ${t.address}`)
1014
+ console.log()
1015
+ }
1016
+ } catch {
1017
+ console.log(`\n Search not available. Browse: https://${chain === 'mainnet' ? '' : 'testnet.'}pad.blumefi.com`)
1018
+ }
1019
+ }
1020
+
966
1021
  async function cmdPadTokens() {
967
1022
  const chain = getChain()
968
1023
  try {
@@ -987,6 +1042,70 @@ async function cmdPadTokens() {
987
1042
  }
988
1043
  }
989
1044
 
1045
+ // ─── Balance command ─────────────────────────────────────────────────
1046
+
1047
+ async function cmdBalance(address) {
1048
+ const viem = await loadViem()
1049
+ const chain = getChain()
1050
+ const net = getNetwork()
1051
+ const pub = await getPublicClient()
1052
+
1053
+ if (!address) {
1054
+ const key = process.env.WALLET_PRIVATE_KEY || process.env.PRIVATE_KEY
1055
+ if (key) {
1056
+ const k = key.startsWith('0x') ? key : `0x${key}`
1057
+ address = viem.privateKeyToAccount(k).address
1058
+ } else { console.error('Usage: blumefi balance [address]'); process.exit(1) }
1059
+ }
1060
+
1061
+ const xrpBalance = await pub.getBalance({ address })
1062
+ const xrpFormatted = parseFloat(viem.formatEther(xrpBalance)).toFixed(4)
1063
+
1064
+ console.log(`\n Balances for ${address}`)
1065
+ console.log(` Network: ${chain}`)
1066
+ console.log(` ─────────────────────────────────────`)
1067
+ console.log(` XRP: ${xrpFormatted}`)
1068
+
1069
+ // Check known tokens
1070
+ const tokens = []
1071
+ if (net.rlusd) tokens.push({ address: net.rlusd, name: 'RLUSD' })
1072
+
1073
+ // Check pad tokens the user might hold — query API for recent tokens
1074
+ try {
1075
+ const data = await apiFetch(`/pad/tokens?chain=${chain}&limit=50&sort=recent`)
1076
+ const padTokens = data.data || data.tokens || data || []
1077
+ if (Array.isArray(padTokens)) {
1078
+ for (const t of padTokens) {
1079
+ if (t.address) tokens.push({ address: t.address, name: t.symbol || t.name || '???' })
1080
+ }
1081
+ }
1082
+ } catch {}
1083
+
1084
+ // Batch check balances
1085
+ const results = []
1086
+ for (const t of tokens) {
1087
+ try {
1088
+ const [bal, decimals] = await Promise.all([
1089
+ readContract({ address: t.address, abi: ERC20_ABI, functionName: 'balanceOf', args: [address] }),
1090
+ readContract({ address: t.address, abi: ERC20_ABI, functionName: 'decimals', args: [] }),
1091
+ ])
1092
+ if (bal > 0n) {
1093
+ const formatted = parseFloat(viem.formatUnits(bal, decimals))
1094
+ results.push({ name: t.name, balance: formatted, address: t.address })
1095
+ }
1096
+ } catch {}
1097
+ }
1098
+
1099
+ if (results.length > 0) {
1100
+ for (const r of results) {
1101
+ const balStr = r.balance > 1000 ? r.balance.toLocaleString() : r.balance.toFixed(4)
1102
+ console.log(` ${r.name.padEnd(9)}${balStr}`)
1103
+ }
1104
+ }
1105
+
1106
+ console.log()
1107
+ }
1108
+
990
1109
  // ─── Wallet & network commands ───────────────────────────────────────
991
1110
 
992
1111
  async function cmdWalletNew() {
@@ -1089,6 +1208,7 @@ Pad (Launchpad):
1089
1208
  pad buy <token> <xrp_amount> Buy tokens with XRP
1090
1209
  pad sell <token> <amount|all> Sell tokens for XRP
1091
1210
  pad info <token> View token info and progress
1211
+ pad search <query> Search tokens by name or symbol
1092
1212
  pad tokens List recent tokens
1093
1213
 
1094
1214
  Swap (DEX):
@@ -1103,12 +1223,11 @@ Trade (Perps — testnet):
1103
1223
  trade position View your open positions
1104
1224
  trade price Get current XRP price
1105
1225
 
1106
- Wallet:
1226
+ Wallet & Account:
1107
1227
  wallet new Generate a new wallet
1108
-
1109
- Network:
1228
+ balance [address] Show XRP and token balances
1110
1229
  faucet [address] Get 25 testnet XRP
1111
- status Show network info, contracts, balance
1230
+ status Show network info, contracts
1112
1231
 
1113
1232
  Options:
1114
1233
  --mainnet Use mainnet (default: testnet)
@@ -1145,6 +1264,7 @@ async function main() {
1145
1264
  else if (sub === 'buy' || sub === 'b') await cmdPadBuy(args[2], args[3])
1146
1265
  else if (sub === 'sell' || sub === 's') await cmdPadSell(args[2], args[3])
1147
1266
  else if (sub === 'info' || sub === 'i') await cmdPadInfo(args[2])
1267
+ else if (sub === 'search' || sub === 'find') await cmdPadSearch(args[2])
1148
1268
  else if (sub === 'tokens' || sub === 'list') await cmdPadTokens()
1149
1269
  else { console.error(`Unknown: pad ${sub}. Try: launch, buy, sell, info, tokens`); process.exit(1) }
1150
1270
  } else if (cmd === 'swap') {
@@ -1161,6 +1281,8 @@ async function main() {
1161
1281
  } else if (cmd === 'wallet' || cmd === 'w') {
1162
1282
  if (!sub || sub === 'new') await cmdWalletNew()
1163
1283
  else { console.error(`Unknown: wallet ${sub}`); process.exit(1) }
1284
+ } else if (cmd === 'balance' || cmd === 'bal' || cmd === 'b') {
1285
+ await cmdBalance(args[1])
1164
1286
  } else if (cmd === 'faucet') {
1165
1287
  await cmdFaucet(args[1])
1166
1288
  } else if (cmd === 'status' || cmd === 's') {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blumefi",
3
- "version": "2.2.0",
3
+ "version": "2.3.0",
4
4
  "description": "BlumeFi CLI — DeFi reimagined for the agentic era. Trade, chat, and interact with the Blume ecosystem from the command line.",
5
5
  "main": "cli.js",
6
6
  "bin": {