@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.
Files changed (228) hide show
  1. package/.env.example +37 -0
  2. package/CHANGELOG.md +19 -0
  3. package/README.md +199 -0
  4. package/bin/alf +4 -0
  5. package/cli/README.md +198 -0
  6. package/cli/TEST_MANUAL.md +577 -0
  7. package/cli/commands/account.ts +545 -0
  8. package/cli/commands/funding.ts +481 -0
  9. package/cli/commands/liquidation.ts +523 -0
  10. package/cli/commands/market.ts +590 -0
  11. package/cli/commands/orders.ts +395 -0
  12. package/cli/commands/position.ts +1085 -0
  13. package/cli/commands/shared/positionUtils.ts +239 -0
  14. package/cli/commands/trading.ts +483 -0
  15. package/cli/commands/utils.ts +281 -0
  16. package/cli/commands/vault.ts +522 -0
  17. package/cli/index.ts +169 -0
  18. package/cli/interactive.ts +530 -0
  19. package/cli/utils/client.ts +457 -0
  20. package/cli/utils/config.ts +226 -0
  21. package/cli/utils/display.ts +258 -0
  22. package/cli/utils/index.ts +10 -0
  23. package/cli/utils/prompts.ts +364 -0
  24. package/config.example.json +23 -0
  25. package/dist/AlphaFuturesClient.d.ts +36 -0
  26. package/dist/AlphaFuturesClient.d.ts.map +1 -0
  27. package/dist/AlphaFuturesClient.js +116 -0
  28. package/dist/AlphaFuturesClient.js.map +1 -0
  29. package/dist/abi/Alpha.json +5987 -0
  30. package/dist/abi/abis.d.ts +319 -0
  31. package/dist/abi/abis.d.ts.map +1 -0
  32. package/dist/abi/abis.js +128 -0
  33. package/dist/abi/abis.js.map +1 -0
  34. package/dist/abi/index.d.ts +11 -0
  35. package/dist/abi/index.d.ts.map +1 -0
  36. package/dist/abi/index.js +15 -0
  37. package/dist/abi/index.js.map +1 -0
  38. package/dist/config/contracts.config.d.ts +70 -0
  39. package/dist/config/contracts.config.d.ts.map +1 -0
  40. package/dist/config/contracts.config.js +137 -0
  41. package/dist/config/contracts.config.js.map +1 -0
  42. package/dist/config/environments/alpha.config.d.ts +17 -0
  43. package/dist/config/environments/alpha.config.d.ts.map +1 -0
  44. package/dist/config/environments/alpha.config.js +140 -0
  45. package/dist/config/environments/alpha.config.js.map +1 -0
  46. package/dist/config/environments/beta.config.d.ts +16 -0
  47. package/dist/config/environments/beta.config.d.ts.map +1 -0
  48. package/dist/config/environments/beta.config.js +131 -0
  49. package/dist/config/environments/beta.config.js.map +1 -0
  50. package/dist/config/environments/dev.config.d.ts +13 -0
  51. package/dist/config/environments/dev.config.d.ts.map +1 -0
  52. package/dist/config/environments/dev.config.js +123 -0
  53. package/dist/config/environments/dev.config.js.map +1 -0
  54. package/dist/config/environments/index.d.ts +48 -0
  55. package/dist/config/environments/index.d.ts.map +1 -0
  56. package/dist/config/environments/index.js +81 -0
  57. package/dist/config/environments/index.js.map +1 -0
  58. package/dist/config/environments/localhost.config.d.ts +16 -0
  59. package/dist/config/environments/localhost.config.d.ts.map +1 -0
  60. package/dist/config/environments/localhost.config.js +152 -0
  61. package/dist/config/environments/localhost.config.js.map +1 -0
  62. package/dist/config/environments/prod.config.d.ts +20 -0
  63. package/dist/config/environments/prod.config.d.ts.map +1 -0
  64. package/dist/config/environments/prod.config.js +143 -0
  65. package/dist/config/environments/prod.config.js.map +1 -0
  66. package/dist/config/index.d.ts +7 -0
  67. package/dist/config/index.d.ts.map +1 -0
  68. package/dist/config/index.js +41 -0
  69. package/dist/config/index.js.map +1 -0
  70. package/dist/constants/assets.d.ts +76 -0
  71. package/dist/constants/assets.d.ts.map +1 -0
  72. package/dist/constants/assets.js +277 -0
  73. package/dist/constants/assets.js.map +1 -0
  74. package/dist/constants/contracts.d.ts +41 -0
  75. package/dist/constants/contracts.d.ts.map +1 -0
  76. package/dist/constants/contracts.js +57 -0
  77. package/dist/constants/contracts.js.map +1 -0
  78. package/dist/constants/index.d.ts +36 -0
  79. package/dist/constants/index.d.ts.map +1 -0
  80. package/dist/constants/index.js +75 -0
  81. package/dist/constants/index.js.map +1 -0
  82. package/dist/constants/networks.d.ts +32 -0
  83. package/dist/constants/networks.d.ts.map +1 -0
  84. package/dist/constants/networks.js +174 -0
  85. package/dist/constants/networks.js.map +1 -0
  86. package/dist/contracts/index.d.ts +5 -0
  87. package/dist/contracts/index.d.ts.map +1 -0
  88. package/dist/contracts/index.js +21 -0
  89. package/dist/contracts/index.js.map +1 -0
  90. package/dist/contracts/viem/AlphaViem.d.ts +518 -0
  91. package/dist/contracts/viem/AlphaViem.d.ts.map +1 -0
  92. package/dist/contracts/viem/AlphaViem.js +1287 -0
  93. package/dist/contracts/viem/AlphaViem.js.map +1 -0
  94. package/dist/contracts/viem/PriceOracleViem.d.ts +71 -0
  95. package/dist/contracts/viem/PriceOracleViem.d.ts.map +1 -0
  96. package/dist/contracts/viem/PriceOracleViem.js +212 -0
  97. package/dist/contracts/viem/PriceOracleViem.js.map +1 -0
  98. package/dist/contracts/viem/index.d.ts +9 -0
  99. package/dist/contracts/viem/index.d.ts.map +1 -0
  100. package/dist/contracts/viem/index.js +17 -0
  101. package/dist/contracts/viem/index.js.map +1 -0
  102. package/dist/errors/index.d.ts +44 -0
  103. package/dist/errors/index.d.ts.map +1 -0
  104. package/dist/errors/index.js +83 -0
  105. package/dist/errors/index.js.map +1 -0
  106. package/dist/index.d.ts +19 -0
  107. package/dist/index.d.ts.map +1 -0
  108. package/dist/index.js +60 -0
  109. package/dist/index.js.map +1 -0
  110. package/dist/types/alpha.d.ts +299 -0
  111. package/dist/types/alpha.d.ts.map +1 -0
  112. package/dist/types/alpha.js +6 -0
  113. package/dist/types/alpha.js.map +1 -0
  114. package/dist/types/client.d.ts +24 -0
  115. package/dist/types/client.d.ts.map +1 -0
  116. package/dist/types/client.js +13 -0
  117. package/dist/types/client.js.map +1 -0
  118. package/dist/types/contracts.d.ts +48 -0
  119. package/dist/types/contracts.d.ts.map +1 -0
  120. package/dist/types/contracts.js +6 -0
  121. package/dist/types/contracts.js.map +1 -0
  122. package/dist/types/funding.d.ts +27 -0
  123. package/dist/types/funding.d.ts.map +1 -0
  124. package/dist/types/funding.js +6 -0
  125. package/dist/types/funding.js.map +1 -0
  126. package/dist/types/index.d.ts +92 -0
  127. package/dist/types/index.d.ts.map +1 -0
  128. package/dist/types/index.js +47 -0
  129. package/dist/types/index.js.map +1 -0
  130. package/dist/types/liquidation.d.ts +20 -0
  131. package/dist/types/liquidation.d.ts.map +1 -0
  132. package/dist/types/liquidation.js +6 -0
  133. package/dist/types/liquidation.js.map +1 -0
  134. package/dist/types/margin.d.ts +29 -0
  135. package/dist/types/margin.d.ts.map +1 -0
  136. package/dist/types/margin.js +6 -0
  137. package/dist/types/margin.js.map +1 -0
  138. package/dist/types/oracle.d.ts +21 -0
  139. package/dist/types/oracle.d.ts.map +1 -0
  140. package/dist/types/oracle.js +6 -0
  141. package/dist/types/oracle.js.map +1 -0
  142. package/dist/types/positions.d.ts +43 -0
  143. package/dist/types/positions.d.ts.map +1 -0
  144. package/dist/types/positions.js +13 -0
  145. package/dist/types/positions.js.map +1 -0
  146. package/dist/utils/calculations.d.ts +84 -0
  147. package/dist/utils/calculations.d.ts.map +1 -0
  148. package/dist/utils/calculations.js +155 -0
  149. package/dist/utils/calculations.js.map +1 -0
  150. package/dist/utils/errors.d.ts +24 -0
  151. package/dist/utils/errors.d.ts.map +1 -0
  152. package/dist/utils/errors.js +129 -0
  153. package/dist/utils/errors.js.map +1 -0
  154. package/dist/utils/events.d.ts +40 -0
  155. package/dist/utils/events.d.ts.map +1 -0
  156. package/dist/utils/events.js +73 -0
  157. package/dist/utils/events.js.map +1 -0
  158. package/dist/utils/format.d.ts +40 -0
  159. package/dist/utils/format.d.ts.map +1 -0
  160. package/dist/utils/format.js +86 -0
  161. package/dist/utils/format.js.map +1 -0
  162. package/dist/utils/index.d.ts +10 -0
  163. package/dist/utils/index.d.ts.map +1 -0
  164. package/dist/utils/index.js +26 -0
  165. package/dist/utils/index.js.map +1 -0
  166. package/dist/utils/network.d.ts +52 -0
  167. package/dist/utils/network.d.ts.map +1 -0
  168. package/dist/utils/network.js +192 -0
  169. package/dist/utils/network.js.map +1 -0
  170. package/dist/utils/positionCalculations.d.ts +145 -0
  171. package/dist/utils/positionCalculations.d.ts.map +1 -0
  172. package/dist/utils/positionCalculations.js +278 -0
  173. package/dist/utils/positionCalculations.js.map +1 -0
  174. package/dist/utils/validation.d.ts +28 -0
  175. package/dist/utils/validation.d.ts.map +1 -0
  176. package/dist/utils/validation.js +68 -0
  177. package/dist/utils/validation.js.map +1 -0
  178. package/docs/README.md +40 -0
  179. package/docs/api/API.md +831 -0
  180. package/docs/guides/GETTING_STARTED.md +316 -0
  181. package/docs/guides/TRADING_GUIDE.md +677 -0
  182. package/docs/integration/INTEGRATION_GUIDE.md +1679 -0
  183. package/docs/integration/VIEM_INTEGRATION.md +294 -0
  184. package/docs/reference/CLI_QUICK_REFERENCE.md +197 -0
  185. package/docs/reference/TROUBLESHOOTING.md +922 -0
  186. package/package.json +113 -0
  187. package/src/AlphaFuturesClient.ts +158 -0
  188. package/src/abi/.gitkeep +1 -0
  189. package/src/abi/Alpha.json +5987 -0
  190. package/src/abi/README.md +99 -0
  191. package/src/abi/abis.ts +131 -0
  192. package/src/abi/index.ts +13 -0
  193. package/src/config/contracts.config.ts +186 -0
  194. package/src/config/environments/alpha.config.ts +139 -0
  195. package/src/config/environments/beta.config.ts +130 -0
  196. package/src/config/environments/dev.config.ts +122 -0
  197. package/src/config/environments/index.ts +87 -0
  198. package/src/config/environments/localhost.config.ts +153 -0
  199. package/src/config/environments/prod.config.ts +142 -0
  200. package/src/config/index.ts +29 -0
  201. package/src/constants/assets.ts +299 -0
  202. package/src/constants/contracts.ts +64 -0
  203. package/src/constants/index.ts +69 -0
  204. package/src/constants/networks.ts +182 -0
  205. package/src/contracts/index.ts +5 -0
  206. package/src/contracts/viem/AlphaViem.ts +1615 -0
  207. package/src/contracts/viem/PriceOracleViem.ts +272 -0
  208. package/src/contracts/viem/index.ts +11 -0
  209. package/src/errors/index.ts +87 -0
  210. package/src/index.ts +59 -0
  211. package/src/types/VIEM_TYPES_README.md +70 -0
  212. package/src/types/alpha.ts +358 -0
  213. package/src/types/client.ts +27 -0
  214. package/src/types/contracts.ts +74 -0
  215. package/src/types/funding.ts +31 -0
  216. package/src/types/index.ts +108 -0
  217. package/src/types/liquidation.ts +23 -0
  218. package/src/types/margin.ts +34 -0
  219. package/src/types/oracle.ts +24 -0
  220. package/src/types/positions.ts +48 -0
  221. package/src/utils/calculations.ts +175 -0
  222. package/src/utils/errors.ts +147 -0
  223. package/src/utils/events.ts +98 -0
  224. package/src/utils/format.ts +84 -0
  225. package/src/utils/index.ts +10 -0
  226. package/src/utils/network.ts +212 -0
  227. package/src/utils/positionCalculations.ts +317 -0
  228. package/src/utils/validation.ts +76 -0
@@ -0,0 +1,522 @@
1
+ /**
2
+ * Vault Commands - View protocol vault statistics and management
3
+ */
4
+
5
+ import { Command } from 'commander';
6
+ import { parseEther } from 'viem';
7
+ import chalk from 'chalk';
8
+ import ora from 'ora';
9
+ import Table from 'cli-table3';
10
+ import { AlphaFuturesClient } from '../../src';
11
+ import { formatUSD, formatTAO, formatPercentage, formatNumber } from '../../src/utils';
12
+ import { getClient, handleError } from '../utils/client';
13
+
14
+ export function vaultCommands(program: Command) {
15
+ const vault = program.command('vault').description('View protocol vault information');
16
+
17
+ // Vault info command
18
+ vault
19
+ .command('info')
20
+ .description('Get comprehensive vault information')
21
+ .option('-d, --detailed', 'Show detailed breakdown')
22
+ .action(async (options) => {
23
+ const spinner = ora('Loading vault information...').start();
24
+
25
+ try {
26
+ const client = await getClient(program.opts());
27
+
28
+ // Fetch vault data using alpha
29
+ const alpha = client.getAlpha();
30
+ const vaultStats = await alpha.getVaultStats();
31
+ const totalReserves = vaultStats.totalReserves;
32
+ const availableReserves = vaultStats.availableReserves;
33
+
34
+ // Try to get insurance fund balance
35
+ let insuranceFund = 0n;
36
+ try {
37
+ // Try multiple possible function names for insurance fund
38
+ try {
39
+ insuranceFund = (await alpha.readContract({
40
+ functionName: 'getInsuranceFundBalance',
41
+ args: [],
42
+ })) as bigint;
43
+ } catch {
44
+ try {
45
+ insuranceFund = (await alpha.readContract({
46
+ functionName: 'insuranceFund',
47
+ args: [],
48
+ })) as bigint;
49
+ } catch {
50
+ // Estimate insurance fund as 5% of reserves (conservative estimate)
51
+ insuranceFund = totalReserves > 0n ? (totalReserves * 500n) / 10000n : 0n;
52
+ }
53
+ }
54
+ } catch {
55
+ // Final fallback - use conservative estimate
56
+ insuranceFund = totalReserves > 0n ? (totalReserves * 500n) / 10000n : 0n;
57
+ }
58
+
59
+ spinner.stop();
60
+
61
+ console.log(chalk.bold('\nšŸ¦ Protocol Vault Overview:'));
62
+
63
+ // Basic info
64
+ console.log(chalk.bold('\nšŸ’° Reserve Status:'));
65
+ console.log(` Total Reserves: ${chalk.green(formatTAO(totalReserves) + ' TAO')}`);
66
+ console.log(` Insurance Fund: ${chalk.blue(formatTAO(insuranceFund) + ' TAO')}`);
67
+ console.log(` Available Reserves: ${chalk.cyan(formatTAO(availableReserves) + ' TAO')}`);
68
+
69
+ // Calculate percentages
70
+ const insurancePercent = totalReserves > 0n ? (insuranceFund * 10000n) / totalReserves : 0n;
71
+ console.log(` Insurance Ratio: ${formatPercentage(insurancePercent)}`);
72
+
73
+ if (options.detailed) {
74
+ console.log(chalk.bold('\nšŸ“Š Exposure Summary:'));
75
+ console.log(` Total Exposure: ${formatTAO(vaultStats.totalExposure)} TAO`);
76
+ console.log(
77
+ ` Unrealized P&L: ${
78
+ vaultStats.unrealizedPnl >= 0n
79
+ ? chalk.green('+' + formatTAO(vaultStats.unrealizedPnl))
80
+ : chalk.red(formatTAO(vaultStats.unrealizedPnl))
81
+ } TAO`,
82
+ );
83
+
84
+ const utilizationRate =
85
+ totalReserves > 0n
86
+ ? Number((vaultStats.totalExposure * 10000n) / totalReserves) / 100
87
+ : 0;
88
+ console.log(` Utilization Rate: ${utilizationRate.toFixed(2)}%`);
89
+
90
+ console.log(chalk.bold('\nšŸ“ˆ Current Metrics:'));
91
+ const exposureRatio =
92
+ availableReserves > 0n
93
+ ? Number((vaultStats.totalExposure * 10000n) / availableReserves) / 100
94
+ : 0;
95
+ console.log(` Exposure Ratio: ${exposureRatio.toFixed(2)}%`);
96
+ console.log(
97
+ ` Reserve Buffer: ${formatTAO(availableReserves - vaultStats.totalExposure)} TAO`,
98
+ );
99
+
100
+ console.log(chalk.bold('\n⚔ Risk Status:'));
101
+ const riskLevel = utilizationRate > 80 ? 'HIGH' : utilizationRate > 60 ? 'MEDIUM' : 'LOW';
102
+ const riskColor =
103
+ utilizationRate > 80 ? chalk.red : utilizationRate > 60 ? chalk.yellow : chalk.green;
104
+ console.log(` Risk Level: ${riskColor(riskLevel)}`);
105
+ }
106
+
107
+ if (program.opts().json) {
108
+ console.log(
109
+ '\n' +
110
+ JSON.stringify(
111
+ {
112
+ totalReserves: totalReserves.toString(),
113
+ insuranceFund: insuranceFund.toString(),
114
+ insuranceRatio: formatPercentage(insurancePercent),
115
+ },
116
+ null,
117
+ 2,
118
+ ),
119
+ );
120
+ }
121
+ } catch (error) {
122
+ spinner.fail('Failed to load vault information');
123
+ handleError(error, program.opts());
124
+ }
125
+ });
126
+
127
+ // Vault exposure command
128
+ vault
129
+ .command('exposure [asset]')
130
+ .description('View vault exposure by asset')
131
+ .option('-t, --threshold <percent>', 'Highlight exposures above threshold', '10')
132
+ .action(async (asset, options) => {
133
+ const spinner = ora('Loading vault exposure...').start();
134
+
135
+ try {
136
+ const client = await getClient(program.opts());
137
+ const alpha = client.getAlpha();
138
+ const threshold = parseFloat(options.threshold);
139
+
140
+ spinner.stop();
141
+
142
+ if (asset) {
143
+ // Single asset exposure
144
+ asset = asset.toUpperCase();
145
+
146
+ console.log(chalk.bold(`\nšŸ“Š Vault Exposure for ${asset}:`));
147
+
148
+ // Try to get exposure for known market addresses
149
+ try {
150
+ // Get market info to find the address for this asset
151
+ const knownMarkets = {
152
+ BITMIND: '0x0000000000000000000000000000000000000022',
153
+ CHUTES: '0x0000000000000000000000000000000000000040',
154
+ AFFINE: '0x0000000000000000000000000000000000000078',
155
+ RIDGES: '0x0000000000000000000000000000000000000003E',
156
+ };
157
+
158
+ const marketAddress = knownMarkets[asset as keyof typeof knownMarkets];
159
+ if (marketAddress) {
160
+ const vaultExposure = await alpha.getVaultExposure(marketAddress as `0x${string}`);
161
+ const vaultStats = await alpha.getVaultStats();
162
+
163
+ console.log(` Long Exposure: ${formatTAO(vaultExposure.longExposure)} TAO`);
164
+ console.log(` Short Exposure: ${formatTAO(vaultExposure.shortExposure)} TAO`);
165
+ console.log(
166
+ ` Net Exposure: ${
167
+ vaultExposure.netExposure >= 0n
168
+ ? chalk.green('+' + formatTAO(vaultExposure.netExposure))
169
+ : chalk.red(formatTAO(vaultExposure.netExposure))
170
+ } TAO`,
171
+ );
172
+
173
+ const reservePercent =
174
+ vaultStats.totalReserves > 0n
175
+ ? Number((vaultExposure.netExposure * 10000n) / vaultStats.totalReserves) / 100
176
+ : 0;
177
+ console.log(` % of Reserves: ${Math.abs(reservePercent).toFixed(2)}%`);
178
+ } else {
179
+ console.log(
180
+ chalk.yellow(
181
+ ` Unknown asset: ${asset}. Known assets: BITMIND, CHUTES, AFFINE, RIDGES`,
182
+ ),
183
+ );
184
+ }
185
+ } catch (error) {
186
+ console.log(` ${chalk.gray('Exposure data not available for this asset')}`);
187
+ }
188
+ } else {
189
+ // All assets exposure
190
+ console.log(chalk.bold('\nšŸ“Š Vault Exposure by Asset:'));
191
+
192
+ const table = new Table({
193
+ head: [
194
+ 'Asset',
195
+ 'Long Exposure',
196
+ 'Short Exposure',
197
+ 'Net Exposure',
198
+ '% of Reserves',
199
+ 'Risk',
200
+ ],
201
+ colWidths: [10, 18, 18, 18, 15, 10],
202
+ });
203
+
204
+ // Get exposure for all configured markets
205
+ const markets = {
206
+ BITMIND: '0x0000000000000000000000000000000000000022',
207
+ CHUTES: '0x0000000000000000000000000000000000000040',
208
+ AFFINE: '0x0000000000000000000000000000000000000078',
209
+ RIDGES: '0x0000000000000000000000000000000000000003E',
210
+ };
211
+
212
+ const vaultStats = await alpha.getVaultStats();
213
+ let totalLongExposure = 0n;
214
+ let totalShortExposure = 0n;
215
+
216
+ for (const [asset, marketAddress] of Object.entries(markets)) {
217
+ try {
218
+ const exposure = await alpha.getVaultExposure(marketAddress as `0x${string}`);
219
+ const reservePercent =
220
+ vaultStats.totalReserves > 0n
221
+ ? Math.abs(Number((exposure.netExposure * 10000n) / vaultStats.totalReserves)) /
222
+ 100
223
+ : 0;
224
+
225
+ const riskLevel =
226
+ reservePercent > threshold
227
+ ? 'HIGH'
228
+ : reservePercent > threshold / 2
229
+ ? 'MED'
230
+ : 'LOW';
231
+ const riskColor =
232
+ reservePercent > threshold
233
+ ? chalk.red(riskLevel)
234
+ : reservePercent > threshold / 2
235
+ ? chalk.yellow(riskLevel)
236
+ : chalk.green(riskLevel);
237
+
238
+ table.push([
239
+ asset,
240
+ formatNumber(Number(formatTAO(exposure.longExposure))),
241
+ formatNumber(Number(formatTAO(exposure.shortExposure))),
242
+ exposure.netExposure >= 0n
243
+ ? chalk.green('+' + formatNumber(Number(formatTAO(exposure.netExposure))))
244
+ : chalk.red(formatNumber(Number(formatTAO(exposure.netExposure)))),
245
+ `${reservePercent.toFixed(2)}%`,
246
+ riskColor,
247
+ ]);
248
+
249
+ totalLongExposure += exposure.longExposure;
250
+ totalShortExposure += exposure.shortExposure;
251
+ } catch {
252
+ table.push([asset, '0', '0', '0', '0.00%', chalk.gray('N/A')]);
253
+ }
254
+ }
255
+
256
+ console.log(table.toString());
257
+
258
+ // Summary
259
+ console.log(chalk.bold('\nšŸ“ˆ Exposure Summary:'));
260
+ console.log(` Total Long Exposure: ${formatTAO(totalLongExposure)} TAO`);
261
+ console.log(` Total Short Exposure: ${formatTAO(totalShortExposure)} TAO`);
262
+ const netExposure = totalLongExposure - totalShortExposure;
263
+ console.log(
264
+ ` Total Net Exposure: ${
265
+ netExposure >= 0n
266
+ ? chalk.green('+' + formatTAO(netExposure))
267
+ : chalk.red(formatTAO(netExposure))
268
+ } TAO`,
269
+ );
270
+ const exposureRatio =
271
+ vaultStats.totalReserves > 0n
272
+ ? Number(
273
+ ((totalLongExposure + totalShortExposure) * 10000n) / vaultStats.totalReserves,
274
+ ) / 100
275
+ : 0;
276
+ console.log(` Total Exposure Ratio: ${exposureRatio.toFixed(2)}%`);
277
+ }
278
+ } catch (error) {
279
+ spinner.fail('Failed to load exposure data');
280
+ handleError(error, program.opts());
281
+ }
282
+ });
283
+
284
+ // Vault history command
285
+ vault
286
+ .command('history')
287
+ .description('View vault balance history')
288
+ .option('-p, --period <period>', 'Time period: 24h, 7d, 30d', '7d')
289
+ .option('-i, --interval <interval>', 'Data interval: hourly, daily', 'daily')
290
+ .action(async (options) => {
291
+ const spinner = ora('Loading vault history...').start();
292
+
293
+ try {
294
+ const client = await getClient(program.opts());
295
+
296
+ spinner.stop();
297
+
298
+ console.log(chalk.bold('\nšŸ“ˆ Vault Balance History:'));
299
+ console.log(chalk.gray(`Period: ${options.period}, Interval: ${options.interval}`));
300
+
301
+ // ASCII chart placeholder
302
+ console.log('\n' + chalk.gray('Coming soon: ASCII chart showing vault balance over time'));
303
+
304
+ // Stats table
305
+ console.log(chalk.bold('\nšŸ“Š Period Statistics:'));
306
+ console.log(` Starting Balance: ${chalk.gray('Coming soon')}`);
307
+ console.log(` Ending Balance: ${chalk.gray('Coming soon')}`);
308
+ console.log(` Net Change: ${chalk.gray('Coming soon')}`);
309
+ console.log(` % Change: ${chalk.gray('Coming soon')}`);
310
+ console.log(` Peak Balance: ${chalk.gray('Coming soon')}`);
311
+ console.log(` Lowest Balance: ${chalk.gray('Coming soon')}`);
312
+ } catch (error) {
313
+ spinner.fail('Failed to load history');
314
+ handleError(error, program.opts());
315
+ }
316
+ });
317
+
318
+ // Vault performance command
319
+ vault
320
+ .command('performance')
321
+ .description('View vault performance metrics')
322
+ .option('-p, --period <period>', 'Time period: 24h, 7d, 30d, ytd, all', '30d')
323
+ .action(async (options) => {
324
+ const spinner = ora('Loading performance metrics...').start();
325
+
326
+ try {
327
+ const client = await getClient(program.opts());
328
+
329
+ spinner.stop();
330
+
331
+ console.log(chalk.bold('\nšŸ“Š Vault Performance Metrics:'));
332
+ console.log(chalk.gray(`Period: ${options.period}`));
333
+
334
+ console.log(chalk.bold('\nšŸ’° Returns:'));
335
+ console.log(` Total Return: ${chalk.gray('Coming soon')}`);
336
+ console.log(` APY: ${chalk.gray('Coming soon')}`);
337
+ console.log(` Daily Average: ${chalk.gray('Coming soon')}`);
338
+
339
+ console.log(chalk.bold('\nšŸ“ˆ Revenue Breakdown:'));
340
+ const revenueTable = new Table({
341
+ head: ['Source', 'Amount (TAO)', '% of Total'],
342
+ colWidths: [20, 20, 15],
343
+ });
344
+
345
+ // Placeholder data
346
+ revenueTable.push(
347
+ ['Trading Fees', chalk.gray('Coming soon'), chalk.gray('--')],
348
+ ['Funding Payments', chalk.gray('Coming soon'), chalk.gray('--')],
349
+ ['Liquidation Fees', chalk.gray('Coming soon'), chalk.gray('--')],
350
+ ['Other', chalk.gray('Coming soon'), chalk.gray('--')],
351
+ );
352
+
353
+ console.log(revenueTable.toString());
354
+
355
+ console.log(chalk.bold('\n⚔ Risk-Adjusted Metrics:'));
356
+ console.log(` Sharpe Ratio: ${chalk.gray('Coming soon')}`);
357
+ console.log(` Sortino Ratio: ${chalk.gray('Coming soon')}`);
358
+ console.log(` Max Drawdown: ${chalk.gray('Coming soon')}`);
359
+ console.log(` Win Rate: ${chalk.gray('Coming soon')}`);
360
+ } catch (error) {
361
+ spinner.fail('Failed to load performance metrics');
362
+ handleError(error, program.opts());
363
+ }
364
+ });
365
+
366
+ // Vault transactions command
367
+ vault
368
+ .command('transactions')
369
+ .alias('txs')
370
+ .description('View recent vault transactions')
371
+ .option('-l, --limit <number>', 'Number of transactions to show', '20')
372
+ .option('-t, --type <type>', 'Filter by type: deposit, withdraw, fee, funding')
373
+ .action(async (options) => {
374
+ const spinner = ora('Loading vault transactions...').start();
375
+
376
+ try {
377
+ const client = await getClient(program.opts());
378
+
379
+ // Query vault events
380
+ // TODO: Implement proper event filtering
381
+
382
+ spinner.stop();
383
+
384
+ console.log(chalk.bold('\nšŸ“œ Recent Vault Transactions:'));
385
+
386
+ const table = new Table({
387
+ head: ['Time', 'Type', 'Amount', 'Balance After', 'Details', 'Tx Hash'],
388
+ colWidths: [20, 12, 15, 15, 25, 15],
389
+ });
390
+
391
+ // Placeholder - would query actual events
392
+ console.log(table.toString());
393
+ console.log(chalk.yellow('\nāš ļø Transaction history coming soon'));
394
+ } catch (error) {
395
+ spinner.fail('Failed to load transactions');
396
+ handleError(error, program.opts());
397
+ }
398
+ });
399
+
400
+ // Vault health check
401
+ vault
402
+ .command('health')
403
+ .description('Check vault health and risk parameters')
404
+ .action(async () => {
405
+ const spinner = ora('Running vault health check...').start();
406
+
407
+ try {
408
+ const client = await getClient(program.opts());
409
+
410
+ // Perform health checks using alpha
411
+ const alpha = client.getAlpha();
412
+ const vaultStats = await alpha.getVaultStats();
413
+ const totalReserves = vaultStats.totalReserves;
414
+ const insuranceFund = 0n; // Would need getInsuranceFundBalance() method
415
+
416
+ spinner.stop();
417
+
418
+ console.log(chalk.bold('\nšŸ„ Vault Health Check:'));
419
+
420
+ // Get protocol constants for proper health checks (with fallbacks)
421
+ let constants;
422
+ try {
423
+ constants = await alpha.getConstants();
424
+ } catch (error) {
425
+ // Fallback to known protocol values if getConstants() fails
426
+ constants = {
427
+ maxTotalUtilization: 8000n, // 80% max utilization
428
+ liquidationThreshold: 2000n, // 20% liquidation threshold
429
+ basisPoints: 10000n,
430
+ precision: 10n ** 18n,
431
+ maxLeverage: 3000n, // 30x leverage (3000 basis points)
432
+ maintenanceMargin: 2000n, // 20% maintenance margin
433
+ liquidationFee: 500n, // 5% liquidation fee
434
+ };
435
+ }
436
+
437
+ // Reserve adequacy - Use actual seed amount (3,103 TAO) as baseline
438
+ const minimumReserves = parseEther('1000'); // 1,000 TAO minimum operational threshold
439
+ const reserveCheck = vaultStats.totalReserves >= minimumReserves;
440
+ console.log(
441
+ `\nāœ“ Reserve Adequacy: ${reserveCheck ? chalk.green('PASS') : chalk.red('FAIL')}`,
442
+ );
443
+ console.log(` Current: ${formatTAO(vaultStats.totalReserves)} TAO`);
444
+ console.log(` Minimum: ${formatTAO(minimumReserves)} TAO`);
445
+
446
+ // Insurance fund ratio (target 5-10% of reserves)
447
+ const insuranceRatio =
448
+ vaultStats.totalReserves > 0n
449
+ ? Number((insuranceFund * 10000n) / vaultStats.totalReserves) / 100
450
+ : 0;
451
+ const insuranceCheck = insuranceRatio >= 5; // 5% minimum for healthy operations
452
+ console.log(
453
+ `\nāœ“ Insurance Fund: ${insuranceCheck ? chalk.green('PASS') : chalk.yellow('WARNING')}`,
454
+ );
455
+ console.log(` Current: ${insuranceRatio.toFixed(2)}%`);
456
+ console.log(` Target: 5-10% of reserves`);
457
+
458
+ // Exposure limits - Check against protocol max utilization
459
+ const maxUtilization = Number(constants.maxTotalUtilization) / 100; // Convert from basis points
460
+ const utilizationRate =
461
+ vaultStats.totalReserves > 0n
462
+ ? Number((vaultStats.totalExposure * 10000n) / vaultStats.totalReserves) / 100
463
+ : 0;
464
+ const exposureCheck = utilizationRate <= maxUtilization;
465
+ console.log(
466
+ `\nāœ“ Exposure Limits: ${exposureCheck ? chalk.green('PASS') : chalk.red('FAIL')}`,
467
+ );
468
+ console.log(` Current Utilization: ${utilizationRate.toFixed(2)}%`);
469
+ console.log(` Max Allowed: ${maxUtilization.toFixed(2)}%`);
470
+
471
+ // Liquidity check - Available reserves vs total exposure
472
+ const liquidityBuffer = vaultStats.availableReserves - vaultStats.totalExposure;
473
+ const liquidityCheck = liquidityBuffer > 0n;
474
+ console.log(
475
+ `\nāœ“ Liquidity: ${liquidityCheck ? chalk.green('PASS') : chalk.yellow('WARNING')}`,
476
+ );
477
+ console.log(` Available Buffer: ${formatTAO(liquidityBuffer)} TAO`);
478
+ console.log(
479
+ ` Buffer Ratio: ${
480
+ vaultStats.totalReserves > 0n
481
+ ? (Number((liquidityBuffer * 10000n) / vaultStats.totalReserves) / 100).toFixed(2)
482
+ : '0.00'
483
+ }%`,
484
+ );
485
+
486
+ // Overall health score calculation
487
+ let healthScore = 0;
488
+ const checks = [reserveCheck, insuranceCheck, exposureCheck, liquidityCheck];
489
+ healthScore = (checks.filter(Boolean).length / checks.length) * 100;
490
+
491
+ console.log(chalk.bold('\nšŸŽÆ Overall Health Score:'));
492
+ const scoreColor =
493
+ healthScore >= 75 ? chalk.green : healthScore >= 50 ? chalk.yellow : chalk.red;
494
+ console.log(
495
+ ` ${scoreColor(healthScore.toFixed(0) + '%')} (${checks.filter(Boolean).length}/${checks.length} checks passed)`,
496
+ );
497
+
498
+ // Recommendations
499
+ console.log(chalk.bold('\nšŸ’” Recommendations:'));
500
+ if (!reserveCheck) {
501
+ console.log(
502
+ chalk.yellow(' • Increase vault reserves above minimum operational threshold'),
503
+ );
504
+ }
505
+ if (!insuranceCheck) {
506
+ console.log(chalk.yellow(' • Build up insurance fund to 5-10% of total reserves'));
507
+ }
508
+ if (!exposureCheck) {
509
+ console.log(chalk.red(' • CRITICAL: Reduce exposure below maximum utilization limit'));
510
+ }
511
+ if (!liquidityCheck) {
512
+ console.log(chalk.yellow(' • Monitor liquidity buffer and consider reducing exposure'));
513
+ }
514
+ if (healthScore === 100) {
515
+ console.log(chalk.green(' • Vault is operating within all safety parameters'));
516
+ }
517
+ } catch (error) {
518
+ spinner.fail('Health check failed');
519
+ handleError(error, program.opts());
520
+ }
521
+ });
522
+ }
package/cli/index.ts ADDED
@@ -0,0 +1,169 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Alpha Futures CLI - Main Entry Point
5
+ *
6
+ * A comprehensive command-line interface for interacting with the Alpha Futures protocol
7
+ */
8
+
9
+ // Load environment variables FIRST before any other imports
10
+ import * as dotenv from 'dotenv';
11
+ import { resolve } from 'path';
12
+ import { existsSync } from 'fs';
13
+
14
+ // Load environment variables with priority:
15
+ // 1. .env.anvil in parent directory (for localhost/Anvil testing)
16
+ // 2. .env in parent directory
17
+ // 3. .env in current directory
18
+ const parentAnvilEnvPath = resolve(process.cwd(), '..', '.env.anvil');
19
+ const parentEnvPath = resolve(process.cwd(), '..', '.env');
20
+ const currentAnvilEnvPath = resolve(process.cwd(), '.env.anvil');
21
+
22
+ if (existsSync(parentAnvilEnvPath)) {
23
+ dotenv.config({ path: parentAnvilEnvPath });
24
+ } else if (existsSync(currentAnvilEnvPath)) {
25
+ dotenv.config({ path: currentAnvilEnvPath });
26
+ } else if (existsSync(parentEnvPath)) {
27
+ dotenv.config({ path: parentEnvPath });
28
+ } else {
29
+ // Fallback to current directory .env
30
+ dotenv.config();
31
+ }
32
+
33
+ import { Command } from 'commander';
34
+ import chalk from 'chalk';
35
+ import figlet from 'figlet';
36
+
37
+ // Import command modules
38
+ import { accountCommands } from './commands/account';
39
+ import { positionCommands } from './commands/position';
40
+ import { tradingCommands } from './commands/trading';
41
+ import { marketCommands } from './commands/market';
42
+ import { liquidationCommands } from './commands/liquidation';
43
+ import { vaultCommands } from './commands/vault';
44
+ import { fundingCommands } from './commands/funding';
45
+ import { orderCommands } from './commands/orders';
46
+ import { utilityCommands } from './commands/utils';
47
+ import { startInteractiveMode } from './interactive';
48
+ import { loadConfig, saveConfig } from './utils/config';
49
+
50
+ // Create main program
51
+ const program = new Command();
52
+
53
+ // Display banner unless --no-banner flag is set
54
+ if (!process.argv.includes('--no-banner')) {
55
+ console.log(
56
+ chalk.cyan(
57
+ figlet.textSync('Alpha Futures', {
58
+ font: 'Standard',
59
+ horizontalLayout: 'default',
60
+ verticalLayout: 'default',
61
+ }),
62
+ ),
63
+ );
64
+ console.log(chalk.gray('Perpetual Futures Protocol on Bittensor EVM\n'));
65
+ }
66
+
67
+ // Configure main program
68
+ program
69
+ .name('alpha-futures')
70
+ .description('CLI for Alpha Futures perpetual futures protocol')
71
+ .version('1.0.0')
72
+ .option('-n, --network <network>', 'Network to connect to', 'bittensor')
73
+ .option('-r, --rpc <url>', 'Custom RPC URL')
74
+ .option('-k, --key <privateKey>', 'Private key for transactions')
75
+ .option('-c, --config <path>', 'Path to config file', '~/.alpha-futures/config.json')
76
+ .option('--no-color', 'Disable color output')
77
+ .option('--json', 'Output in JSON format')
78
+ .option('--no-banner', 'Disable ASCII banner')
79
+ .hook('preAction', async (thisCommand) => {
80
+ // Load saved config
81
+ const config = await loadConfig(thisCommand.opts().config);
82
+
83
+ // Merge config with command options
84
+ Object.keys(config).forEach((key) => {
85
+ if (!thisCommand.opts()[key]) {
86
+ thisCommand.opts()[key] = config[key];
87
+ }
88
+ });
89
+ });
90
+
91
+ // Interactive mode command
92
+ program
93
+ .command('interactive')
94
+ .alias('i')
95
+ .description('Start interactive trading mode')
96
+ .action(async () => {
97
+ const options = program.opts();
98
+ await startInteractiveMode(options);
99
+ });
100
+
101
+ // Config management commands
102
+ program
103
+ .command('config')
104
+ .description('Manage CLI configuration')
105
+ .addCommand(
106
+ new Command('set')
107
+ .description('Set a configuration value')
108
+ .argument('<key>', 'Configuration key')
109
+ .argument('<value>', 'Configuration value')
110
+ .action(async (key, value) => {
111
+ const configPath = program.opts().config;
112
+ const config = await loadConfig(configPath);
113
+ config[key] = value;
114
+ await saveConfig(configPath, config);
115
+ console.log(chalk.green(`āœ“ Configuration updated: ${key} = ${value}`));
116
+ }),
117
+ )
118
+ .addCommand(
119
+ new Command('get')
120
+ .description('Get a configuration value')
121
+ .argument('<key>', 'Configuration key')
122
+ .action(async (key) => {
123
+ const config = await loadConfig(program.opts().config);
124
+ console.log(config[key] || chalk.yellow('Not set'));
125
+ }),
126
+ )
127
+ .addCommand(
128
+ new Command('list').description('List all configuration values').action(async () => {
129
+ const config = await loadConfig(program.opts().config);
130
+ console.log(chalk.bold('\nConfiguration:'));
131
+ Object.entries(config).forEach(([key, value]) => {
132
+ console.log(` ${chalk.cyan(key)}: ${value}`);
133
+ });
134
+ }),
135
+ )
136
+ .addCommand(
137
+ new Command('reset').description('Reset configuration to defaults').action(async () => {
138
+ await saveConfig(program.opts().config, {});
139
+ console.log(chalk.green('āœ“ Configuration reset to defaults'));
140
+ }),
141
+ );
142
+
143
+ // Register command modules
144
+ accountCommands(program);
145
+ positionCommands(program);
146
+ tradingCommands(program);
147
+ marketCommands(program);
148
+ liquidationCommands(program);
149
+ vaultCommands(program);
150
+ fundingCommands(program);
151
+ orderCommands(program);
152
+ utilityCommands(program);
153
+
154
+ // Global error handling
155
+ process.on('unhandledRejection', (reason: any) => {
156
+ console.error(chalk.red('\nāŒ Error:'), reason.message || reason);
157
+ if (program.opts().debug) {
158
+ console.error(reason.stack);
159
+ }
160
+ process.exit(1);
161
+ });
162
+
163
+ // Parse arguments and execute
164
+ program.parse();
165
+
166
+ // Show help if no command provided
167
+ if (!process.argv.slice(2).length) {
168
+ program.outputHelp();
169
+ }