@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,530 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interactive Trading Mode
|
|
3
|
+
*
|
|
4
|
+
* Provides a real-time interactive interface for trading
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import chalk from 'chalk';
|
|
8
|
+
import inquirer from 'inquirer';
|
|
9
|
+
import ora from 'ora';
|
|
10
|
+
import { parseEther } from 'viem';
|
|
11
|
+
import { AlphaFuturesClient } from '../src';
|
|
12
|
+
import { formatUSD, formatTAO, formatPercentage } from '../src/utils';
|
|
13
|
+
import { getClient, handleError } from './utils/client';
|
|
14
|
+
import { displayPositionDetails, displayMarketSummary } from './utils/display';
|
|
15
|
+
|
|
16
|
+
interface InteractiveOptions {
|
|
17
|
+
network?: string;
|
|
18
|
+
rpc?: string;
|
|
19
|
+
key?: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export async function startInteractiveMode(options: InteractiveOptions) {
|
|
23
|
+
console.clear();
|
|
24
|
+
console.log(chalk.cyan.bold('🚀 Alpha Futures Interactive Trading Mode'));
|
|
25
|
+
console.log(chalk.gray('Type "help" for available commands or "exit" to quit\n'));
|
|
26
|
+
|
|
27
|
+
let client: AlphaFuturesClient;
|
|
28
|
+
let running = true;
|
|
29
|
+
|
|
30
|
+
// Initialize client
|
|
31
|
+
const spinner = ora('Connecting to Alpha Futures...').start();
|
|
32
|
+
try {
|
|
33
|
+
client = await getClient(options);
|
|
34
|
+
const address = await client.getSignerAddress();
|
|
35
|
+
spinner.succeed(`Connected as ${chalk.cyan(address)}`);
|
|
36
|
+
} catch (error: unknown) {
|
|
37
|
+
spinner.fail('Failed to connect');
|
|
38
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
39
|
+
console.error(chalk.red(errorMessage));
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Main loop
|
|
44
|
+
while (running) {
|
|
45
|
+
try {
|
|
46
|
+
// Get user input
|
|
47
|
+
const { command } = await inquirer.prompt([
|
|
48
|
+
{
|
|
49
|
+
type: 'input',
|
|
50
|
+
name: 'command',
|
|
51
|
+
message: chalk.green('>'),
|
|
52
|
+
prefix: '',
|
|
53
|
+
},
|
|
54
|
+
]);
|
|
55
|
+
|
|
56
|
+
// Parse command
|
|
57
|
+
const [cmd, ...args] = command.trim().toLowerCase().split(' ');
|
|
58
|
+
|
|
59
|
+
switch (cmd) {
|
|
60
|
+
case 'help':
|
|
61
|
+
case 'h':
|
|
62
|
+
showHelp();
|
|
63
|
+
break;
|
|
64
|
+
|
|
65
|
+
case 'balance':
|
|
66
|
+
case 'bal':
|
|
67
|
+
await showBalance(client);
|
|
68
|
+
break;
|
|
69
|
+
|
|
70
|
+
case 'positions':
|
|
71
|
+
case 'pos':
|
|
72
|
+
await showPositions(client);
|
|
73
|
+
break;
|
|
74
|
+
|
|
75
|
+
case 'market':
|
|
76
|
+
case 'mkt':
|
|
77
|
+
await showMarket(client, args[0]);
|
|
78
|
+
break;
|
|
79
|
+
|
|
80
|
+
case 'trade':
|
|
81
|
+
case 't':
|
|
82
|
+
await executeTrade(client);
|
|
83
|
+
break;
|
|
84
|
+
|
|
85
|
+
case 'open':
|
|
86
|
+
await quickOpen(client, args);
|
|
87
|
+
break;
|
|
88
|
+
|
|
89
|
+
case 'close':
|
|
90
|
+
await quickClose(client, args[0]);
|
|
91
|
+
break;
|
|
92
|
+
|
|
93
|
+
case 'deposit':
|
|
94
|
+
case 'dep':
|
|
95
|
+
await deposit(client, args[0]);
|
|
96
|
+
break;
|
|
97
|
+
|
|
98
|
+
case 'withdraw':
|
|
99
|
+
case 'wd':
|
|
100
|
+
await withdraw(client, args[0]);
|
|
101
|
+
break;
|
|
102
|
+
|
|
103
|
+
case 'stats':
|
|
104
|
+
await showStats(client);
|
|
105
|
+
break;
|
|
106
|
+
|
|
107
|
+
case 'clear':
|
|
108
|
+
case 'cls':
|
|
109
|
+
console.clear();
|
|
110
|
+
break;
|
|
111
|
+
|
|
112
|
+
case 'exit':
|
|
113
|
+
case 'quit':
|
|
114
|
+
case 'q':
|
|
115
|
+
running = false;
|
|
116
|
+
break;
|
|
117
|
+
|
|
118
|
+
case '':
|
|
119
|
+
// Empty command, do nothing
|
|
120
|
+
break;
|
|
121
|
+
|
|
122
|
+
default:
|
|
123
|
+
console.log(chalk.yellow(`Unknown command: ${cmd}. Type "help" for available commands.`));
|
|
124
|
+
}
|
|
125
|
+
} catch (error: unknown) {
|
|
126
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
127
|
+
console.error(chalk.red('Error:'), errorMessage);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
console.log(chalk.cyan('\n👋 Goodbye!'));
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function showHelp() {
|
|
135
|
+
console.log(chalk.bold('\n📚 Available Commands:'));
|
|
136
|
+
console.log(' ' + chalk.cyan('help, h') + ' Show this help message');
|
|
137
|
+
console.log(' ' + chalk.cyan('balance, bal') + ' Show account balance');
|
|
138
|
+
console.log(' ' + chalk.cyan('positions, pos') + ' List open positions');
|
|
139
|
+
console.log(' ' + chalk.cyan('market, mkt') + ' <asset> Show market data');
|
|
140
|
+
console.log(' ' + chalk.cyan('trade, t') + ' Open interactive trade dialog');
|
|
141
|
+
console.log(
|
|
142
|
+
' ' + chalk.cyan('open') + ' <asset> <long/short> <size> <margin> Quick open position',
|
|
143
|
+
);
|
|
144
|
+
console.log(' ' + chalk.cyan('close') + ' <positionId> Close position (use bytes16 format)');
|
|
145
|
+
console.log(' ' + chalk.cyan('deposit, dep') + ' <amount> Deposit TAO');
|
|
146
|
+
console.log(' ' + chalk.cyan('withdraw, wd') + ' <amount> Withdraw TAO');
|
|
147
|
+
console.log(' ' + chalk.cyan('stats') + ' Show protocol statistics');
|
|
148
|
+
console.log(' ' + chalk.cyan('clear, cls') + ' Clear screen');
|
|
149
|
+
console.log(' ' + chalk.cyan('exit, quit, q') + ' Exit interactive mode');
|
|
150
|
+
console.log();
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
async function showBalance(client: AlphaFuturesClient) {
|
|
154
|
+
const spinner = ora('Loading balance...').start();
|
|
155
|
+
|
|
156
|
+
try {
|
|
157
|
+
const address = await client.getSignerAddress();
|
|
158
|
+
const addressTyped = address as `0x${string}`;
|
|
159
|
+
const summary = await client.getAlpha().getAccountSummary(addressTyped);
|
|
160
|
+
|
|
161
|
+
spinner.stop();
|
|
162
|
+
|
|
163
|
+
console.log(chalk.bold('\n💰 Account Balance:'));
|
|
164
|
+
console.log(` Deposited: ${chalk.bold(formatTAO(summary.depositedBalance) + ' TAO')}`);
|
|
165
|
+
console.log(` Equity: ${chalk.bold(formatTAO(summary.accountEquity) + ' TAO')}`);
|
|
166
|
+
console.log(` Available: ${chalk.green(formatTAO(summary.availableMargin) + ' TAO')}`);
|
|
167
|
+
console.log(` Locked: ${chalk.yellow(formatTAO(summary.lockedMargin) + ' TAO')}`);
|
|
168
|
+
console.log();
|
|
169
|
+
} catch (error) {
|
|
170
|
+
spinner.fail('Failed to load balance');
|
|
171
|
+
throw error;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
async function showPositions(client: AlphaFuturesClient) {
|
|
176
|
+
const spinner = ora('Loading positions...').start();
|
|
177
|
+
|
|
178
|
+
try {
|
|
179
|
+
const address = await client.getSignerAddress();
|
|
180
|
+
const addressTyped = address as `0x${string}`;
|
|
181
|
+
const positionIds = await client.getAlpha().getUserPositions(addressTyped);
|
|
182
|
+
|
|
183
|
+
if (positionIds.length === 0) {
|
|
184
|
+
spinner.stop();
|
|
185
|
+
console.log(chalk.yellow('\nNo open positions'));
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Get position details which includes market info
|
|
190
|
+
const positionDetails = await Promise.all(
|
|
191
|
+
positionIds.map((id) => client.getAlpha().getPositionDetails(id)),
|
|
192
|
+
);
|
|
193
|
+
|
|
194
|
+
// Filter active positions (notionalValue > 0 means active)
|
|
195
|
+
const activePositionsWithIds = positionDetails
|
|
196
|
+
.map((pos, index) => ({ ...pos, positionId: positionIds[index] }))
|
|
197
|
+
.filter((p) => p.notionalValue > 0n);
|
|
198
|
+
|
|
199
|
+
spinner.stop();
|
|
200
|
+
|
|
201
|
+
console.log(chalk.bold(`\n📊 Open Positions (${activePositionsWithIds.length}):`));
|
|
202
|
+
|
|
203
|
+
for (const pos of activePositionsWithIds) {
|
|
204
|
+
const currentPrice = await client.oracle.getPrice(pos.market);
|
|
205
|
+
// Compute total unrealized P&L from components
|
|
206
|
+
const pnl = pos.pricePnl + pos.fundingPayment + pos.interestPayment;
|
|
207
|
+
|
|
208
|
+
console.log(
|
|
209
|
+
`\n ${pos.positionId} - ${pos.market} ${pos.isLong ? chalk.green('LONG') : chalk.red('SHORT')}`,
|
|
210
|
+
);
|
|
211
|
+
console.log(` Notional: ${formatUSD(pos.notionalValue)} | Margin: ${formatTAO(pos.margin)}`);
|
|
212
|
+
console.log(` Entry: ${formatUSD(pos.entryPrice)} | Current: ${formatUSD(currentPrice)}`);
|
|
213
|
+
console.log(
|
|
214
|
+
` P&L: ${pnl >= 0n ? chalk.green('+' + formatUSD(pnl)) : chalk.red(formatUSD(pnl))}`,
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
console.log();
|
|
218
|
+
} catch (error) {
|
|
219
|
+
spinner.fail('Failed to load positions');
|
|
220
|
+
throw error;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
async function showMarket(client: AlphaFuturesClient, asset?: string) {
|
|
225
|
+
if (!asset) {
|
|
226
|
+
console.log(chalk.yellow('Usage: market <asset>'));
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
const spinner = ora('Loading market data...').start();
|
|
231
|
+
|
|
232
|
+
try {
|
|
233
|
+
asset = asset.toUpperCase();
|
|
234
|
+
const [price, fundingRate] = await Promise.all([
|
|
235
|
+
client.oracle.getPrice(asset as `0x${string}`),
|
|
236
|
+
client.getAlpha().getFundingRate(asset as `0x${string}`),
|
|
237
|
+
]);
|
|
238
|
+
|
|
239
|
+
spinner.stop();
|
|
240
|
+
|
|
241
|
+
console.log(chalk.bold(`\n💹 ${asset} Market:`));
|
|
242
|
+
console.log(` Price: ${chalk.cyan(formatUSD(price))}`);
|
|
243
|
+
console.log(` Funding Rate: ${formatPercentage(fundingRate)} per 8h`);
|
|
244
|
+
console.log();
|
|
245
|
+
} catch (error) {
|
|
246
|
+
spinner.fail('Failed to load market data');
|
|
247
|
+
throw error;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
async function executeTrade(client: AlphaFuturesClient) {
|
|
252
|
+
try {
|
|
253
|
+
const address = await client.getSignerAddress();
|
|
254
|
+
const addressTyped = address as `0x${string}`;
|
|
255
|
+
const available = await client.getAlpha().getAvailableMargin(addressTyped);
|
|
256
|
+
|
|
257
|
+
console.log(chalk.cyan(`\nAvailable Balance: ${formatTAO(available)} TAO`));
|
|
258
|
+
|
|
259
|
+
const answers = await inquirer.prompt([
|
|
260
|
+
{
|
|
261
|
+
type: 'input',
|
|
262
|
+
name: 'asset',
|
|
263
|
+
message: 'Asset:',
|
|
264
|
+
default: 'ALPHA',
|
|
265
|
+
transformer: (input) => input.toUpperCase(),
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
type: 'list',
|
|
269
|
+
name: 'direction',
|
|
270
|
+
message: 'Direction:',
|
|
271
|
+
choices: [
|
|
272
|
+
{ name: chalk.green('Long ↗'), value: 'long' },
|
|
273
|
+
{ name: chalk.red('Short ↘'), value: 'short' },
|
|
274
|
+
],
|
|
275
|
+
},
|
|
276
|
+
{
|
|
277
|
+
type: 'input',
|
|
278
|
+
name: 'margin',
|
|
279
|
+
message: 'Margin (TAO):',
|
|
280
|
+
validate: (input) => {
|
|
281
|
+
const amount = parseFloat(input);
|
|
282
|
+
if (isNaN(amount) || amount <= 0) return 'Invalid amount';
|
|
283
|
+
if (parseEther(input) > available) return 'Insufficient balance';
|
|
284
|
+
return true;
|
|
285
|
+
},
|
|
286
|
+
},
|
|
287
|
+
{
|
|
288
|
+
type: 'list',
|
|
289
|
+
name: 'leverage',
|
|
290
|
+
message: 'Leverage:',
|
|
291
|
+
choices: ['1x', '2x', '3x', '5x', '10x'],
|
|
292
|
+
default: '3x',
|
|
293
|
+
},
|
|
294
|
+
]);
|
|
295
|
+
|
|
296
|
+
const marginAmount = parseEther(answers.margin);
|
|
297
|
+
const leverage = parseFloat(answers.leverage);
|
|
298
|
+
const positionSize = (marginAmount * BigInt(Math.floor(leverage * 100))) / 100n;
|
|
299
|
+
const isLong = answers.direction === 'long';
|
|
300
|
+
|
|
301
|
+
// Get current price
|
|
302
|
+
const currentPrice = await client.oracle.getPrice(answers.asset as `0x${string}`);
|
|
303
|
+
|
|
304
|
+
// Show summary and confirm
|
|
305
|
+
console.log(chalk.bold('\n📋 Order Summary:'));
|
|
306
|
+
console.log(` ${isLong ? chalk.green('LONG') : chalk.red('SHORT')} ${answers.asset}`);
|
|
307
|
+
console.log(` Size: ${formatUSD(positionSize)}`);
|
|
308
|
+
console.log(` Entry: ${formatUSD(currentPrice)}`);
|
|
309
|
+
console.log(` Leverage: ${leverage}x`);
|
|
310
|
+
|
|
311
|
+
const { confirm } = await inquirer.prompt([
|
|
312
|
+
{
|
|
313
|
+
type: 'confirm',
|
|
314
|
+
name: 'confirm',
|
|
315
|
+
message: 'Execute trade?',
|
|
316
|
+
default: true,
|
|
317
|
+
},
|
|
318
|
+
]);
|
|
319
|
+
|
|
320
|
+
if (!confirm) {
|
|
321
|
+
console.log(chalk.yellow('Trade cancelled'));
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
const spinner = ora('Opening position...').start();
|
|
326
|
+
|
|
327
|
+
const txHash = await client.getAlpha().openMarketPosition(
|
|
328
|
+
answers.asset as `0x${string}`,
|
|
329
|
+
isLong,
|
|
330
|
+
marginAmount,
|
|
331
|
+
parseEther(answers.leverage.replace('x', '')),
|
|
332
|
+
100n, // 1% max slippage
|
|
333
|
+
{
|
|
334
|
+
waitForConfirmation: true,
|
|
335
|
+
},
|
|
336
|
+
);
|
|
337
|
+
|
|
338
|
+
spinner.succeed('Position opened!');
|
|
339
|
+
console.log(chalk.green(`Transaction: ${txHash}\n`));
|
|
340
|
+
} catch (error) {
|
|
341
|
+
throw error;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
async function quickOpen(client: AlphaFuturesClient, args: string[]) {
|
|
346
|
+
if (args.length < 4) {
|
|
347
|
+
console.log(chalk.yellow('Usage: open <asset> <long/short> <margin> <leverage>'));
|
|
348
|
+
console.log(chalk.gray('Example: open ALPHA long 100 3'));
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
const [asset, direction, margin, leverage] = args;
|
|
353
|
+
const isLong = direction === 'long';
|
|
354
|
+
|
|
355
|
+
const spinner = ora('Opening position...').start();
|
|
356
|
+
|
|
357
|
+
try {
|
|
358
|
+
const txHash = await client.getAlpha().openMarketPosition(
|
|
359
|
+
asset.toUpperCase() as `0x${string}`,
|
|
360
|
+
isLong,
|
|
361
|
+
parseEther(margin),
|
|
362
|
+
parseEther(leverage),
|
|
363
|
+
100n, // 1% max slippage
|
|
364
|
+
{ waitForConfirmation: true },
|
|
365
|
+
);
|
|
366
|
+
|
|
367
|
+
spinner.succeed(`Position opened: ${asset.toUpperCase()} ${direction.toUpperCase()}`);
|
|
368
|
+
console.log(chalk.green(`Transaction: ${txHash}`));
|
|
369
|
+
} catch (error) {
|
|
370
|
+
spinner.fail('Failed to open position');
|
|
371
|
+
throw error;
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* Validates position ID format and provides helpful error message
|
|
377
|
+
* @param positionId Position ID to validate
|
|
378
|
+
* @throws Error with helpful message if format is incorrect
|
|
379
|
+
*/
|
|
380
|
+
function validatePositionIdFormat(positionId: string): void {
|
|
381
|
+
if (!positionId) {
|
|
382
|
+
throw new Error(`Position ID cannot be empty.
|
|
383
|
+
|
|
384
|
+
Expected format: 32 hex characters after 0x (bytes16)
|
|
385
|
+
Example: 0x00000000000000000000000000000001`);
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
const hex = positionId.startsWith('0x') ? positionId.slice(2) : positionId;
|
|
389
|
+
|
|
390
|
+
// Check if contains only hex characters
|
|
391
|
+
if (!/^[0-9a-fA-F]*$/.test(hex)) {
|
|
392
|
+
throw new Error(`Invalid position ID format: "${positionId}"
|
|
393
|
+
|
|
394
|
+
Position ID must contain only hexadecimal characters (0-9, a-f, A-F).
|
|
395
|
+
Expected format: 32 hex characters after 0x (bytes16)
|
|
396
|
+
Example: 0x00000000000000000000000000000001`);
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
// Warn if too long (would be truncated)
|
|
400
|
+
if (hex.length > 32) {
|
|
401
|
+
console.warn(
|
|
402
|
+
chalk.yellow(`⚠️ Position ID is longer than 32 hex characters and will be truncated.
|
|
403
|
+
Given: ${positionId}
|
|
404
|
+
Will use: 0x${hex.slice(0, 32)}`),
|
|
405
|
+
);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
async function quickClose(client: AlphaFuturesClient, positionId?: string) {
|
|
410
|
+
if (!positionId) {
|
|
411
|
+
console.log(chalk.yellow('Usage: close <positionId>'));
|
|
412
|
+
console.log(chalk.gray('Example: close 0x00000000000000000000000000000001'));
|
|
413
|
+
console.log(
|
|
414
|
+
chalk.gray('Note: Position ID must be in bytes16 format (32 hex characters after 0x)'),
|
|
415
|
+
);
|
|
416
|
+
return;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
try {
|
|
420
|
+
// Validate format first
|
|
421
|
+
validatePositionIdFormat(positionId);
|
|
422
|
+
} catch (error: any) {
|
|
423
|
+
console.error(chalk.red('❌ ' + error.message));
|
|
424
|
+
return;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
const spinner = ora('Closing position...').start();
|
|
428
|
+
|
|
429
|
+
try {
|
|
430
|
+
// Convert position ID to proper format - pad to 32 characters if needed
|
|
431
|
+
const hex = positionId.startsWith('0x') ? positionId.slice(2) : positionId;
|
|
432
|
+
const normalizedHex = hex.length > 32 ? hex.slice(0, 32) : hex.padEnd(32, '0');
|
|
433
|
+
const formattedPositionId = `0x${normalizedHex}` as `0x${string}`;
|
|
434
|
+
|
|
435
|
+
const position = await client.getAlpha().getPosition(formattedPositionId);
|
|
436
|
+
const txHash = await client
|
|
437
|
+
.getAlpha()
|
|
438
|
+
.closePosition(formattedPositionId, position.notionalValue, {
|
|
439
|
+
waitForConfirmation: true,
|
|
440
|
+
});
|
|
441
|
+
|
|
442
|
+
spinner.succeed(`Position #${positionId} closed`);
|
|
443
|
+
console.log(chalk.green(`Transaction: ${txHash}`));
|
|
444
|
+
} catch (error) {
|
|
445
|
+
spinner.fail('Failed to close position');
|
|
446
|
+
throw error;
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
async function deposit(client: AlphaFuturesClient, amount?: string) {
|
|
451
|
+
if (!amount) {
|
|
452
|
+
console.log(chalk.yellow('Usage: deposit <amount>'));
|
|
453
|
+
return;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
const spinner = ora('Processing deposit...').start();
|
|
457
|
+
|
|
458
|
+
try {
|
|
459
|
+
const txHash = await client.getAlpha().deposit(parseEther(amount), {
|
|
460
|
+
waitForConfirmation: true,
|
|
461
|
+
});
|
|
462
|
+
|
|
463
|
+
spinner.succeed(`Deposited ${amount} TAO`);
|
|
464
|
+
|
|
465
|
+
// Show new balance
|
|
466
|
+
const address = await client.getSignerAddress();
|
|
467
|
+
const addressTyped = address as `0x${string}`;
|
|
468
|
+
const balance = await client.getAlpha().getMarginBalance(addressTyped);
|
|
469
|
+
console.log(chalk.gray(`New balance: ${formatTAO(balance)} TAO\n`));
|
|
470
|
+
console.log(chalk.green(`Transaction: ${txHash}`));
|
|
471
|
+
} catch (error) {
|
|
472
|
+
spinner.fail('Deposit failed');
|
|
473
|
+
throw error;
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
async function withdraw(client: AlphaFuturesClient, amount?: string) {
|
|
478
|
+
if (!amount) {
|
|
479
|
+
console.log(chalk.yellow('Usage: withdraw <amount>'));
|
|
480
|
+
return;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
const spinner = ora('Processing withdrawal...').start();
|
|
484
|
+
|
|
485
|
+
try {
|
|
486
|
+
const address = await client.getSignerAddress();
|
|
487
|
+
const addressTyped = address as `0x${string}`;
|
|
488
|
+
const withdrawAmount =
|
|
489
|
+
amount === 'all'
|
|
490
|
+
? await client.getAlpha().getAvailableMargin(addressTyped)
|
|
491
|
+
: parseEther(amount);
|
|
492
|
+
|
|
493
|
+
const txHash = await client.getAlpha().withdraw(withdrawAmount, {
|
|
494
|
+
waitForConfirmation: true,
|
|
495
|
+
});
|
|
496
|
+
|
|
497
|
+
spinner.succeed(`Withdrew ${formatTAO(withdrawAmount)} TAO`);
|
|
498
|
+
|
|
499
|
+
// Show new balance
|
|
500
|
+
const balance = await client.getAlpha().getMarginBalance(addressTyped);
|
|
501
|
+
console.log(chalk.gray(`Remaining balance: ${formatTAO(balance)} TAO\n`));
|
|
502
|
+
console.log(chalk.green(`Transaction: ${txHash}`));
|
|
503
|
+
} catch (error) {
|
|
504
|
+
spinner.fail('Withdrawal failed');
|
|
505
|
+
throw error;
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
async function showStats(client: AlphaFuturesClient) {
|
|
510
|
+
const spinner = ora('Loading statistics...').start();
|
|
511
|
+
|
|
512
|
+
try {
|
|
513
|
+
const [vaultBalance, vaultStats] = await Promise.all([
|
|
514
|
+
client.getAlpha().getVaultBalance(),
|
|
515
|
+
client.getAlpha().getVaultStats(),
|
|
516
|
+
]);
|
|
517
|
+
|
|
518
|
+
spinner.stop();
|
|
519
|
+
|
|
520
|
+
console.log(chalk.bold('\n📊 Protocol Statistics:'));
|
|
521
|
+
console.log(` Vault Balance: ${formatTAO(vaultBalance)} TAO`);
|
|
522
|
+
console.log(` Total Reserves: ${formatTAO(vaultStats.totalReserves)} TAO`);
|
|
523
|
+
console.log(` Available Reserves: ${formatTAO(vaultStats.availableReserves)} TAO`);
|
|
524
|
+
console.log(` Total Exposure: ${formatTAO(vaultStats.totalExposure)} TAO`);
|
|
525
|
+
console.log();
|
|
526
|
+
} catch (error) {
|
|
527
|
+
spinner.fail('Failed to load statistics');
|
|
528
|
+
throw error;
|
|
529
|
+
}
|
|
530
|
+
}
|