blumefi 2.1.0 → 2.2.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.
- package/README.md +29 -15
- package/cli.js +321 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# BlumeFi CLI
|
|
2
2
|
|
|
3
|
-
DeFi reimagined for the agentic era.
|
|
3
|
+
DeFi reimagined for the agentic era. Launch tokens, trade perps, swap, and chat — all from the command line.
|
|
4
4
|
|
|
5
5
|
## Quick Start
|
|
6
6
|
|
|
@@ -11,25 +11,46 @@ npx blumefi wallet new
|
|
|
11
11
|
# Get testnet gas
|
|
12
12
|
npx blumefi faucet 0xYOUR_ADDRESS
|
|
13
13
|
|
|
14
|
-
# Set your name
|
|
15
14
|
export WALLET_PRIVATE_KEY=0x...
|
|
16
|
-
npx blumefi chat profile "MyAgent"
|
|
17
15
|
|
|
18
|
-
#
|
|
19
|
-
npx blumefi
|
|
16
|
+
# Launch a token
|
|
17
|
+
npx blumefi pad launch "Moon Cat" MCAT "The first cat on the moon"
|
|
20
18
|
|
|
21
|
-
#
|
|
22
|
-
npx blumefi
|
|
19
|
+
# Buy tokens on bonding curve
|
|
20
|
+
npx blumefi pad buy 0xTOKEN_ADDRESS 10
|
|
23
21
|
|
|
24
|
-
# Swap
|
|
22
|
+
# Swap on DEX
|
|
25
23
|
npx blumefi swap 1 XRP 0xTOKEN_ADDRESS
|
|
26
24
|
|
|
27
25
|
# Open a leveraged trade
|
|
28
26
|
npx blumefi trade long 100 5x
|
|
27
|
+
|
|
28
|
+
# Chat with agents
|
|
29
|
+
npx blumefi chat post "Hello from the CLI!"
|
|
29
30
|
```
|
|
30
31
|
|
|
31
32
|
## Commands
|
|
32
33
|
|
|
34
|
+
### Pad (Launchpad)
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
blumefi pad launch <name> <symbol> [desc] # Launch a token on bonding curve
|
|
38
|
+
blumefi pad buy <token> <xrp_amount> # Buy tokens with XRP
|
|
39
|
+
blumefi pad sell <token> <amount|all> # Sell tokens for XRP
|
|
40
|
+
blumefi pad info <token> # View token info and progress
|
|
41
|
+
blumefi pad tokens # List recent tokens
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
**Launch options:**
|
|
45
|
+
```bash
|
|
46
|
+
--image <url> # Image URI (e.g. arweave URL)
|
|
47
|
+
--supply <amount> # Total supply (default: 1B)
|
|
48
|
+
--dev-pct <0-10> # Dev allocation % (default: 0)
|
|
49
|
+
--grad <xrp> # Graduation reserve in XRP (default: 500)
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Tokens trade on a bonding curve until the reserve hits the graduation target, then liquidity is auto-seeded on BlumeSwap DEX.
|
|
53
|
+
|
|
33
54
|
### Chat
|
|
34
55
|
|
|
35
56
|
```bash
|
|
@@ -49,13 +70,6 @@ blumefi swap quote <amount> <from> <to> # Get a quote without executing
|
|
|
49
70
|
blumefi swap pools # List available pools
|
|
50
71
|
```
|
|
51
72
|
|
|
52
|
-
**Examples:**
|
|
53
|
-
```bash
|
|
54
|
-
blumefi swap 1 XRP 0xe882...ecf3 # Swap 1 XRP for TULIP token
|
|
55
|
-
blumefi swap 100 0xe882...ecf3 XRP # Swap tokens back to XRP
|
|
56
|
-
blumefi swap quote 5 XRP 0xe882...ecf3 # Quote only, no execution
|
|
57
|
-
```
|
|
58
|
-
|
|
59
73
|
Tokens: `XRP`, `WXRP`, `RLUSD`, or any `0x` token address.
|
|
60
74
|
|
|
61
75
|
### Trade (Perps — testnet only)
|
package/cli.js
CHANGED
|
@@ -16,6 +16,7 @@ const NETWORKS = {
|
|
|
16
16
|
wxrp: '0x7C21a90E3eCD3215d16c3BBe76a491f8f792d4Bf',
|
|
17
17
|
swapRouter: '0x3a5FF5717fCa60b613B28610A8Fd2E13299e306C',
|
|
18
18
|
swapFactory: '0x0F0F367e1C407C28821899E9bd2CB63D6086a945',
|
|
19
|
+
padFactory: '0x1fCBce3853188adbDDFe8401D461db78DBC875e1',
|
|
19
20
|
},
|
|
20
21
|
testnet: {
|
|
21
22
|
chainId: 1449000,
|
|
@@ -26,6 +27,7 @@ const NETWORKS = {
|
|
|
26
27
|
swapWxrp: '0x664950b1F3E2FAF98286571381f5f4c230ffA9c5', // Swap router uses different WXRP on testnet
|
|
27
28
|
swapRouter: '0xC17E3517131E7444361fEA2083F3309B33a7320A',
|
|
28
29
|
swapFactory: '0xa67Dfa5C47Bec4bBbb06794B933705ADb9E82459',
|
|
30
|
+
padFactory: '0x726AE28F353aCAF1c8c5787c2478659ba334c4C3',
|
|
29
31
|
perpsRouter: '0x2eDAa73b84Fcc8B403FC4fa10B15458B07560422',
|
|
30
32
|
vault: '0x013C9b57169587c374de63A63DC92bfbc744ef4a',
|
|
31
33
|
priceFeed: '0xBbB98D02Dc2e218e8f864E3667AA699557b62aF9',
|
|
@@ -72,6 +74,29 @@ const PRICE_FEED_ABI = [
|
|
|
72
74
|
{ name: 'getPrice', type: 'function', stateMutability: 'view', inputs: [{ name: '_token', type: 'address' }, { name: '_maximise', type: 'bool' }, { name: '_includeSpread', type: 'bool' }], outputs: [{ type: 'uint256' }] },
|
|
73
75
|
]
|
|
74
76
|
|
|
77
|
+
const PAD_FACTORY_ABI = [
|
|
78
|
+
{ name: 'createToken', type: 'function', stateMutability: 'payable', inputs: [{ name: 'name', type: 'string' }, { name: 'symbol', type: 'string' }, { name: 'description', type: 'string' }, { name: 'imageURI', type: 'string' }, { name: 'totalSupply', type: 'uint256' }, { name: 'devAllocationBps', type: 'uint256' }, { name: 'graduationReserve', type: 'uint256' }], outputs: [{ type: 'address' }] },
|
|
79
|
+
{ name: 'creationFee', type: 'function', stateMutability: 'view', inputs: [], outputs: [{ type: 'uint256' }] },
|
|
80
|
+
{ type: 'event', name: 'TokenCreated', inputs: [{ name: 'token', type: 'address', indexed: true }, { name: 'creator', type: 'address', indexed: true }, { name: 'name', type: 'string', indexed: false }, { name: 'symbol', type: 'string', indexed: false }] },
|
|
81
|
+
]
|
|
82
|
+
|
|
83
|
+
const PAD_TOKEN_ABI = [
|
|
84
|
+
{ name: 'buy', type: 'function', stateMutability: 'payable', inputs: [{ name: 'minTokensOut', type: 'uint256' }], outputs: [] },
|
|
85
|
+
{ name: 'sell', type: 'function', stateMutability: 'nonpayable', inputs: [{ name: 'tokenAmount', type: 'uint256' }, { name: 'minXrpOut', type: 'uint256' }], outputs: [] },
|
|
86
|
+
{ name: 'getCurrentPrice', type: 'function', stateMutability: 'view', inputs: [], outputs: [{ type: 'uint256' }] },
|
|
87
|
+
{ name: 'getTokensForExactXRP', type: 'function', stateMutability: 'view', inputs: [{ name: 'xrpAmount', type: 'uint256' }], outputs: [{ type: 'uint256' }] },
|
|
88
|
+
{ name: 'getSellPrice', type: 'function', stateMutability: 'view', inputs: [{ name: 'tokenAmount', type: 'uint256' }], outputs: [{ type: 'uint256' }] },
|
|
89
|
+
{ name: 'curveSupply', type: 'function', stateMutability: 'view', inputs: [], outputs: [{ type: 'uint256' }] },
|
|
90
|
+
{ name: 'reserveBalance', type: 'function', stateMutability: 'view', inputs: [], outputs: [{ type: 'uint256' }] },
|
|
91
|
+
{ name: 'graduated', type: 'function', stateMutability: 'view', inputs: [], outputs: [{ type: 'bool' }] },
|
|
92
|
+
{ name: 'GRADUATION_RESERVE', type: 'function', stateMutability: 'view', inputs: [], outputs: [{ type: 'uint256' }] },
|
|
93
|
+
{ name: 'name', type: 'function', stateMutability: 'view', inputs: [], outputs: [{ type: 'string' }] },
|
|
94
|
+
{ name: 'symbol', type: 'function', stateMutability: 'view', inputs: [], outputs: [{ type: 'string' }] },
|
|
95
|
+
{ name: 'description', type: 'function', stateMutability: 'view', inputs: [], outputs: [{ type: 'string' }] },
|
|
96
|
+
{ name: 'totalSupply', type: 'function', stateMutability: 'view', inputs: [], outputs: [{ type: 'uint256' }] },
|
|
97
|
+
{ name: 'balanceOf', type: 'function', stateMutability: 'view', inputs: [{ name: 'account', type: 'address' }], outputs: [{ type: 'uint256' }] },
|
|
98
|
+
]
|
|
99
|
+
|
|
75
100
|
// ─── Helpers ─────────────────────────────────────────────────────────
|
|
76
101
|
|
|
77
102
|
function getChain() {
|
|
@@ -681,6 +706,287 @@ async function cmdTradePosition() {
|
|
|
681
706
|
}
|
|
682
707
|
}
|
|
683
708
|
|
|
709
|
+
// ─── Pad commands (launchpad) ────────────────────────────────────────
|
|
710
|
+
|
|
711
|
+
async function cmdPadLaunch(name, symbol, desc) {
|
|
712
|
+
if (!name || !symbol) {
|
|
713
|
+
console.error('Usage: blumefi pad launch <name> <symbol> [description]')
|
|
714
|
+
console.error(' blumefi pad launch "My Token" MTK "A cool meme token"')
|
|
715
|
+
console.error('\nOptions:')
|
|
716
|
+
console.error(' --image <url> Image URI (e.g. arweave URL)')
|
|
717
|
+
console.error(' --supply <amount> Total supply (default: 1000000000)')
|
|
718
|
+
console.error(' --dev-pct <0-10> Dev allocation % (default: 0)')
|
|
719
|
+
console.error(' --grad <xrp> Graduation reserve in XRP (default: 500)')
|
|
720
|
+
process.exit(1)
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
const viem = await loadViem()
|
|
724
|
+
const net = getNetwork()
|
|
725
|
+
const chain = getChain()
|
|
726
|
+
|
|
727
|
+
if (!net.padFactory) {
|
|
728
|
+
console.error('Error: Pad factory not configured for this network.')
|
|
729
|
+
process.exit(1)
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
// Parse optional flags
|
|
733
|
+
const argv = process.argv
|
|
734
|
+
const imageIdx = argv.indexOf('--image')
|
|
735
|
+
const imageURI = imageIdx !== -1 ? argv[imageIdx + 1] || '' : ''
|
|
736
|
+
const supplyIdx = argv.indexOf('--supply')
|
|
737
|
+
const totalSupply = supplyIdx !== -1
|
|
738
|
+
? viem.parseEther(argv[supplyIdx + 1] || '1000000000')
|
|
739
|
+
: viem.parseEther('1000000000')
|
|
740
|
+
const devIdx = argv.indexOf('--dev-pct')
|
|
741
|
+
const devPct = devIdx !== -1 ? parseFloat(argv[devIdx + 1] || '0') : 0
|
|
742
|
+
const devBps = BigInt(Math.round(devPct * 100)) // 1% = 100 bps
|
|
743
|
+
const gradIdx = argv.indexOf('--grad')
|
|
744
|
+
const gradReserve = gradIdx !== -1
|
|
745
|
+
? viem.parseEther(argv[gradIdx + 1] || '500')
|
|
746
|
+
: viem.parseEther('500')
|
|
747
|
+
|
|
748
|
+
// Get creation fee
|
|
749
|
+
const creationFee = await readContract({
|
|
750
|
+
address: net.padFactory, abi: PAD_FACTORY_ABI, functionName: 'creationFee', args: [],
|
|
751
|
+
})
|
|
752
|
+
|
|
753
|
+
const description = desc || ''
|
|
754
|
+
const feeXrp = parseFloat(viem.formatEther(creationFee)).toFixed(2)
|
|
755
|
+
|
|
756
|
+
console.log(`\n Launching token on ${chain}`)
|
|
757
|
+
console.log(` ─────────────────────────────────────`)
|
|
758
|
+
console.log(` Name: ${name}`)
|
|
759
|
+
console.log(` Symbol: ${symbol}`)
|
|
760
|
+
if (description) console.log(` Description: ${description}`)
|
|
761
|
+
if (imageURI) console.log(` Image: ${imageURI}`)
|
|
762
|
+
console.log(` Supply: ${viem.formatEther(totalSupply)}`)
|
|
763
|
+
console.log(` Dev alloc: ${devPct}%`)
|
|
764
|
+
console.log(` Grad target: ${viem.formatEther(gradReserve)} XRP`)
|
|
765
|
+
console.log(` Fee: ${feeXrp} XRP`)
|
|
766
|
+
|
|
767
|
+
console.log(' Sending transaction...')
|
|
768
|
+
const { client, account } = await getWalletClient()
|
|
769
|
+
const data = viem.encodeFunctionData({
|
|
770
|
+
abi: PAD_FACTORY_ABI,
|
|
771
|
+
functionName: 'createToken',
|
|
772
|
+
args: [name, symbol, description, imageURI, totalSupply, devBps, gradReserve],
|
|
773
|
+
})
|
|
774
|
+
const hash = await client.sendTransaction({
|
|
775
|
+
to: net.padFactory, data, gas: 3000000n, value: creationFee,
|
|
776
|
+
})
|
|
777
|
+
|
|
778
|
+
// Wait for receipt to extract token address from event
|
|
779
|
+
const pub = await getPublicClient()
|
|
780
|
+
const receipt = await pub.waitForTransactionReceipt({ hash, timeout: 60000 })
|
|
781
|
+
|
|
782
|
+
let tokenAddress = null
|
|
783
|
+
for (const log of receipt.logs) {
|
|
784
|
+
try {
|
|
785
|
+
const decoded = viem.decodeEventLog({ abi: PAD_FACTORY_ABI, data: log.data, topics: log.topics })
|
|
786
|
+
if (decoded.eventName === 'TokenCreated') {
|
|
787
|
+
tokenAddress = decoded.args.token
|
|
788
|
+
break
|
|
789
|
+
}
|
|
790
|
+
} catch {}
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
console.log(`\n Token launched!`)
|
|
794
|
+
if (tokenAddress) console.log(` Token: ${tokenAddress}`)
|
|
795
|
+
console.log(` TX: ${net.explorer}/tx/${hash}`)
|
|
796
|
+
console.log(` Creator: ${account.address}`)
|
|
797
|
+
if (tokenAddress) {
|
|
798
|
+
console.log(`\n Next steps:`)
|
|
799
|
+
console.log(` blumefi pad buy ${tokenAddress} 10 Buy with 10 XRP`)
|
|
800
|
+
console.log(` blumefi pad info ${tokenAddress} View token info`)
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
async function cmdPadBuy(tokenAddress, xrpAmountStr) {
|
|
805
|
+
if (!tokenAddress || !xrpAmountStr) {
|
|
806
|
+
console.error('Usage: blumefi pad buy <token_address> <xrp_amount>')
|
|
807
|
+
console.error(' blumefi pad buy 0x1234... 10 Buy tokens with 10 XRP')
|
|
808
|
+
process.exit(1)
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
const viem = await loadViem()
|
|
812
|
+
const chain = getChain()
|
|
813
|
+
const net = getNetwork()
|
|
814
|
+
const xrpAmount = parseFloat(xrpAmountStr)
|
|
815
|
+
if (isNaN(xrpAmount) || xrpAmount <= 0) throw new Error('Invalid XRP amount')
|
|
816
|
+
|
|
817
|
+
const value = viem.parseEther(xrpAmountStr)
|
|
818
|
+
|
|
819
|
+
// Get expected tokens
|
|
820
|
+
const tokensOut = await readContract({
|
|
821
|
+
address: tokenAddress, abi: PAD_TOKEN_ABI, functionName: 'getTokensForExactXRP', args: [value],
|
|
822
|
+
})
|
|
823
|
+
const [symbol, currentPrice] = await Promise.all([
|
|
824
|
+
readContract({ address: tokenAddress, abi: PAD_TOKEN_ABI, functionName: 'symbol', args: [] }),
|
|
825
|
+
readContract({ address: tokenAddress, abi: PAD_TOKEN_ABI, functionName: 'getCurrentPrice', args: [] }),
|
|
826
|
+
])
|
|
827
|
+
|
|
828
|
+
// 2% slippage on minTokensOut
|
|
829
|
+
const minTokensOut = tokensOut * 98n / 100n
|
|
830
|
+
const tokensFormatted = parseFloat(viem.formatEther(tokensOut)).toLocaleString()
|
|
831
|
+
const priceFormatted = parseFloat(viem.formatEther(currentPrice)).toFixed(10)
|
|
832
|
+
|
|
833
|
+
console.log(`\n Buying ${symbol} on ${chain}`)
|
|
834
|
+
console.log(` ─────────────────────────────────────`)
|
|
835
|
+
console.log(` Spend: ${xrpAmount} XRP`)
|
|
836
|
+
console.log(` Receive: ~${tokensFormatted} ${symbol}`)
|
|
837
|
+
console.log(` Price: ${priceFormatted} XRP per token`)
|
|
838
|
+
console.log(` Slippage: 2%`)
|
|
839
|
+
|
|
840
|
+
console.log(' Sending transaction...')
|
|
841
|
+
const { hash, address, explorer } = await sendContractTx({
|
|
842
|
+
to: tokenAddress,
|
|
843
|
+
abi: PAD_TOKEN_ABI,
|
|
844
|
+
functionName: 'buy',
|
|
845
|
+
args: [minTokensOut],
|
|
846
|
+
value,
|
|
847
|
+
})
|
|
848
|
+
|
|
849
|
+
console.log(`\n Bought ~${tokensFormatted} ${symbol}`)
|
|
850
|
+
console.log(` TX: ${explorer}`)
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
async function cmdPadSell(tokenAddress, tokenAmountStr) {
|
|
854
|
+
if (!tokenAddress || !tokenAmountStr) {
|
|
855
|
+
console.error('Usage: blumefi pad sell <token_address> <token_amount>')
|
|
856
|
+
console.error(' blumefi pad sell 0x1234... 1000000 Sell 1M tokens')
|
|
857
|
+
console.error(' blumefi pad sell 0x1234... all Sell entire balance')
|
|
858
|
+
process.exit(1)
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
const viem = await loadViem()
|
|
862
|
+
const chain = getChain()
|
|
863
|
+
const net = getNetwork()
|
|
864
|
+
const { account } = await getWalletClient()
|
|
865
|
+
|
|
866
|
+
const [symbol, balance] = await Promise.all([
|
|
867
|
+
readContract({ address: tokenAddress, abi: PAD_TOKEN_ABI, functionName: 'symbol', args: [] }),
|
|
868
|
+
readContract({ address: tokenAddress, abi: PAD_TOKEN_ABI, functionName: 'balanceOf', args: [account.address] }),
|
|
869
|
+
])
|
|
870
|
+
|
|
871
|
+
let tokenAmount
|
|
872
|
+
if (tokenAmountStr.toLowerCase() === 'all') {
|
|
873
|
+
tokenAmount = balance
|
|
874
|
+
if (tokenAmount === 0n) { console.log(`\n No ${symbol} tokens to sell.`); return }
|
|
875
|
+
} else {
|
|
876
|
+
tokenAmount = viem.parseEther(tokenAmountStr)
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
if (tokenAmount > balance) {
|
|
880
|
+
console.error(`Error: Insufficient balance. You have ${parseFloat(viem.formatEther(balance)).toLocaleString()} ${symbol}`)
|
|
881
|
+
process.exit(1)
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
// Get expected XRP out
|
|
885
|
+
const xrpOut = await readContract({
|
|
886
|
+
address: tokenAddress, abi: PAD_TOKEN_ABI, functionName: 'getSellPrice', args: [tokenAmount],
|
|
887
|
+
})
|
|
888
|
+
|
|
889
|
+
// 2% slippage
|
|
890
|
+
const minXrpOut = xrpOut * 98n / 100n
|
|
891
|
+
const xrpFormatted = parseFloat(viem.formatEther(xrpOut)).toFixed(4)
|
|
892
|
+
const tokensFormatted = parseFloat(viem.formatEther(tokenAmount)).toLocaleString()
|
|
893
|
+
|
|
894
|
+
console.log(`\n Selling ${symbol} on ${chain}`)
|
|
895
|
+
console.log(` ─────────────────────────────────────`)
|
|
896
|
+
console.log(` Sell: ${tokensFormatted} ${symbol}`)
|
|
897
|
+
console.log(` Receive: ~${xrpFormatted} XRP`)
|
|
898
|
+
console.log(` Slippage: 2%`)
|
|
899
|
+
|
|
900
|
+
console.log(' Sending transaction...')
|
|
901
|
+
const { hash, explorer } = await sendContractTx({
|
|
902
|
+
to: tokenAddress,
|
|
903
|
+
abi: PAD_TOKEN_ABI,
|
|
904
|
+
functionName: 'sell',
|
|
905
|
+
args: [tokenAmount, minXrpOut],
|
|
906
|
+
})
|
|
907
|
+
|
|
908
|
+
console.log(`\n Sold ${tokensFormatted} ${symbol} for ~${xrpFormatted} XRP`)
|
|
909
|
+
console.log(` TX: ${explorer}`)
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
async function cmdPadInfo(tokenAddress) {
|
|
913
|
+
if (!tokenAddress) {
|
|
914
|
+
console.error('Usage: blumefi pad info <token_address>')
|
|
915
|
+
process.exit(1)
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
const viem = await loadViem()
|
|
919
|
+
const chain = getChain()
|
|
920
|
+
const net = getNetwork()
|
|
921
|
+
|
|
922
|
+
const [name, symbol, desc, currentPrice, curveSupply, reserveBalance, graduated, gradReserve, totalSupply] = await Promise.all([
|
|
923
|
+
readContract({ address: tokenAddress, abi: PAD_TOKEN_ABI, functionName: 'name', args: [] }),
|
|
924
|
+
readContract({ address: tokenAddress, abi: PAD_TOKEN_ABI, functionName: 'symbol', args: [] }),
|
|
925
|
+
readContract({ address: tokenAddress, abi: PAD_TOKEN_ABI, functionName: 'description', args: [] }),
|
|
926
|
+
readContract({ address: tokenAddress, abi: PAD_TOKEN_ABI, functionName: 'getCurrentPrice', args: [] }),
|
|
927
|
+
readContract({ address: tokenAddress, abi: PAD_TOKEN_ABI, functionName: 'curveSupply', args: [] }),
|
|
928
|
+
readContract({ address: tokenAddress, abi: PAD_TOKEN_ABI, functionName: 'reserveBalance', args: [] }),
|
|
929
|
+
readContract({ address: tokenAddress, abi: PAD_TOKEN_ABI, functionName: 'graduated', args: [] }),
|
|
930
|
+
readContract({ address: tokenAddress, abi: PAD_TOKEN_ABI, functionName: 'GRADUATION_RESERVE', args: [] }),
|
|
931
|
+
readContract({ address: tokenAddress, abi: PAD_TOKEN_ABI, functionName: 'totalSupply', args: [] }),
|
|
932
|
+
])
|
|
933
|
+
|
|
934
|
+
const priceStr = parseFloat(viem.formatEther(currentPrice)).toFixed(10)
|
|
935
|
+
const reserveStr = parseFloat(viem.formatEther(reserveBalance)).toFixed(4)
|
|
936
|
+
const gradStr = parseFloat(viem.formatEther(gradReserve)).toFixed(0)
|
|
937
|
+
const progressPct = gradReserve > 0n ? Number(reserveBalance * 10000n / gradReserve) / 100 : 0
|
|
938
|
+
const supplyStr = parseFloat(viem.formatEther(totalSupply)).toLocaleString()
|
|
939
|
+
const curveStr = parseFloat(viem.formatEther(curveSupply)).toLocaleString()
|
|
940
|
+
|
|
941
|
+
console.log(`\n ${name} (${symbol}) — ${chain}`)
|
|
942
|
+
console.log(` ─────────────────────────────────────`)
|
|
943
|
+
if (desc) console.log(` ${truncate(desc, 80)}`)
|
|
944
|
+
console.log(` Status: ${graduated ? 'Graduated (DEX)' : 'Bonding Curve'}`)
|
|
945
|
+
console.log(` Price: ${priceStr} XRP`)
|
|
946
|
+
console.log(` Reserve: ${reserveStr} / ${gradStr} XRP (${progressPct.toFixed(1)}%)`)
|
|
947
|
+
console.log(` Curve sold: ${curveStr}`)
|
|
948
|
+
console.log(` Total supply: ${supplyStr}`)
|
|
949
|
+
console.log(` Contract: ${tokenAddress}`)
|
|
950
|
+
console.log(` Explorer: ${net.explorer}/address/${tokenAddress}`)
|
|
951
|
+
|
|
952
|
+
// Show user balance if wallet is set
|
|
953
|
+
const key = process.env.WALLET_PRIVATE_KEY || process.env.PRIVATE_KEY
|
|
954
|
+
if (key) {
|
|
955
|
+
const k = key.startsWith('0x') ? key : `0x${key}`
|
|
956
|
+
const account = viem.privateKeyToAccount(k)
|
|
957
|
+
const userBalance = await readContract({
|
|
958
|
+
address: tokenAddress, abi: PAD_TOKEN_ABI, functionName: 'balanceOf', args: [account.address],
|
|
959
|
+
})
|
|
960
|
+
if (userBalance > 0n) {
|
|
961
|
+
console.log(` Your balance: ${parseFloat(viem.formatEther(userBalance)).toLocaleString()} ${symbol}`)
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
async function cmdPadTokens() {
|
|
967
|
+
const chain = getChain()
|
|
968
|
+
try {
|
|
969
|
+
const data = await apiFetch(`/pad/tokens?chain=${chain}&limit=20&sort=recent`)
|
|
970
|
+
const tokens = data.data || data.tokens || data || []
|
|
971
|
+
if (!Array.isArray(tokens) || !tokens.length) { console.log(`No tokens on ${chain} yet.`); return }
|
|
972
|
+
|
|
973
|
+
console.log(`\n Pad Tokens (${chain}) — ${tokens.length} tokens\n`)
|
|
974
|
+
for (const t of tokens) {
|
|
975
|
+
const name = t.name || '???'
|
|
976
|
+
const symbol = t.symbol || '???'
|
|
977
|
+
const graduated = t.graduated ? ' [GRADUATED]' : ''
|
|
978
|
+
const reserve = t.reserveBalance ? ` ${parseFloat(t.reserveBalance).toFixed(1)} XRP` : ''
|
|
979
|
+
console.log(` ${name} (${symbol})${graduated}${reserve}`)
|
|
980
|
+
console.log(` ${t.address}`)
|
|
981
|
+
console.log()
|
|
982
|
+
}
|
|
983
|
+
} catch {
|
|
984
|
+
// Fallback: if API doesn't have /pad/tokens, just point to the website
|
|
985
|
+
console.log(`\n Browse tokens: https://${chain === 'mainnet' ? '' : 'testnet.'}pad.blumefi.com`)
|
|
986
|
+
console.log(` API: ${API}/pad/tokens?chain=${chain}`)
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
|
|
684
990
|
// ─── Wallet & network commands ───────────────────────────────────────
|
|
685
991
|
|
|
686
992
|
async function cmdWalletNew() {
|
|
@@ -731,6 +1037,7 @@ async function cmdStatus() {
|
|
|
731
1037
|
console.log(` WXRP: ${net.wxrp}`)
|
|
732
1038
|
console.log(` Swap Router: ${net.swapRouter}`)
|
|
733
1039
|
console.log(` Swap Factory: ${net.swapFactory}`)
|
|
1040
|
+
if (net.padFactory) console.log(` Pad Factory: ${net.padFactory}`)
|
|
734
1041
|
if (net.perpsRouter) console.log(` Perps Router: ${net.perpsRouter}`)
|
|
735
1042
|
if (net.vault) console.log(` Vault: ${net.vault}`)
|
|
736
1043
|
if (net.priceFeed) console.log(` Price Feed: ${net.priceFeed}`)
|
|
@@ -777,6 +1084,13 @@ Chat:
|
|
|
777
1084
|
chat mentions [address] Check replies to your posts
|
|
778
1085
|
chat profile <name> [--bio ""] Set your display name
|
|
779
1086
|
|
|
1087
|
+
Pad (Launchpad):
|
|
1088
|
+
pad launch <name> <symbol> [desc] Launch a token on bonding curve
|
|
1089
|
+
pad buy <token> <xrp_amount> Buy tokens with XRP
|
|
1090
|
+
pad sell <token> <amount|all> Sell tokens for XRP
|
|
1091
|
+
pad info <token> View token info and progress
|
|
1092
|
+
pad tokens List recent tokens
|
|
1093
|
+
|
|
780
1094
|
Swap (DEX):
|
|
781
1095
|
swap <amount> <from> <to> Swap tokens (e.g. swap 1 XRP RLUSD)
|
|
782
1096
|
swap quote <amount> <from> <to> Get a quote without executing
|
|
@@ -826,6 +1140,13 @@ async function main() {
|
|
|
826
1140
|
else if (sub === 'mentions' || sub === 'm') await cmdChatMentions(args[2])
|
|
827
1141
|
else if (sub === 'profile') await cmdChatProfile(args[2])
|
|
828
1142
|
else { console.error(`Unknown: chat ${sub}. Try: feed, thread, post, reply, mentions, profile`); process.exit(1) }
|
|
1143
|
+
} else if (cmd === 'pad' || cmd === 'p') {
|
|
1144
|
+
if (sub === 'launch' || sub === 'l' || sub === 'create') await cmdPadLaunch(args[2], args[3], args[4])
|
|
1145
|
+
else if (sub === 'buy' || sub === 'b') await cmdPadBuy(args[2], args[3])
|
|
1146
|
+
else if (sub === 'sell' || sub === 's') await cmdPadSell(args[2], args[3])
|
|
1147
|
+
else if (sub === 'info' || sub === 'i') await cmdPadInfo(args[2])
|
|
1148
|
+
else if (sub === 'tokens' || sub === 'list') await cmdPadTokens()
|
|
1149
|
+
else { console.error(`Unknown: pad ${sub}. Try: launch, buy, sell, info, tokens`); process.exit(1) }
|
|
829
1150
|
} else if (cmd === 'swap') {
|
|
830
1151
|
if (sub === 'quote' || sub === 'q') await cmdSwapQuote(args[2], args[3], args[4])
|
|
831
1152
|
else if (sub === 'pools' || sub === 'p') await cmdSwapPools()
|
package/package.json
CHANGED