@megatao/sdk 1.1.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/.env.example +37 -0
- package/CHANGELOG.md +19 -0
- package/README.md +199 -0
- package/bin/alf +4 -0
- package/cli/README.md +198 -0
- package/cli/TEST_MANUAL.md +577 -0
- package/cli/commands/account.ts +545 -0
- package/cli/commands/funding.ts +481 -0
- package/cli/commands/liquidation.ts +523 -0
- package/cli/commands/market.ts +590 -0
- package/cli/commands/orders.ts +395 -0
- package/cli/commands/position.ts +1085 -0
- package/cli/commands/shared/positionUtils.ts +239 -0
- package/cli/commands/trading.ts +483 -0
- package/cli/commands/utils.ts +281 -0
- package/cli/commands/vault.ts +522 -0
- package/cli/index.ts +169 -0
- package/cli/interactive.ts +530 -0
- package/cli/utils/client.ts +457 -0
- package/cli/utils/config.ts +226 -0
- package/cli/utils/display.ts +258 -0
- package/cli/utils/index.ts +10 -0
- package/cli/utils/prompts.ts +364 -0
- package/config.example.json +23 -0
- package/dist/AlphaFuturesClient.d.ts +36 -0
- package/dist/AlphaFuturesClient.d.ts.map +1 -0
- package/dist/AlphaFuturesClient.js +116 -0
- package/dist/AlphaFuturesClient.js.map +1 -0
- package/dist/abi/Alpha.json +5987 -0
- package/dist/abi/abis.d.ts +319 -0
- package/dist/abi/abis.d.ts.map +1 -0
- package/dist/abi/abis.js +128 -0
- package/dist/abi/abis.js.map +1 -0
- package/dist/abi/index.d.ts +11 -0
- package/dist/abi/index.d.ts.map +1 -0
- package/dist/abi/index.js +15 -0
- package/dist/abi/index.js.map +1 -0
- package/dist/config/contracts.config.d.ts +70 -0
- package/dist/config/contracts.config.d.ts.map +1 -0
- package/dist/config/contracts.config.js +137 -0
- package/dist/config/contracts.config.js.map +1 -0
- package/dist/config/environments/alpha.config.d.ts +17 -0
- package/dist/config/environments/alpha.config.d.ts.map +1 -0
- package/dist/config/environments/alpha.config.js +140 -0
- package/dist/config/environments/alpha.config.js.map +1 -0
- package/dist/config/environments/beta.config.d.ts +16 -0
- package/dist/config/environments/beta.config.d.ts.map +1 -0
- package/dist/config/environments/beta.config.js +131 -0
- package/dist/config/environments/beta.config.js.map +1 -0
- package/dist/config/environments/dev.config.d.ts +13 -0
- package/dist/config/environments/dev.config.d.ts.map +1 -0
- package/dist/config/environments/dev.config.js +123 -0
- package/dist/config/environments/dev.config.js.map +1 -0
- package/dist/config/environments/index.d.ts +48 -0
- package/dist/config/environments/index.d.ts.map +1 -0
- package/dist/config/environments/index.js +81 -0
- package/dist/config/environments/index.js.map +1 -0
- package/dist/config/environments/localhost.config.d.ts +16 -0
- package/dist/config/environments/localhost.config.d.ts.map +1 -0
- package/dist/config/environments/localhost.config.js +152 -0
- package/dist/config/environments/localhost.config.js.map +1 -0
- package/dist/config/environments/prod.config.d.ts +20 -0
- package/dist/config/environments/prod.config.d.ts.map +1 -0
- package/dist/config/environments/prod.config.js +143 -0
- package/dist/config/environments/prod.config.js.map +1 -0
- package/dist/config/index.d.ts +7 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +41 -0
- package/dist/config/index.js.map +1 -0
- package/dist/constants/assets.d.ts +76 -0
- package/dist/constants/assets.d.ts.map +1 -0
- package/dist/constants/assets.js +277 -0
- package/dist/constants/assets.js.map +1 -0
- package/dist/constants/contracts.d.ts +41 -0
- package/dist/constants/contracts.d.ts.map +1 -0
- package/dist/constants/contracts.js +57 -0
- package/dist/constants/contracts.js.map +1 -0
- package/dist/constants/index.d.ts +36 -0
- package/dist/constants/index.d.ts.map +1 -0
- package/dist/constants/index.js +75 -0
- package/dist/constants/index.js.map +1 -0
- package/dist/constants/networks.d.ts +32 -0
- package/dist/constants/networks.d.ts.map +1 -0
- package/dist/constants/networks.js +174 -0
- package/dist/constants/networks.js.map +1 -0
- package/dist/contracts/index.d.ts +5 -0
- package/dist/contracts/index.d.ts.map +1 -0
- package/dist/contracts/index.js +21 -0
- package/dist/contracts/index.js.map +1 -0
- package/dist/contracts/viem/AlphaViem.d.ts +518 -0
- package/dist/contracts/viem/AlphaViem.d.ts.map +1 -0
- package/dist/contracts/viem/AlphaViem.js +1287 -0
- package/dist/contracts/viem/AlphaViem.js.map +1 -0
- package/dist/contracts/viem/PriceOracleViem.d.ts +71 -0
- package/dist/contracts/viem/PriceOracleViem.d.ts.map +1 -0
- package/dist/contracts/viem/PriceOracleViem.js +212 -0
- package/dist/contracts/viem/PriceOracleViem.js.map +1 -0
- package/dist/contracts/viem/index.d.ts +9 -0
- package/dist/contracts/viem/index.d.ts.map +1 -0
- package/dist/contracts/viem/index.js +17 -0
- package/dist/contracts/viem/index.js.map +1 -0
- package/dist/errors/index.d.ts +44 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/index.js +83 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +60 -0
- package/dist/index.js.map +1 -0
- package/dist/types/alpha.d.ts +299 -0
- package/dist/types/alpha.d.ts.map +1 -0
- package/dist/types/alpha.js +6 -0
- package/dist/types/alpha.js.map +1 -0
- package/dist/types/client.d.ts +24 -0
- package/dist/types/client.d.ts.map +1 -0
- package/dist/types/client.js +13 -0
- package/dist/types/client.js.map +1 -0
- package/dist/types/contracts.d.ts +48 -0
- package/dist/types/contracts.d.ts.map +1 -0
- package/dist/types/contracts.js +6 -0
- package/dist/types/contracts.js.map +1 -0
- package/dist/types/funding.d.ts +27 -0
- package/dist/types/funding.d.ts.map +1 -0
- package/dist/types/funding.js +6 -0
- package/dist/types/funding.js.map +1 -0
- package/dist/types/index.d.ts +92 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +47 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/liquidation.d.ts +20 -0
- package/dist/types/liquidation.d.ts.map +1 -0
- package/dist/types/liquidation.js +6 -0
- package/dist/types/liquidation.js.map +1 -0
- package/dist/types/margin.d.ts +29 -0
- package/dist/types/margin.d.ts.map +1 -0
- package/dist/types/margin.js +6 -0
- package/dist/types/margin.js.map +1 -0
- package/dist/types/oracle.d.ts +21 -0
- package/dist/types/oracle.d.ts.map +1 -0
- package/dist/types/oracle.js +6 -0
- package/dist/types/oracle.js.map +1 -0
- package/dist/types/positions.d.ts +43 -0
- package/dist/types/positions.d.ts.map +1 -0
- package/dist/types/positions.js +13 -0
- package/dist/types/positions.js.map +1 -0
- package/dist/utils/calculations.d.ts +84 -0
- package/dist/utils/calculations.d.ts.map +1 -0
- package/dist/utils/calculations.js +155 -0
- package/dist/utils/calculations.js.map +1 -0
- package/dist/utils/errors.d.ts +24 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +129 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/events.d.ts +40 -0
- package/dist/utils/events.d.ts.map +1 -0
- package/dist/utils/events.js +73 -0
- package/dist/utils/events.js.map +1 -0
- package/dist/utils/format.d.ts +40 -0
- package/dist/utils/format.d.ts.map +1 -0
- package/dist/utils/format.js +86 -0
- package/dist/utils/format.js.map +1 -0
- package/dist/utils/index.d.ts +10 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +26 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/network.d.ts +52 -0
- package/dist/utils/network.d.ts.map +1 -0
- package/dist/utils/network.js +192 -0
- package/dist/utils/network.js.map +1 -0
- package/dist/utils/positionCalculations.d.ts +145 -0
- package/dist/utils/positionCalculations.d.ts.map +1 -0
- package/dist/utils/positionCalculations.js +278 -0
- package/dist/utils/positionCalculations.js.map +1 -0
- package/dist/utils/validation.d.ts +28 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/utils/validation.js +68 -0
- package/dist/utils/validation.js.map +1 -0
- package/docs/README.md +40 -0
- package/docs/api/API.md +831 -0
- package/docs/guides/GETTING_STARTED.md +316 -0
- package/docs/guides/TRADING_GUIDE.md +677 -0
- package/docs/integration/INTEGRATION_GUIDE.md +1679 -0
- package/docs/integration/VIEM_INTEGRATION.md +294 -0
- package/docs/reference/CLI_QUICK_REFERENCE.md +197 -0
- package/docs/reference/TROUBLESHOOTING.md +922 -0
- package/package.json +113 -0
- package/src/AlphaFuturesClient.ts +158 -0
- package/src/abi/.gitkeep +1 -0
- package/src/abi/Alpha.json +5987 -0
- package/src/abi/README.md +99 -0
- package/src/abi/abis.ts +131 -0
- package/src/abi/index.ts +13 -0
- package/src/config/contracts.config.ts +186 -0
- package/src/config/environments/alpha.config.ts +139 -0
- package/src/config/environments/beta.config.ts +130 -0
- package/src/config/environments/dev.config.ts +122 -0
- package/src/config/environments/index.ts +87 -0
- package/src/config/environments/localhost.config.ts +153 -0
- package/src/config/environments/prod.config.ts +142 -0
- package/src/config/index.ts +29 -0
- package/src/constants/assets.ts +299 -0
- package/src/constants/contracts.ts +64 -0
- package/src/constants/index.ts +69 -0
- package/src/constants/networks.ts +182 -0
- package/src/contracts/index.ts +5 -0
- package/src/contracts/viem/AlphaViem.ts +1615 -0
- package/src/contracts/viem/PriceOracleViem.ts +272 -0
- package/src/contracts/viem/index.ts +11 -0
- package/src/errors/index.ts +87 -0
- package/src/index.ts +59 -0
- package/src/types/VIEM_TYPES_README.md +70 -0
- package/src/types/alpha.ts +358 -0
- package/src/types/client.ts +27 -0
- package/src/types/contracts.ts +74 -0
- package/src/types/funding.ts +31 -0
- package/src/types/index.ts +108 -0
- package/src/types/liquidation.ts +23 -0
- package/src/types/margin.ts +34 -0
- package/src/types/oracle.ts +24 -0
- package/src/types/positions.ts +48 -0
- package/src/utils/calculations.ts +175 -0
- package/src/utils/errors.ts +147 -0
- package/src/utils/events.ts +98 -0
- package/src/utils/format.ts +84 -0
- package/src/utils/index.ts +10 -0
- package/src/utils/network.ts +212 -0
- package/src/utils/positionCalculations.ts +317 -0
- package/src/utils/validation.ts +76 -0
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Display Utilities
|
|
3
|
+
*
|
|
4
|
+
* Helper functions for formatting and displaying data in the CLI
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import chalk from 'chalk';
|
|
8
|
+
import Table from 'cli-table3';
|
|
9
|
+
import { formatUSD, formatTAO, formatPercentage } from '../../src/utils';
|
|
10
|
+
|
|
11
|
+
// Asset name mapping for subnet market addresses
|
|
12
|
+
const ASSET_NAMES_DATA = [
|
|
13
|
+
{ address: '0x0000000000000000000000000000000000000022', name: 'BITMIND' }, // Subnet 34
|
|
14
|
+
{ address: '0x0000000000000000000000000000000000000040', name: 'CHUTES' }, // Subnet 64
|
|
15
|
+
{ address: '0x0000000000000000000000000000000000000078', name: 'AFFINE' }, // Subnet 120
|
|
16
|
+
{ address: '0x0000000000000000000000000000000000000003E', name: 'RIDGES' }, // Subnet 62
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
const ASSET_NAMES: { [address: string]: string } = {};
|
|
20
|
+
ASSET_NAMES_DATA.forEach(({ address, name }) => {
|
|
21
|
+
ASSET_NAMES[address] = name;
|
|
22
|
+
ASSET_NAMES[address.toLowerCase()] = name;
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Display detailed position information
|
|
27
|
+
*/
|
|
28
|
+
export function displayPositionDetails(position: any, currentPrice: bigint) {
|
|
29
|
+
// Handle both old and new position structures
|
|
30
|
+
// Get asset name from mapping or fallback to UNKNOWN
|
|
31
|
+
let assetName = 'UNKNOWN';
|
|
32
|
+
if (position.asset) {
|
|
33
|
+
const assetAddress = position.asset.toLowerCase();
|
|
34
|
+
assetName = ASSET_NAMES[assetAddress] || ASSET_NAMES[position.asset] || 'UNKNOWN';
|
|
35
|
+
}
|
|
36
|
+
const status =
|
|
37
|
+
position.isActive !== undefined
|
|
38
|
+
? position.isActive
|
|
39
|
+
? chalk.green('Active')
|
|
40
|
+
: chalk.gray('Closed')
|
|
41
|
+
: position.notionalValue > 0n
|
|
42
|
+
? chalk.green('Active')
|
|
43
|
+
: chalk.gray('Closed');
|
|
44
|
+
|
|
45
|
+
console.log(` Asset: ${chalk.cyan(assetName)}`);
|
|
46
|
+
console.log(` Direction: ${position.isLong ? chalk.green('LONG ↗') : chalk.red('SHORT ↘')}`);
|
|
47
|
+
console.log(` Size: ${formatUSD(position.notionalValue)}`);
|
|
48
|
+
console.log(` Margin: ${formatTAO(position.margin)} TAO`);
|
|
49
|
+
|
|
50
|
+
// Calculate leverage from position size and margin
|
|
51
|
+
if (position.notionalValue && position.margin && position.margin !== 0n) {
|
|
52
|
+
// Both size and margin are in 18-decimal format (wei)
|
|
53
|
+
// Leverage = position.notionalValue / position.margin
|
|
54
|
+
const leverageRaw = BigInt(position.notionalValue) / BigInt(position.margin);
|
|
55
|
+
|
|
56
|
+
// Convert to number for display (leverage is typically a small number like 3x)
|
|
57
|
+
const leverageValue = Number(leverageRaw);
|
|
58
|
+
|
|
59
|
+
// If the calculated leverage seems too high, it might be in different format
|
|
60
|
+
const displayLeverage =
|
|
61
|
+
leverageValue > 1000
|
|
62
|
+
? (leverageValue / 1e18).toFixed(2) // Handle if still in wei format
|
|
63
|
+
: leverageValue.toFixed(2);
|
|
64
|
+
|
|
65
|
+
console.log(` Leverage: ${displayLeverage}x`);
|
|
66
|
+
} else if (position.leverage !== undefined) {
|
|
67
|
+
// Handle leverage field - could be in basis points or regular number
|
|
68
|
+
const leverageRaw = Number(position.leverage);
|
|
69
|
+
let leverageValue: number;
|
|
70
|
+
|
|
71
|
+
if (leverageRaw > 100) {
|
|
72
|
+
// Leverage is in basis points (e.g., 3000 = 30x, 10000 = 100%, so 30000 = 3x)
|
|
73
|
+
// Actually, if it's basis points for leverage calculation: 3x = 30000 basis points
|
|
74
|
+
// But the contract seems to multiply by 10000, so 3x = 30000
|
|
75
|
+
leverageValue = leverageRaw / 10000;
|
|
76
|
+
} else {
|
|
77
|
+
// Leverage is in regular format (e.g., 3 = 3x)
|
|
78
|
+
leverageValue = leverageRaw;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
console.log(` Leverage: ${leverageValue.toFixed(2)}x`);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
console.log(` Entry Price: ${formatUSD(position.entryPrice)}`);
|
|
85
|
+
console.log(` Current Price: ${formatUSD(currentPrice)}`);
|
|
86
|
+
console.log(` Status: ${status}`);
|
|
87
|
+
|
|
88
|
+
// Handle timestamps - could be lastUpdated (monolith) or timestamp (old)
|
|
89
|
+
const timestamp = position.lastUpdated || position.timestamp;
|
|
90
|
+
if (timestamp) {
|
|
91
|
+
console.log(` Last Updated: ${new Date(Number(timestamp) * 1000).toLocaleString()}`);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Only show liquidation price if available
|
|
95
|
+
if (position.liquidationPrice !== undefined) {
|
|
96
|
+
console.log(` Liquidation Price: ${formatUSD(position.liquidationPrice)}`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Calculate position P&L
|
|
102
|
+
*/
|
|
103
|
+
export function calculatePnL(position: any, currentPrice: bigint, size: bigint): bigint {
|
|
104
|
+
// Ensure all values are BigInt
|
|
105
|
+
const entryPrice = BigInt(position.entryPrice);
|
|
106
|
+
const currPrice = BigInt(currentPrice);
|
|
107
|
+
const posSize = BigInt(size);
|
|
108
|
+
|
|
109
|
+
const priceDiff = position.isLong ? currPrice - entryPrice : entryPrice - currPrice;
|
|
110
|
+
|
|
111
|
+
// Avoid division by zero
|
|
112
|
+
if (entryPrice === 0n) {
|
|
113
|
+
return 0n;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return (priceDiff * posSize) / entryPrice;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Display market summary
|
|
121
|
+
*/
|
|
122
|
+
export function displayMarketSummary(marketData: any) {
|
|
123
|
+
const table = new Table({
|
|
124
|
+
head: ['Metric', 'Value'],
|
|
125
|
+
colWidths: [20, 30],
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
table.push(
|
|
129
|
+
['Price', formatUSD(marketData.price)],
|
|
130
|
+
[
|
|
131
|
+
'24h Change',
|
|
132
|
+
marketData.change24h ? formatPercentage(marketData.change24h) : chalk.gray('N/A'),
|
|
133
|
+
],
|
|
134
|
+
['24h Volume', marketData.volume24h ? formatUSD(marketData.volume24h) : chalk.gray('N/A')],
|
|
135
|
+
['Funding Rate', formatPercentage(marketData.fundingRate) + ' per 8h'],
|
|
136
|
+
[
|
|
137
|
+
'Open Interest',
|
|
138
|
+
marketData.openInterest ? formatUSD(marketData.openInterest) : chalk.gray('N/A'),
|
|
139
|
+
],
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
console.log(table.toString());
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Create a simple ASCII price chart (placeholder)
|
|
147
|
+
*/
|
|
148
|
+
export function createPriceChart(): string {
|
|
149
|
+
// This is a placeholder for ASCII chart generation
|
|
150
|
+
const chart = `
|
|
151
|
+
$110 | ╱╲
|
|
152
|
+
$108 | ╱ ╲
|
|
153
|
+
$106 | ╱ ╲
|
|
154
|
+
$104 | ╱ ╲
|
|
155
|
+
$102 | ╱ ╲
|
|
156
|
+
$100 |╱
|
|
157
|
+
└──────────
|
|
158
|
+
1h 2h 3h`;
|
|
159
|
+
|
|
160
|
+
return chalk.gray(chart);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Create a volume chart (placeholder)
|
|
165
|
+
*/
|
|
166
|
+
export function createVolumeChart(): string {
|
|
167
|
+
const chart = `
|
|
168
|
+
10M | ▐▌
|
|
169
|
+
8M | ▐▌ ▐▌
|
|
170
|
+
6M | ▐▌ ▐▌
|
|
171
|
+
4M |▐▌▐▌ ▐▌▐▌
|
|
172
|
+
2M |▐▌▐▌▐▌▐▌▐▌
|
|
173
|
+
└──────────
|
|
174
|
+
1h 2h 3h`;
|
|
175
|
+
|
|
176
|
+
return chalk.gray(chart);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Format a large number with K/M/B suffixes
|
|
181
|
+
*/
|
|
182
|
+
export function formatLargeNumber(value: bigint): string {
|
|
183
|
+
const num = Number(value);
|
|
184
|
+
|
|
185
|
+
if (num >= 1e9) {
|
|
186
|
+
return (num / 1e9).toFixed(2) + 'B';
|
|
187
|
+
} else if (num >= 1e6) {
|
|
188
|
+
return (num / 1e6).toFixed(2) + 'M';
|
|
189
|
+
} else if (num >= 1e3) {
|
|
190
|
+
return (num / 1e3).toFixed(2) + 'K';
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return num.toFixed(2);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Display a progress bar
|
|
198
|
+
*/
|
|
199
|
+
export function progressBar(current: number, total: number, width: number = 20): string {
|
|
200
|
+
const percentage = current / total;
|
|
201
|
+
const filled = Math.round(width * percentage);
|
|
202
|
+
const empty = width - filled;
|
|
203
|
+
|
|
204
|
+
const bar = chalk.green('█'.repeat(filled)) + chalk.gray('░'.repeat(empty));
|
|
205
|
+
const percentStr = (percentage * 100).toFixed(1) + '%';
|
|
206
|
+
|
|
207
|
+
return `${bar} ${percentStr}`;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Display risk indicator
|
|
212
|
+
*/
|
|
213
|
+
export function riskIndicator(riskLevel: number): string {
|
|
214
|
+
if (riskLevel < 20) {
|
|
215
|
+
return chalk.green('●●●●●') + ' Low Risk';
|
|
216
|
+
} else if (riskLevel < 40) {
|
|
217
|
+
return chalk.green('●●●') + chalk.gray('●●') + ' Low-Medium Risk';
|
|
218
|
+
} else if (riskLevel < 60) {
|
|
219
|
+
return chalk.yellow('●●●') + chalk.gray('●●') + ' Medium Risk';
|
|
220
|
+
} else if (riskLevel < 80) {
|
|
221
|
+
return chalk.red('●●') + chalk.gray('●●●') + ' High Risk';
|
|
222
|
+
} else {
|
|
223
|
+
return chalk.red('●') + chalk.gray('●●●●') + ' Very High Risk';
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Format time remaining
|
|
229
|
+
*/
|
|
230
|
+
export function formatTimeRemaining(seconds: number): string {
|
|
231
|
+
const hours = Math.floor(seconds / 3600);
|
|
232
|
+
const minutes = Math.floor((seconds % 3600) / 60);
|
|
233
|
+
const secs = seconds % 60;
|
|
234
|
+
|
|
235
|
+
if (hours > 0) {
|
|
236
|
+
return `${hours}h ${minutes}m`;
|
|
237
|
+
} else if (minutes > 0) {
|
|
238
|
+
return `${minutes}m ${secs}s`;
|
|
239
|
+
} else {
|
|
240
|
+
return `${secs}s`;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Display a summary card
|
|
246
|
+
*/
|
|
247
|
+
export function displaySummaryCard(title: string, data: Array<[string, string]>) {
|
|
248
|
+
const maxKeyLength = Math.max(...data.map(([key]) => key.length));
|
|
249
|
+
|
|
250
|
+
console.log(chalk.bold(`\n╔══ ${title} ${'═'.repeat(40 - title.length)}`));
|
|
251
|
+
|
|
252
|
+
data.forEach(([key, value]) => {
|
|
253
|
+
const padding = ' '.repeat(maxKeyLength - key.length);
|
|
254
|
+
console.log(`║ ${key}:${padding} ${value}`);
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
console.log('╚' + '═'.repeat(44));
|
|
258
|
+
}
|
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompt Utilities
|
|
3
|
+
*
|
|
4
|
+
* Helper functions for user input and confirmation
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import inquirer from 'inquirer';
|
|
8
|
+
import chalk from 'chalk';
|
|
9
|
+
import { privateKeyToAccount } from 'viem/accounts';
|
|
10
|
+
import { parseEther, formatEther, getAddress as viemGetAddress } from 'viem';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Confirm an action with the user
|
|
14
|
+
*/
|
|
15
|
+
export async function confirmAction(
|
|
16
|
+
message: string,
|
|
17
|
+
defaultValue: boolean = false,
|
|
18
|
+
): Promise<boolean> {
|
|
19
|
+
const { confirmed } = await inquirer.prompt([
|
|
20
|
+
{
|
|
21
|
+
type: 'confirm',
|
|
22
|
+
name: 'confirmed',
|
|
23
|
+
message,
|
|
24
|
+
default: defaultValue,
|
|
25
|
+
},
|
|
26
|
+
]);
|
|
27
|
+
|
|
28
|
+
return confirmed;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Select from a list of options
|
|
33
|
+
*/
|
|
34
|
+
export async function selectFromList<T>(
|
|
35
|
+
message: string,
|
|
36
|
+
choices: Array<{ name: string; value: T }>,
|
|
37
|
+
defaultValue?: T,
|
|
38
|
+
): Promise<T> {
|
|
39
|
+
const { selected } = await inquirer.prompt([
|
|
40
|
+
{
|
|
41
|
+
type: 'list',
|
|
42
|
+
name: 'selected',
|
|
43
|
+
message,
|
|
44
|
+
choices,
|
|
45
|
+
default: defaultValue,
|
|
46
|
+
},
|
|
47
|
+
]);
|
|
48
|
+
|
|
49
|
+
return selected;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Get a numeric input with validation
|
|
54
|
+
*/
|
|
55
|
+
export async function getNumericInput(
|
|
56
|
+
message: string,
|
|
57
|
+
options: {
|
|
58
|
+
min?: number;
|
|
59
|
+
max?: number;
|
|
60
|
+
decimals?: number;
|
|
61
|
+
default?: number;
|
|
62
|
+
} = {},
|
|
63
|
+
): Promise<number> {
|
|
64
|
+
const { value } = await inquirer.prompt([
|
|
65
|
+
{
|
|
66
|
+
type: 'input',
|
|
67
|
+
name: 'value',
|
|
68
|
+
message,
|
|
69
|
+
default: options.default?.toString(),
|
|
70
|
+
validate: (input) => {
|
|
71
|
+
const num = parseFloat(input);
|
|
72
|
+
|
|
73
|
+
if (isNaN(num)) {
|
|
74
|
+
return 'Please enter a valid number';
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (options.min !== undefined && num < options.min) {
|
|
78
|
+
return `Value must be at least ${options.min}`;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (options.max !== undefined && num > options.max) {
|
|
82
|
+
return `Value must be at most ${options.max}`;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return true;
|
|
86
|
+
},
|
|
87
|
+
filter: (input) => {
|
|
88
|
+
const num = parseFloat(input);
|
|
89
|
+
if (options.decimals !== undefined) {
|
|
90
|
+
return parseFloat(num.toFixed(options.decimals));
|
|
91
|
+
}
|
|
92
|
+
return num;
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
]);
|
|
96
|
+
|
|
97
|
+
return value;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Get an Ethereum address with validation
|
|
102
|
+
*/
|
|
103
|
+
export async function getAddress(message: string, defaultValue?: string): Promise<string> {
|
|
104
|
+
const { address } = await inquirer.prompt([
|
|
105
|
+
{
|
|
106
|
+
type: 'input',
|
|
107
|
+
name: 'address',
|
|
108
|
+
message,
|
|
109
|
+
default: defaultValue,
|
|
110
|
+
validate: (input) => {
|
|
111
|
+
try {
|
|
112
|
+
viemGetAddress(input);
|
|
113
|
+
return true;
|
|
114
|
+
} catch {
|
|
115
|
+
return 'Please enter a valid Ethereum address';
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
filter: (input) => {
|
|
119
|
+
try {
|
|
120
|
+
return viemGetAddress(input);
|
|
121
|
+
} catch {
|
|
122
|
+
return input;
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
]);
|
|
127
|
+
|
|
128
|
+
return address;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Get a private key with validation (masked input)
|
|
133
|
+
*/
|
|
134
|
+
export async function getPrivateKey(message: string = 'Enter private key:'): Promise<string> {
|
|
135
|
+
const { key } = await inquirer.prompt([
|
|
136
|
+
{
|
|
137
|
+
type: 'password',
|
|
138
|
+
name: 'key',
|
|
139
|
+
message,
|
|
140
|
+
mask: '*',
|
|
141
|
+
validate: (input) => {
|
|
142
|
+
if (!input || input.length === 0) {
|
|
143
|
+
return 'Private key is required';
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
try {
|
|
147
|
+
// Validate it's a valid private key format
|
|
148
|
+
const cleanKey = input.startsWith('0x') ? input : '0x' + input;
|
|
149
|
+
if (cleanKey.length !== 66) {
|
|
150
|
+
return 'Invalid private key length';
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Try to create an account to validate
|
|
154
|
+
privateKeyToAccount(cleanKey as `0x${string}`);
|
|
155
|
+
return true;
|
|
156
|
+
} catch {
|
|
157
|
+
return 'Invalid private key format';
|
|
158
|
+
}
|
|
159
|
+
},
|
|
160
|
+
filter: (input) => {
|
|
161
|
+
return input.startsWith('0x') ? input : '0x' + input;
|
|
162
|
+
},
|
|
163
|
+
},
|
|
164
|
+
]);
|
|
165
|
+
|
|
166
|
+
return key;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Get TAO amount with validation
|
|
171
|
+
*/
|
|
172
|
+
export async function getTaoAmount(
|
|
173
|
+
message: string,
|
|
174
|
+
options: {
|
|
175
|
+
maxAmount?: bigint;
|
|
176
|
+
minAmount?: bigint;
|
|
177
|
+
default?: string;
|
|
178
|
+
} = {},
|
|
179
|
+
): Promise<bigint> {
|
|
180
|
+
const { amount } = await inquirer.prompt([
|
|
181
|
+
{
|
|
182
|
+
type: 'input',
|
|
183
|
+
name: 'amount',
|
|
184
|
+
message,
|
|
185
|
+
default: options.default,
|
|
186
|
+
validate: (input) => {
|
|
187
|
+
try {
|
|
188
|
+
const value = parseEther(input);
|
|
189
|
+
|
|
190
|
+
if (options.minAmount && value < options.minAmount) {
|
|
191
|
+
return `Minimum amount is ${formatEther(options.minAmount)} TAO`;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if (options.maxAmount && value > options.maxAmount) {
|
|
195
|
+
return `Maximum amount is ${formatEther(options.maxAmount)} TAO`;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
return true;
|
|
199
|
+
} catch {
|
|
200
|
+
return 'Please enter a valid amount';
|
|
201
|
+
}
|
|
202
|
+
},
|
|
203
|
+
},
|
|
204
|
+
]);
|
|
205
|
+
|
|
206
|
+
return parseEther(amount);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Multi-select from a list
|
|
211
|
+
*/
|
|
212
|
+
export async function multiSelect<T>(
|
|
213
|
+
message: string,
|
|
214
|
+
choices: Array<{ name: string; value: T; checked?: boolean }>,
|
|
215
|
+
): Promise<T[]> {
|
|
216
|
+
const { selected } = await inquirer.prompt([
|
|
217
|
+
{
|
|
218
|
+
type: 'checkbox',
|
|
219
|
+
name: 'selected',
|
|
220
|
+
message,
|
|
221
|
+
choices,
|
|
222
|
+
},
|
|
223
|
+
]);
|
|
224
|
+
|
|
225
|
+
return selected;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Validates direction input
|
|
230
|
+
*/
|
|
231
|
+
export function validateDirection(direction: string): 'long' | 'short' {
|
|
232
|
+
const normalizedDirection = direction.toLowerCase().trim();
|
|
233
|
+
|
|
234
|
+
if (['long', 'buy'].includes(normalizedDirection)) {
|
|
235
|
+
return 'long';
|
|
236
|
+
} else if (['short', 'sell'].includes(normalizedDirection)) {
|
|
237
|
+
return 'short';
|
|
238
|
+
} else {
|
|
239
|
+
throw new Error(`Invalid direction: "${direction}". Must be one of: long, short, buy, sell`);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Get asset symbol with validation
|
|
245
|
+
*/
|
|
246
|
+
export async function getAssetSymbol(
|
|
247
|
+
message: string = 'Enter asset symbol:',
|
|
248
|
+
defaultValue: string = 'ALPHA',
|
|
249
|
+
): Promise<string> {
|
|
250
|
+
const { asset } = await inquirer.prompt([
|
|
251
|
+
{
|
|
252
|
+
type: 'input',
|
|
253
|
+
name: 'asset',
|
|
254
|
+
message,
|
|
255
|
+
default: defaultValue,
|
|
256
|
+
transformer: (input) => input.toUpperCase(),
|
|
257
|
+
filter: (input) => input.toUpperCase(),
|
|
258
|
+
validate: (input) => {
|
|
259
|
+
if (!input || input.length === 0) {
|
|
260
|
+
return 'Asset symbol is required';
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
if (!/^[A-Z0-9]+$/.test(input.toUpperCase())) {
|
|
264
|
+
return 'Asset symbol must contain only letters and numbers';
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
return true;
|
|
268
|
+
},
|
|
269
|
+
},
|
|
270
|
+
]);
|
|
271
|
+
|
|
272
|
+
return asset;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Display a warning and get confirmation
|
|
277
|
+
*/
|
|
278
|
+
export async function confirmWarning(
|
|
279
|
+
warning: string,
|
|
280
|
+
confirmMessage: string = 'Do you want to proceed?',
|
|
281
|
+
): Promise<boolean> {
|
|
282
|
+
console.log(chalk.yellow.bold('\n⚠️ Warning:'));
|
|
283
|
+
console.log(chalk.yellow(warning));
|
|
284
|
+
|
|
285
|
+
return confirmAction(confirmMessage, false);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Get leverage selection
|
|
290
|
+
*/
|
|
291
|
+
export async function selectLeverage(
|
|
292
|
+
message: string = 'Select leverage:',
|
|
293
|
+
defaultValue: number = 3,
|
|
294
|
+
): Promise<number> {
|
|
295
|
+
const leverageOptions = [
|
|
296
|
+
{ name: '1x (No leverage)', value: 1 },
|
|
297
|
+
{ name: '2x', value: 2 },
|
|
298
|
+
{ name: '3x (Recommended)', value: 3 },
|
|
299
|
+
{ name: '5x', value: 5 },
|
|
300
|
+
{ name: '10x (High risk)', value: 10 },
|
|
301
|
+
];
|
|
302
|
+
|
|
303
|
+
return selectFromList(message, leverageOptions, defaultValue);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Get position size with smart defaults
|
|
308
|
+
*/
|
|
309
|
+
export async function getPositionSize(
|
|
310
|
+
availableBalance: bigint,
|
|
311
|
+
leverage: number = 3,
|
|
312
|
+
): Promise<{ size: bigint; margin: bigint }> {
|
|
313
|
+
console.log(chalk.cyan(`Available balance: ${formatEther(availableBalance)} TAO`));
|
|
314
|
+
|
|
315
|
+
const { sizeType } = await inquirer.prompt([
|
|
316
|
+
{
|
|
317
|
+
type: 'list',
|
|
318
|
+
name: 'sizeType',
|
|
319
|
+
message: 'How would you like to specify position size?',
|
|
320
|
+
choices: [
|
|
321
|
+
{ name: 'By margin amount (TAO)', value: 'margin' },
|
|
322
|
+
{ name: 'By position size (USD)', value: 'size' },
|
|
323
|
+
{ name: 'By percentage of balance', value: 'percentage' },
|
|
324
|
+
],
|
|
325
|
+
},
|
|
326
|
+
]);
|
|
327
|
+
|
|
328
|
+
let margin: bigint;
|
|
329
|
+
let size: bigint;
|
|
330
|
+
|
|
331
|
+
switch (sizeType) {
|
|
332
|
+
case 'margin':
|
|
333
|
+
margin = await getTaoAmount('Enter margin amount:', {
|
|
334
|
+
maxAmount: availableBalance,
|
|
335
|
+
minAmount: parseEther('10'), // Minimum 10 TAO
|
|
336
|
+
});
|
|
337
|
+
size = margin * BigInt(leverage);
|
|
338
|
+
break;
|
|
339
|
+
|
|
340
|
+
case 'size':
|
|
341
|
+
const sizeUsd = await getNumericInput('Enter position size (USD):', {
|
|
342
|
+
min: 100,
|
|
343
|
+
max: Number(formatEther(availableBalance)) * leverage * 100, // Rough USD estimate
|
|
344
|
+
});
|
|
345
|
+
size = parseEther(sizeUsd.toString());
|
|
346
|
+
margin = size / BigInt(leverage);
|
|
347
|
+
break;
|
|
348
|
+
|
|
349
|
+
case 'percentage':
|
|
350
|
+
const percentage = await getNumericInput('Enter percentage of balance:', {
|
|
351
|
+
min: 1,
|
|
352
|
+
max: 100,
|
|
353
|
+
decimals: 1,
|
|
354
|
+
});
|
|
355
|
+
margin = (availableBalance * BigInt(Math.floor(percentage * 10))) / 1000n;
|
|
356
|
+
size = margin * BigInt(leverage);
|
|
357
|
+
break;
|
|
358
|
+
|
|
359
|
+
default:
|
|
360
|
+
throw new Error('Invalid size type');
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
return { size, margin };
|
|
364
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"network": "mainnet",
|
|
3
|
+
"rpcUrl": "https://your-rpc-endpoint.com",
|
|
4
|
+
"contracts": {
|
|
5
|
+
"positionManager": "0x0000000000000000000000000000000000000000",
|
|
6
|
+
"marginAccount": "0x0000000000000000000000000000000000000000",
|
|
7
|
+
"fundingRate": "0x0000000000000000000000000000000000000000",
|
|
8
|
+
"liquidationEngine": "0x0000000000000000000000000000000000000000",
|
|
9
|
+
"protocolVault": "0x0000000000000000000000000000000000000000",
|
|
10
|
+
"priceOracle": "0x0000000000000000000000000000000000000000"
|
|
11
|
+
},
|
|
12
|
+
"defaultSettings": {
|
|
13
|
+
"leverage": 3,
|
|
14
|
+
"slippage": 0.5,
|
|
15
|
+
"gasLimit": 500000,
|
|
16
|
+
"confirmations": 2
|
|
17
|
+
},
|
|
18
|
+
"display": {
|
|
19
|
+
"currency": "USD",
|
|
20
|
+
"decimals": 2,
|
|
21
|
+
"timezone": "UTC"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Alpha Futures Client
|
|
3
|
+
* Main client class that provides access to all protocol contracts
|
|
4
|
+
*/
|
|
5
|
+
import { PriceOracleViem } from './contracts/viem/PriceOracleViem';
|
|
6
|
+
import { AlphaViem } from './contracts/viem/AlphaViem';
|
|
7
|
+
import { type Environment } from './config/environments';
|
|
8
|
+
import { type PublicClient, type WalletClient, type Address } from 'viem';
|
|
9
|
+
export interface AlphaClientConfig {
|
|
10
|
+
rpcUrl?: string;
|
|
11
|
+
privateKey?: `0x${string}`;
|
|
12
|
+
walletClient?: WalletClient;
|
|
13
|
+
}
|
|
14
|
+
export declare class AlphaFuturesClient {
|
|
15
|
+
private alphaContract;
|
|
16
|
+
private oracleContract;
|
|
17
|
+
private publicClient;
|
|
18
|
+
private walletClient?;
|
|
19
|
+
private environment?;
|
|
20
|
+
readonly oracle: PriceOracleViem;
|
|
21
|
+
constructor(environment: Environment, config?: AlphaClientConfig);
|
|
22
|
+
getAlpha(): AlphaViem;
|
|
23
|
+
getPublicClient(): PublicClient;
|
|
24
|
+
getWalletClient(): WalletClient | undefined;
|
|
25
|
+
getEnvironment(): Environment | undefined;
|
|
26
|
+
get isInitialized(): boolean;
|
|
27
|
+
get isConnected(): boolean;
|
|
28
|
+
getSignerAddress(): Promise<Address | undefined>;
|
|
29
|
+
/**
|
|
30
|
+
* Get the collateral token address (TAO/USDC) for the current environment
|
|
31
|
+
* @returns The collateral token contract address
|
|
32
|
+
*/
|
|
33
|
+
getCollateralTokenAddress(): Address | undefined;
|
|
34
|
+
static forEnvironment(environment: Environment, config?: AlphaClientConfig): AlphaFuturesClient;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=AlphaFuturesClient.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AlphaFuturesClient.d.ts","sourceRoot":"","sources":["../src/AlphaFuturesClient.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACnE,OAAO,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AACvD,OAAO,EAAwB,KAAK,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAC/E,OAAO,EAIL,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,OAAO,EACb,MAAM,MAAM,CAAC;AAGd,MAAM,WAAW,iBAAiB;IAChC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,KAAK,MAAM,EAAE,CAAC;IAC3B,YAAY,CAAC,EAAE,YAAY,CAAC;CAC7B;AAED,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,aAAa,CAAY;IACjC,OAAO,CAAC,cAAc,CAAkB;IACxC,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,YAAY,CAAC,CAAe;IACpC,OAAO,CAAC,WAAW,CAAC,CAAc;IAClC,SAAgB,MAAM,EAAE,eAAe,CAAC;gBAE5B,WAAW,EAAE,WAAW,EAAE,MAAM,GAAE,iBAAsB;IAiFpE,QAAQ,IAAI,SAAS;IAIrB,eAAe,IAAI,YAAY;IAI/B,eAAe,IAAI,YAAY,GAAG,SAAS;IAI3C,cAAc,IAAI,WAAW,GAAG,SAAS;IAIzC,IAAI,aAAa,IAAI,OAAO,CAE3B;IAED,IAAI,WAAW,IAAI,OAAO,CAEzB;IAEK,gBAAgB,IAAI,OAAO,CAAC,OAAO,GAAG,SAAS,CAAC;IAItD;;;OAGG;IACH,yBAAyB,IAAI,OAAO,GAAG,SAAS;IAMhD,MAAM,CAAC,cAAc,CACnB,WAAW,EAAE,WAAW,EACxB,MAAM,GAAE,iBAAsB,GAC7B,kBAAkB;CAGtB"}
|