@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,1615 @@
1
+ /**
2
+ * Alpha contract wrapper using Viem
3
+ * Main implementation of ALPHA perpetual futures protocol
4
+ */
5
+
6
+ import {
7
+ Address,
8
+ PublicClient,
9
+ WalletClient,
10
+ Hash,
11
+ TransactionReceipt,
12
+ parseEventLogs,
13
+ encodeFunctionData,
14
+ } from 'viem';
15
+ import { TransactionOptions } from '../../types';
16
+ import * as AlphaTypes from '../../types/alpha';
17
+ import AlphaABI from '../../abi/Alpha.json';
18
+
19
+ export class AlphaViem {
20
+ private publicClient: PublicClient;
21
+ private walletClient?: WalletClient;
22
+ private contractAddress: Address;
23
+ private collateralTokenAddress?: Address;
24
+
25
+ constructor(
26
+ contractAddress: Address,
27
+ publicClient: PublicClient,
28
+ walletClient?: WalletClient,
29
+ collateralTokenAddress?: Address,
30
+ ) {
31
+ this.contractAddress = contractAddress;
32
+ this.publicClient = publicClient;
33
+ this.walletClient = walletClient;
34
+ this.collateralTokenAddress = collateralTokenAddress;
35
+ }
36
+
37
+ private get isNativeCollateral(): boolean {
38
+ return (
39
+ !this.collateralTokenAddress ||
40
+ this.collateralTokenAddress === '0x0000000000000000000000000000000000000000'
41
+ );
42
+ }
43
+
44
+ // ============ Utility Functions ============
45
+
46
+ /**
47
+ * Convert bytes32 (padded by ABI encoding) to bytes16
48
+ * Takes first 16 bytes from the 32 byte value
49
+ */
50
+ private bytes32ToBytes16(bytes32: string): `0x${string}` {
51
+ // Remove 0x prefix if present
52
+ const hex = bytes32.startsWith('0x') ? bytes32.slice(2) : bytes32;
53
+ // Take first 32 characters (16 bytes)
54
+ const bytes16Hex = hex.slice(0, 32);
55
+ return `0x${bytes16Hex}` as `0x${string}`;
56
+ }
57
+
58
+ /**
59
+ * Simulate a contract transaction before writing to catch errors early
60
+ * This prevents sending failed transactions to the wallet
61
+ */
62
+ private async simulateAndWriteContract<
63
+ T extends { functionName: string; args?: readonly unknown[] },
64
+ >(
65
+ writeParams: T & {
66
+ address: Address;
67
+ abi: typeof AlphaABI;
68
+ account: Address;
69
+ value?: bigint;
70
+ },
71
+ ): Promise<Hash> {
72
+ if (!this.walletClient) {
73
+ throw new Error('Wallet client required for write operations');
74
+ }
75
+
76
+ if (!this.walletClient.account) {
77
+ throw new Error('Wallet client must have an account for transactions');
78
+ }
79
+
80
+ // Simulate the transaction first to catch errors early
81
+ try {
82
+ await this.publicClient.simulateContract({
83
+ address: writeParams.address,
84
+ abi: writeParams.abi,
85
+ functionName: writeParams.functionName,
86
+ args: writeParams.args,
87
+ account: this.walletClient.account.address,
88
+ value: writeParams.value,
89
+ });
90
+ } catch (simulationError: any) {
91
+ console.error('[simulateContract] Raw viem error:', simulationError);
92
+ let errorMessage = 'Transaction simulation failed';
93
+ let errorName: string | undefined;
94
+ let errorArgs: any[] | undefined;
95
+
96
+ // Walk the viem error chain to find decoded custom error data
97
+ for (let cur = simulationError; cur; cur = cur.cause) {
98
+ if (cur.data?.errorName) {
99
+ errorName = cur.data.errorName;
100
+ errorArgs = cur.data.args ? [...cur.data.args] : undefined;
101
+ errorMessage = errorName!;
102
+ if (errorArgs && errorArgs.length > 0) {
103
+ errorMessage += `: ${errorArgs
104
+ .map((arg: any) => (typeof arg === 'bigint' ? arg.toString() : String(arg)))
105
+ .join(', ')}`;
106
+ }
107
+ break;
108
+ }
109
+ }
110
+
111
+ // If no decoded error found, fall back to message extraction
112
+ if (!errorName) {
113
+ if (simulationError.cause?.shortMessage) {
114
+ errorMessage = simulationError.cause.shortMessage;
115
+ } else if (simulationError.shortMessage) {
116
+ errorMessage = simulationError.shortMessage;
117
+ } else if (simulationError.cause?.message) {
118
+ errorMessage = simulationError.cause.message;
119
+ } else if (simulationError.message) {
120
+ errorMessage = simulationError.message;
121
+ }
122
+ }
123
+
124
+ const error: any = new Error(errorMessage);
125
+ error.code = 'SIMULATION_FAILED';
126
+ error.cause = simulationError;
127
+ error.simulationError = true;
128
+ error.contractErrorName = errorName;
129
+ error.contractErrorArgs = errorArgs;
130
+ throw error;
131
+ }
132
+
133
+ // If simulation succeeds, proceed with the actual write
134
+ // Note: writeContract needs the full account object, not just the address
135
+ return await this.walletClient.writeContract({
136
+ ...writeParams,
137
+ account: this.walletClient.account,
138
+ } as any);
139
+ }
140
+
141
+ // ============ Admin Functions ============
142
+
143
+ async initializeMarket(
144
+ market: Address,
145
+ maxLeverage: bigint,
146
+ maintenanceMargin: bigint,
147
+ liquidationFee: bigint,
148
+ options?: TransactionOptions,
149
+ ): Promise<Hash> {
150
+ if (!this.walletClient) throw new Error('Wallet client required for write operations');
151
+
152
+ const { waitForConfirmation, ...txOptions } = options || {};
153
+
154
+ if (!this.walletClient.account) {
155
+ throw new Error('Wallet client must have an account for transactions');
156
+ }
157
+
158
+ const hash = await this.walletClient.writeContract({
159
+ address: this.contractAddress,
160
+ abi: AlphaABI,
161
+ functionName: 'initializeMarket',
162
+ args: [market, maxLeverage, maintenanceMargin, liquidationFee],
163
+ account: this.walletClient.account,
164
+ ...txOptions,
165
+ } as any);
166
+
167
+ if (waitForConfirmation) {
168
+ await this.publicClient.waitForTransactionReceipt({ hash });
169
+ return hash;
170
+ }
171
+
172
+ return hash;
173
+ }
174
+
175
+ async addMarket(market: Address, symbol: string, options?: TransactionOptions): Promise<Hash> {
176
+ if (!this.walletClient) throw new Error('Wallet client required for write operations');
177
+
178
+ const { waitForConfirmation, ...txOptions } = options || {};
179
+
180
+ if (!this.walletClient.account) {
181
+ throw new Error('Wallet client must have an account for transactions');
182
+ }
183
+
184
+ const hash = await this.walletClient.writeContract({
185
+ address: this.contractAddress,
186
+ abi: AlphaABI,
187
+ functionName: 'addMarket',
188
+ args: [market, symbol],
189
+ account: this.walletClient.account,
190
+ ...txOptions,
191
+ } as any);
192
+
193
+ if (waitForConfirmation) {
194
+ await this.publicClient.waitForTransactionReceipt({ hash });
195
+ return hash;
196
+ }
197
+
198
+ return hash;
199
+ }
200
+
201
+ async seedVault(amount: bigint, options?: TransactionOptions): Promise<Hash> {
202
+ if (!this.walletClient) throw new Error('Wallet client required for write operations');
203
+
204
+ const { waitForConfirmation, ...txOptions } = options || {};
205
+
206
+ if (!this.walletClient.account) {
207
+ throw new Error('Wallet client must have an account for transactions');
208
+ }
209
+
210
+ const hash = await this.walletClient.writeContract({
211
+ address: this.contractAddress,
212
+ abi: AlphaABI,
213
+ functionName: 'seedVault',
214
+ args: [amount],
215
+ account: this.walletClient.account,
216
+ ...txOptions,
217
+ } as any);
218
+
219
+ if (waitForConfirmation) {
220
+ await this.publicClient.waitForTransactionReceipt({ hash });
221
+ return hash;
222
+ }
223
+
224
+ return hash;
225
+ }
226
+
227
+ // ============ Margin Management ============
228
+
229
+ async deposit(amount: bigint, options?: TransactionOptions): Promise<Hash> {
230
+ const { waitForConfirmation, ...txOptions } = options || {};
231
+
232
+ if (!this.walletClient?.account) {
233
+ throw new Error('Wallet client must have an account for transactions');
234
+ }
235
+
236
+ const hash = await this.simulateAndWriteContract({
237
+ address: this.contractAddress,
238
+ abi: AlphaABI,
239
+ functionName: 'deposit',
240
+ args: [amount],
241
+ account: this.walletClient.account.address,
242
+ ...(this.isNativeCollateral ? { value: amount } : {}),
243
+ ...txOptions,
244
+ });
245
+
246
+ if (waitForConfirmation) {
247
+ await this.publicClient.waitForTransactionReceipt({ hash });
248
+ return hash;
249
+ }
250
+
251
+ return hash;
252
+ }
253
+
254
+ async withdraw(amount: bigint, options?: TransactionOptions): Promise<Hash> {
255
+ const { waitForConfirmation, ...txOptions } = options || {};
256
+
257
+ if (!this.walletClient?.account) {
258
+ throw new Error('Wallet client must have an account for transactions');
259
+ }
260
+
261
+ const hash = await this.simulateAndWriteContract({
262
+ address: this.contractAddress,
263
+ abi: AlphaABI,
264
+ functionName: 'withdraw',
265
+ args: [amount],
266
+ account: this.walletClient.account.address,
267
+ ...txOptions,
268
+ });
269
+
270
+ if (waitForConfirmation) {
271
+ await this.publicClient.waitForTransactionReceipt({ hash });
272
+ return hash;
273
+ }
274
+
275
+ return hash;
276
+ }
277
+
278
+ // ============ Position Management ============
279
+
280
+ /**
281
+ * Opens a market position with specified margin, leverage, and slippage tolerance
282
+ * @param market - Market address
283
+ * @param isLong - True for long position, false for short
284
+ * @param margin - Collateral amount to risk (in wei)
285
+ * @param leverage - Leverage multiplier in 1e18 format (e.g., 3e18 for 3x)
286
+ * @param maxSlippage - Maximum allowed slippage in basis points
287
+ * @param options - Transaction options
288
+ * @returns Transaction hash
289
+ */
290
+ async openMarketPosition(
291
+ market: Address,
292
+ isLong: boolean,
293
+ margin: bigint,
294
+ leverage: bigint,
295
+ maxSlippage: bigint,
296
+ options?: TransactionOptions,
297
+ ): Promise<Hash> {
298
+ const { waitForConfirmation, ...txOptions } = options || {};
299
+
300
+ if (!this.walletClient?.account) {
301
+ throw new Error('Wallet client must have an account for transactions');
302
+ }
303
+
304
+ // Contract expects a single struct parameter: MarketPositionParams
305
+ const params = {
306
+ market,
307
+ isLong,
308
+ margin,
309
+ leverage,
310
+ maxSlippage,
311
+ };
312
+
313
+ const hash = await this.simulateAndWriteContract({
314
+ address: this.contractAddress,
315
+ abi: AlphaABI,
316
+ functionName: 'openMarketPosition',
317
+ args: [params],
318
+ account: this.walletClient.account.address,
319
+ ...txOptions,
320
+ });
321
+
322
+ if (waitForConfirmation) {
323
+ await this.publicClient.waitForTransactionReceipt({ hash });
324
+ return hash;
325
+ }
326
+
327
+ return hash;
328
+ }
329
+
330
+ async openMarketPositionWithStruct(
331
+ params: AlphaTypes.MarketPositionParams,
332
+ options?: TransactionOptions,
333
+ ): Promise<Hash> {
334
+ if (!this.walletClient) throw new Error('Wallet client required for write operations');
335
+
336
+ const { waitForConfirmation, ...txOptions } = options || {};
337
+
338
+ if (!this.walletClient.account) {
339
+ throw new Error('Wallet client must have an account for transactions');
340
+ }
341
+
342
+ const hash = await this.walletClient.writeContract({
343
+ address: this.contractAddress,
344
+ abi: AlphaABI,
345
+ functionName: 'openMarketPositionWithStruct',
346
+ args: [params],
347
+ account: this.walletClient.account,
348
+ ...txOptions,
349
+ } as any);
350
+
351
+ if (waitForConfirmation) {
352
+ await this.publicClient.waitForTransactionReceipt({ hash });
353
+ return hash;
354
+ }
355
+
356
+ return hash;
357
+ }
358
+
359
+ async closePosition(
360
+ positionId: AlphaTypes.Bytes16,
361
+ sizeToClose: bigint,
362
+ options?: TransactionOptions,
363
+ ): Promise<Hash> {
364
+ const { waitForConfirmation, ...txOptions } = options || {};
365
+
366
+ if (!this.walletClient?.account) {
367
+ throw new Error('Wallet client must have an account for transactions');
368
+ }
369
+
370
+ const hash = await this.simulateAndWriteContract({
371
+ address: this.contractAddress,
372
+ abi: AlphaABI,
373
+ functionName: 'closePosition',
374
+ args: [positionId, sizeToClose],
375
+ account: this.walletClient.account.address,
376
+ ...txOptions,
377
+ });
378
+
379
+ if (waitForConfirmation) {
380
+ await this.publicClient.waitForTransactionReceipt({ hash });
381
+ return hash;
382
+ }
383
+
384
+ return hash;
385
+ }
386
+
387
+ /**
388
+ * Batch multiple contract calls into a single transaction using multicall.
389
+ * Handles ABI encoding internally.
390
+ *
391
+ * @param calls - Array of { functionName, args } to batch
392
+ * @param options - Optional transaction options
393
+ * @returns Transaction hash
394
+ *
395
+ * @example
396
+ * // Close multiple positions in one tx
397
+ * await alpha.multicall([
398
+ * { functionName: 'closePosition', args: [posId1, 0n] },
399
+ * { functionName: 'closePosition', args: [posId2, 0n] },
400
+ * ]);
401
+ */
402
+ async multicall(
403
+ calls: { functionName: string; args?: readonly unknown[] }[],
404
+ options?: TransactionOptions,
405
+ ): Promise<Hash> {
406
+ const { waitForConfirmation, ...txOptions } = options || {};
407
+
408
+ if (!this.walletClient?.account) {
409
+ throw new Error('Wallet client must have an account for transactions');
410
+ }
411
+
412
+ if (calls.length === 0) {
413
+ throw new Error('No calls provided');
414
+ }
415
+
416
+ const calldata = calls.map((call) =>
417
+ encodeFunctionData({
418
+ abi: AlphaABI,
419
+ functionName: call.functionName,
420
+ args: call.args ?? [],
421
+ }),
422
+ );
423
+
424
+ const hash = await this.simulateAndWriteContract({
425
+ address: this.contractAddress,
426
+ abi: AlphaABI,
427
+ functionName: 'multicall',
428
+ args: [calldata],
429
+ account: this.walletClient.account.address,
430
+ ...txOptions,
431
+ });
432
+
433
+ if (waitForConfirmation) {
434
+ await this.publicClient.waitForTransactionReceipt({ hash });
435
+ }
436
+
437
+ return hash;
438
+ }
439
+
440
+ /**
441
+ * Close multiple positions in a single transaction using multicall
442
+ * @param positionIds - Array of position IDs to close (bytes16 format)
443
+ * @param options - Optional transaction options
444
+ * @returns Transaction hash
445
+ */
446
+ async closeAllPositions(
447
+ positionIds: AlphaTypes.Bytes16[],
448
+ options?: TransactionOptions,
449
+ ): Promise<Hash> {
450
+ if (positionIds.length === 0) {
451
+ throw new Error('No position IDs provided');
452
+ }
453
+
454
+ return this.multicall(
455
+ positionIds.map((positionId) => ({
456
+ functionName: 'closePosition',
457
+ args: [positionId, 0n],
458
+ })),
459
+ options,
460
+ );
461
+ }
462
+
463
+ // ============ Order Management ============
464
+
465
+ /**
466
+ * Places a limit order with specified margin and leverage
467
+ * @param market - Market address
468
+ * @param isBuy - True for buy order, false for sell
469
+ * @param margin - Collateral amount to risk
470
+ * @param leverage - Leverage multiplier in 1e18 format (e.g., 3e18 for 3x)
471
+ * @param price - Limit price in wei
472
+ * @param reduceOnlyType - 0=Normal, 1=TakeProfit (natural side), 2=StopLoss (opposite side)
473
+ * @param options - Transaction options
474
+ * @returns Transaction hash
475
+ */
476
+ async placeLimitOrder(
477
+ market: Address,
478
+ isBuy: boolean,
479
+ margin: bigint,
480
+ leverage: bigint,
481
+ price: bigint,
482
+ reduceOnlyType: number = 0,
483
+ options?: TransactionOptions,
484
+ ): Promise<Hash> {
485
+ const { waitForConfirmation, ...txOptions } = options || {};
486
+
487
+ if (!this.walletClient?.account) {
488
+ throw new Error('Wallet client must have an account for transactions');
489
+ }
490
+
491
+ const params = {
492
+ market,
493
+ isBuy,
494
+ margin,
495
+ leverage,
496
+ price,
497
+ reduceOnlyType,
498
+ };
499
+
500
+ const hash = await this.simulateAndWriteContract({
501
+ address: this.contractAddress,
502
+ abi: AlphaABI,
503
+ functionName: 'placeLimitOrder',
504
+ args: [params],
505
+ account: this.walletClient.account.address,
506
+ ...txOptions,
507
+ });
508
+
509
+ if (waitForConfirmation) {
510
+ await this.publicClient.waitForTransactionReceipt({ hash });
511
+ return hash;
512
+ }
513
+
514
+ return hash;
515
+ }
516
+
517
+ /**
518
+ * Places a limit order using a params struct
519
+ * @param params - LimitOrderParams struct containing all order parameters
520
+ * @param options - Transaction options
521
+ * @returns Transaction hash
522
+ */
523
+ async placeLimitOrderWithStruct(
524
+ params: AlphaTypes.LimitOrderParams,
525
+ options?: TransactionOptions,
526
+ ): Promise<Hash> {
527
+ return this.placeLimitOrder(
528
+ params.market,
529
+ params.isBuy,
530
+ params.margin,
531
+ params.leverage,
532
+ params.price,
533
+ params.reduceOnlyType,
534
+ options,
535
+ );
536
+ }
537
+
538
+ async cancelOrder(market: Address, orderId: AlphaTypes.Bytes16, options?: TransactionOptions): Promise<Hash> {
539
+ if (!this.walletClient) throw new Error('Wallet client required for write operations');
540
+
541
+ const { waitForConfirmation, ...txOptions } = options || {};
542
+
543
+ if (!this.walletClient.account) {
544
+ throw new Error('Wallet client must have an account for transactions');
545
+ }
546
+
547
+ const hash = await this.walletClient.writeContract({
548
+ address: this.contractAddress,
549
+ abi: AlphaABI,
550
+ functionName: 'cancelOrder',
551
+ args: [market, orderId],
552
+ account: this.walletClient.account,
553
+ ...txOptions,
554
+ } as any);
555
+
556
+ if (waitForConfirmation) {
557
+ await this.publicClient.waitForTransactionReceipt({ hash });
558
+ return hash;
559
+ }
560
+
561
+ return hash;
562
+ }
563
+
564
+ async cancelAllOrders(market: Address, options?: TransactionOptions): Promise<Hash> {
565
+ if (!this.walletClient) throw new Error('Wallet client required for write operations');
566
+
567
+ const { waitForConfirmation, ...txOptions } = options || {};
568
+
569
+ if (!this.walletClient.account) {
570
+ throw new Error('Wallet client must have an account for transactions');
571
+ }
572
+
573
+ const hash = await this.walletClient.writeContract({
574
+ address: this.contractAddress,
575
+ abi: AlphaABI,
576
+ functionName: 'cancelAllOrders',
577
+ args: [market],
578
+ account: this.walletClient.account,
579
+ ...txOptions,
580
+ } as any);
581
+
582
+ if (waitForConfirmation) {
583
+ await this.publicClient.waitForTransactionReceipt({ hash });
584
+ return hash;
585
+ }
586
+
587
+ return hash;
588
+ }
589
+
590
+ // ============ Liquidation Functions ============
591
+
592
+ async liquidatePosition(
593
+ positionId: AlphaTypes.Bytes16,
594
+ options?: TransactionOptions,
595
+ ): Promise<Hash> {
596
+ if (!this.walletClient) throw new Error('Wallet client required for write operations');
597
+
598
+ const { waitForConfirmation, ...txOptions } = options || {};
599
+
600
+ if (!this.walletClient.account) {
601
+ throw new Error('Wallet client must have an account for transactions');
602
+ }
603
+
604
+ const hash = await this.walletClient.writeContract({
605
+ address: this.contractAddress,
606
+ abi: AlphaABI,
607
+ functionName: 'liquidatePosition',
608
+ args: [positionId],
609
+ account: this.walletClient.account,
610
+ ...txOptions,
611
+ } as any);
612
+
613
+ if (waitForConfirmation) {
614
+ await this.publicClient.waitForTransactionReceipt({ hash });
615
+ return hash;
616
+ }
617
+
618
+ return hash;
619
+ }
620
+
621
+ async claimKeeperRewards(options?: TransactionOptions): Promise<Hash> {
622
+ if (!this.walletClient) throw new Error('Wallet client required for write operations');
623
+
624
+ const { waitForConfirmation, ...txOptions } = options || {};
625
+
626
+ if (!this.walletClient.account) {
627
+ throw new Error('Wallet client must have an account for transactions');
628
+ }
629
+
630
+ const hash = await this.walletClient.writeContract({
631
+ address: this.contractAddress,
632
+ abi: AlphaABI,
633
+ functionName: 'claimKeeperRewards',
634
+ args: [],
635
+ account: this.walletClient.account,
636
+ ...txOptions,
637
+ } as any);
638
+
639
+ if (waitForConfirmation) {
640
+ await this.publicClient.waitForTransactionReceipt({ hash });
641
+ return hash;
642
+ }
643
+
644
+ return hash;
645
+ }
646
+
647
+ // ============ View Functions - Positions ============
648
+
649
+ async getPositionId(trader: Address, market: Address): Promise<AlphaTypes.Bytes16> {
650
+ const result = await this.publicClient.readContract({
651
+ address: this.contractAddress,
652
+ abi: AlphaABI,
653
+ functionName: 'getPositionId',
654
+ args: [trader, market],
655
+ });
656
+ // Convert bytes32 (padded) to bytes16
657
+ return this.bytes32ToBytes16(result as string) as AlphaTypes.Bytes16;
658
+ }
659
+
660
+ async hasPosition(trader: Address, market: Address): Promise<boolean> {
661
+ return (await this.publicClient.readContract({
662
+ address: this.contractAddress,
663
+ abi: AlphaABI,
664
+ functionName: 'hasPosition',
665
+ args: [trader, market],
666
+ })) as boolean;
667
+ }
668
+
669
+ async getPosition(positionId: AlphaTypes.Bytes16): Promise<AlphaTypes.MonolithPosition> {
670
+ const result = (await this.publicClient.readContract({
671
+ address: this.contractAddress,
672
+ abi: AlphaABI,
673
+ functionName: 'getPosition',
674
+ args: [positionId],
675
+ })) as any[];
676
+
677
+ // Ensure values are BigInt for calculations
678
+ const notionalValue = BigInt(result[3]);
679
+ const margin = BigInt(result[4]);
680
+
681
+ return {
682
+ // Based on ABI: [0] owner, [1] market, [2] isLong, [3] notionalValue, [4] margin, [5] entryPrice, [6] fundingIndex, [7] lastUpdateTime
683
+ notionalValue: result[3],
684
+ margin: result[4],
685
+ entryPrice: result[5],
686
+ isLong: result[2],
687
+ lastUpdated: result[7], // Maps from contract's lastUpdateTime
688
+ fundingIndex: result[6],
689
+ leverage: margin > 0n ? (notionalValue * 1000000000000000000n) / margin : 0n, // Calculate leverage in 1e18 format (notionalValue/margin * 1e18)
690
+ liquidationPrice: 0n, // Not returned by ABI - would need separate calculation
691
+ };
692
+ }
693
+
694
+ async getPositionDetails(positionId: AlphaTypes.Bytes16): Promise<AlphaTypes.PositionDetails> {
695
+ return (await this.publicClient.readContract({
696
+ address: this.contractAddress,
697
+ abi: AlphaABI,
698
+ functionName: 'getPositionDetails',
699
+ args: [positionId],
700
+ })) as AlphaTypes.PositionDetails;
701
+ }
702
+
703
+ async getUserPositions(trader: Address): Promise<AlphaTypes.Bytes16[]> {
704
+ const result = (await this.publicClient.readContract({
705
+ address: this.contractAddress,
706
+ abi: AlphaABI,
707
+ functionName: 'getUserPositions',
708
+ args: [trader],
709
+ })) as string[];
710
+ // Convert each bytes32 (padded) to bytes16
711
+ return result.map((id) => this.bytes32ToBytes16(id) as AlphaTypes.Bytes16);
712
+ }
713
+
714
+ async getUserPositionsSummary(trader: Address): Promise<AlphaTypes.PositionSummary> {
715
+ const result = (await this.publicClient.readContract({
716
+ address: this.contractAddress,
717
+ abi: AlphaABI,
718
+ functionName: 'getUserPositionsSummary',
719
+ args: [trader],
720
+ })) as any[];
721
+ return {
722
+ totalPositions: result[0],
723
+ totalMargin: result[1],
724
+ totalUnrealizedPnl: result[2],
725
+ totalSize: result[3],
726
+ };
727
+ }
728
+
729
+ async calculateUnrealizedPnl(positionId: AlphaTypes.Bytes16): Promise<bigint> {
730
+ return (await this.publicClient.readContract({
731
+ address: this.contractAddress,
732
+ abi: AlphaABI,
733
+ functionName: 'calculateUnrealizedPnl',
734
+ args: [positionId],
735
+ })) as bigint;
736
+ }
737
+
738
+ async getMarginRatio(positionId: AlphaTypes.Bytes16): Promise<bigint> {
739
+ return (await this.publicClient.readContract({
740
+ address: this.contractAddress,
741
+ abi: AlphaABI,
742
+ functionName: 'getMarginRatio',
743
+ args: [positionId],
744
+ })) as bigint;
745
+ }
746
+
747
+ async isLiquidatable(positionId: AlphaTypes.Bytes16): Promise<boolean> {
748
+ return (await this.publicClient.readContract({
749
+ address: this.contractAddress,
750
+ abi: AlphaABI,
751
+ functionName: 'isLiquidatable',
752
+ args: [positionId],
753
+ })) as boolean;
754
+ }
755
+
756
+ async getLiquidationStatus(
757
+ positionId: AlphaTypes.Bytes16,
758
+ ): Promise<AlphaTypes.LiquidationStatus> {
759
+ const result = (await this.publicClient.readContract({
760
+ address: this.contractAddress,
761
+ abi: AlphaABI,
762
+ functionName: 'getLiquidationStatus',
763
+ args: [positionId],
764
+ })) as any[];
765
+ return {
766
+ isLiquidatable: result[0],
767
+ marginRatio: result[1],
768
+ requiredMargin: result[2],
769
+ liquidationPrice: result[3],
770
+ };
771
+ }
772
+
773
+ /**
774
+ * Get account-level liquidation status (cross-margin)
775
+ * When account equity < total maintenance, ALL positions are liquidatable (Hyperliquid-style)
776
+ */
777
+ async getAccountLiquidationStatus(
778
+ trader: Address,
779
+ ): Promise<{
780
+ liquidatable: boolean;
781
+ worstPositionId: AlphaTypes.Bytes16;
782
+ accountEquity: bigint;
783
+ totalMaintenanceRequired: bigint;
784
+ }> {
785
+ const result = (await this.publicClient.readContract({
786
+ address: this.contractAddress,
787
+ abi: AlphaABI,
788
+ functionName: 'getAccountLiquidationStatus',
789
+ args: [trader],
790
+ })) as any[];
791
+ return {
792
+ liquidatable: result[0],
793
+ worstPositionId: result[1] as AlphaTypes.Bytes16,
794
+ accountEquity: result[2],
795
+ totalMaintenanceRequired: result[3],
796
+ };
797
+ }
798
+
799
+ /**
800
+ * Get cross-margin liquidation price for a position
801
+ * Uses Hyperliquid formula: accounts for all positions' PnL in the account
802
+ */
803
+ async getAccountLiquidationPrice(positionId: AlphaTypes.Bytes16): Promise<bigint> {
804
+ return (await this.publicClient.readContract({
805
+ address: this.contractAddress,
806
+ abi: AlphaABI,
807
+ functionName: 'getAccountLiquidationPrice',
808
+ args: [positionId],
809
+ })) as bigint;
810
+ }
811
+
812
+ // ============ View Functions - Margin ============
813
+
814
+ /**
815
+ * Get raw deposited margin balance (excludes unrealized PnL).
816
+ * For account equity (balance + PnL), use getAccountSummary().
817
+ */
818
+ async getMarginBalance(trader: Address): Promise<bigint> {
819
+ return (await this.publicClient.readContract({
820
+ address: this.contractAddress,
821
+ abi: AlphaABI,
822
+ functionName: 'getMarginBalance',
823
+ args: [trader],
824
+ })) as bigint;
825
+ }
826
+
827
+ /**
828
+ * Get comprehensive account summary in a single RPC call.
829
+ * Returns deposited balance, account equity, unrealized PnL, locked margin, and available margin.
830
+ */
831
+ async getAccountSummary(trader: Address): Promise<AlphaTypes.AccountSummary> {
832
+ const result = (await this.publicClient.readContract({
833
+ address: this.contractAddress,
834
+ abi: AlphaABI,
835
+ functionName: 'getAccountSummary',
836
+ args: [trader],
837
+ })) as any;
838
+ return {
839
+ depositedBalance: result.depositedBalance ?? result[0],
840
+ accountEquity: result.accountEquity ?? result[1],
841
+ unrealizedPnl: result.unrealizedPnl ?? result[2],
842
+ lockedMargin: result.lockedMargin ?? result[3],
843
+ availableMargin: result.availableMargin ?? result[4],
844
+ };
845
+ }
846
+
847
+ async getLockedMargin(trader: Address): Promise<bigint> {
848
+ return (await this.publicClient.readContract({
849
+ address: this.contractAddress,
850
+ abi: AlphaABI,
851
+ functionName: 'getLockedMargin',
852
+ args: [trader],
853
+ })) as bigint;
854
+ }
855
+
856
+ async getAvailableMargin(trader: Address): Promise<bigint> {
857
+ return (await this.publicClient.readContract({
858
+ address: this.contractAddress,
859
+ abi: AlphaABI,
860
+ functionName: 'getAvailableMargin',
861
+ args: [trader],
862
+ })) as bigint;
863
+ }
864
+
865
+ async getMaxUserDeposit(): Promise<bigint> {
866
+ return (await this.publicClient.readContract({
867
+ address: this.contractAddress,
868
+ abi: AlphaABI,
869
+ functionName: 'getMaxUserDeposit',
870
+ args: [],
871
+ })) as bigint;
872
+ }
873
+
874
+ async getMaxGlobalDeposits(): Promise<bigint> {
875
+ return (await this.publicClient.readContract({
876
+ address: this.contractAddress,
877
+ abi: AlphaABI,
878
+ functionName: 'getMaxGlobalDeposits',
879
+ args: [],
880
+ })) as bigint;
881
+ }
882
+
883
+ async getTotalDeposits(): Promise<bigint> {
884
+ return (await this.publicClient.readContract({
885
+ address: this.contractAddress,
886
+ abi: AlphaABI,
887
+ functionName: 'getTotalDeposits',
888
+ args: [],
889
+ })) as bigint;
890
+ }
891
+
892
+ // ============ View Functions - Markets ============
893
+
894
+ async getMarketInfo(market: Address): Promise<AlphaTypes.MarketInfo> {
895
+ const result = (await this.publicClient.readContract({
896
+ address: this.contractAddress,
897
+ abi: AlphaABI,
898
+ functionName: 'getMarketInfo',
899
+ args: [market],
900
+ })) as any[];
901
+
902
+ if (!result || !Array.isArray(result) || result.length < 8) {
903
+ throw new Error(
904
+ `Invalid market info response for market ${market}. ` +
905
+ `Expected array with 8 elements, got: ${JSON.stringify(result)}`,
906
+ );
907
+ }
908
+
909
+ return {
910
+ longOpenInterest: result[0],
911
+ shortOpenInterest: result[1],
912
+ fundingRate: result[2],
913
+ lastFundingUpdate: result[3],
914
+ isActive: result[4],
915
+ maxLeverage: result[5],
916
+ maintenanceMargin: result[6],
917
+ liquidationFee: result[7],
918
+ };
919
+ }
920
+
921
+ async getMarketOpenInterest(market: Address): Promise<{ longOI: bigint; shortOI: bigint }> {
922
+ const result = (await this.publicClient.readContract({
923
+ address: this.contractAddress,
924
+ abi: AlphaABI,
925
+ functionName: 'getMarketOpenInterest',
926
+ args: [market],
927
+ })) as any[];
928
+ return {
929
+ longOI: result[0],
930
+ shortOI: result[1],
931
+ };
932
+ }
933
+
934
+ async getFundingRate(market: Address): Promise<bigint> {
935
+ return (await this.publicClient.readContract({
936
+ address: this.contractAddress,
937
+ abi: AlphaABI,
938
+ functionName: 'getFundingRate',
939
+ args: [market],
940
+ })) as bigint;
941
+ }
942
+
943
+ async getFundingState(market: Address): Promise<AlphaTypes.FundingState> {
944
+ const result = (await this.publicClient.readContract({
945
+ address: this.contractAddress,
946
+ abi: AlphaABI,
947
+ functionName: 'getFundingState',
948
+ args: [market],
949
+ })) as any[];
950
+
951
+ // Based on ABI, getFundingState returns:
952
+ // [0] currentRate (int256), [1] cumulativeIndex (int256), [2] lastUpdate (uint256)
953
+ const lastUpdateTime = result[2] !== undefined ? BigInt(result[2]) : 0n;
954
+
955
+ return {
956
+ fundingRate: result[0] || 0n,
957
+ fundingIndex: result[1] || 0n,
958
+ lastUpdateTime: result[2] || 0n,
959
+ nextFundingTime: lastUpdateTime + 8n * 3600n, // Add 8 hours to lastUpdate
960
+ };
961
+ }
962
+
963
+ // ============ Funding Rate Updates (Keeper Function) ============
964
+
965
+ async updateFundingRates(
966
+ markets: Address[],
967
+ options?: TransactionOptions,
968
+ ): Promise<{
969
+ hash: Hash;
970
+ wait: () => Promise<TransactionReceipt>;
971
+ }> {
972
+ if (!this.walletClient) throw new Error('Wallet client required for write operations');
973
+
974
+ const { waitForConfirmation: _waitForConfirmation, ...txOptions } = options || {};
975
+
976
+ if (!this.walletClient.account) {
977
+ throw new Error('Wallet client must have an account for transactions');
978
+ }
979
+
980
+ const hash = await this.walletClient.writeContract({
981
+ address: this.contractAddress,
982
+ abi: AlphaABI,
983
+ functionName: 'updateFundingRates',
984
+ args: [markets],
985
+ account: this.walletClient.account,
986
+ ...txOptions,
987
+ } as any);
988
+
989
+ return {
990
+ hash,
991
+ wait: async () => {
992
+ const receipt = await this.publicClient.waitForTransactionReceipt({ hash });
993
+ return receipt;
994
+ },
995
+ };
996
+ }
997
+
998
+ // ============ View Functions - Orders ============
999
+
1000
+ async getBestBid(market: Address): Promise<AlphaTypes.Bytes16> {
1001
+ return (await this.publicClient.readContract({
1002
+ address: this.contractAddress,
1003
+ abi: AlphaABI,
1004
+ functionName: 'getBestBid',
1005
+ args: [market],
1006
+ })) as AlphaTypes.Bytes16;
1007
+ }
1008
+
1009
+ async getBestAsk(market: Address): Promise<AlphaTypes.Bytes16> {
1010
+ return (await this.publicClient.readContract({
1011
+ address: this.contractAddress,
1012
+ abi: AlphaABI,
1013
+ functionName: 'getBestAsk',
1014
+ args: [market],
1015
+ })) as AlphaTypes.Bytes16;
1016
+ }
1017
+
1018
+ /**
1019
+ * Get all open order IDs for a trader in a specific market
1020
+ * @param trader - Trader address
1021
+ * @param market - Market address
1022
+ * @returns Array of order IDs (bytes16)
1023
+ */
1024
+ async getUserOrders(trader: Address, market: Address): Promise<AlphaTypes.Bytes16[]> {
1025
+ const result = (await this.publicClient.readContract({
1026
+ address: this.contractAddress,
1027
+ abi: AlphaABI,
1028
+ functionName: 'getUserOrders',
1029
+ args: [trader, market],
1030
+ })) as string[];
1031
+ // Convert each bytes32 (padded) to bytes16
1032
+ return result.map((id) => this.bytes32ToBytes16(id) as AlphaTypes.Bytes16);
1033
+ }
1034
+
1035
+ /**
1036
+ * Get details of a specific order
1037
+ * @param market - The market address
1038
+ * @param orderId - The order ID (bytes16)
1039
+ * @returns Order details including trader, direction, size, price, reduceOnly
1040
+ */
1041
+ async getOrderDetails(market: Address, orderId: AlphaTypes.Bytes16): Promise<AlphaTypes.OrderDetails> {
1042
+ const result = (await this.publicClient.readContract({
1043
+ address: this.contractAddress,
1044
+ abi: AlphaABI,
1045
+ functionName: 'getOrderDetails',
1046
+ args: [market, orderId],
1047
+ })) as any;
1048
+
1049
+ // Contract returns a struct with: trader, isLong, notionalValue, price, reduceOnly, next, prev
1050
+ return {
1051
+ trader: result.trader,
1052
+ isLong: result.isLong,
1053
+ notionalValue: result.notionalValue,
1054
+ price: result.price,
1055
+ reduceOnly: result.reduceOnly,
1056
+ next: result.next,
1057
+ prev: result.prev,
1058
+ };
1059
+ }
1060
+
1061
+ // ============ View Functions - Vault ============
1062
+
1063
+ async getVaultStats(): Promise<AlphaTypes.VaultStats> {
1064
+ const result = (await this.publicClient.readContract({
1065
+ address: this.contractAddress,
1066
+ abi: AlphaABI,
1067
+ functionName: 'getVaultStats',
1068
+ args: [],
1069
+ })) as any[];
1070
+ return {
1071
+ totalReserves: result[0],
1072
+ availableReserves: result[1],
1073
+ totalExposure: result[2],
1074
+ unrealizedPnl: result[3],
1075
+ };
1076
+ }
1077
+
1078
+ async getVaultBalance(): Promise<bigint> {
1079
+ return (await this.publicClient.readContract({
1080
+ address: this.contractAddress,
1081
+ abi: AlphaABI,
1082
+ functionName: 'getVaultBalance',
1083
+ args: [],
1084
+ })) as bigint;
1085
+ }
1086
+
1087
+ async getVaultState(): Promise<AlphaTypes.VaultState> {
1088
+ return (await this.publicClient.readContract({
1089
+ address: this.contractAddress,
1090
+ abi: AlphaABI,
1091
+ functionName: 'getVaultState',
1092
+ args: [],
1093
+ })) as AlphaTypes.VaultState;
1094
+ }
1095
+
1096
+ async getVaultExposure(market: Address): Promise<AlphaTypes.VaultExposure> {
1097
+ const result = (await this.publicClient.readContract({
1098
+ address: this.contractAddress,
1099
+ abi: AlphaABI,
1100
+ functionName: 'getVaultExposure',
1101
+ args: [market],
1102
+ })) as any[];
1103
+ return {
1104
+ longExposure: result[0],
1105
+ shortExposure: result[1],
1106
+ netExposure: result[2],
1107
+ utilizationRate: result[3],
1108
+ };
1109
+ }
1110
+
1111
+ // ============ View Functions - Protocol Limits ============
1112
+
1113
+ async getMaxPositionSize(market: Address): Promise<bigint> {
1114
+ return (await this.publicClient.readContract({
1115
+ address: this.contractAddress,
1116
+ abi: AlphaABI,
1117
+ functionName: 'getMaxPositionSize',
1118
+ args: [market],
1119
+ })) as bigint;
1120
+ }
1121
+
1122
+ // ============ View Functions - Execution Analysis ============
1123
+
1124
+ async calculateVaultSlippage(market: Address, size: bigint, isBuy: boolean): Promise<bigint> {
1125
+ return (await this.publicClient.readContract({
1126
+ address: this.contractAddress,
1127
+ abi: AlphaABI,
1128
+ functionName: 'calculateVaultSlippage',
1129
+ args: [market, size, isBuy],
1130
+ })) as bigint;
1131
+ }
1132
+
1133
+ async getOptimalExecutionPlan(
1134
+ market: Address,
1135
+ size: bigint,
1136
+ isLong: boolean,
1137
+ maxSlippage: bigint,
1138
+ ): Promise<AlphaTypes.ExecutionPlan> {
1139
+ return (await this.publicClient.readContract({
1140
+ address: this.contractAddress,
1141
+ abi: AlphaABI,
1142
+ functionName: 'getOptimalExecutionPlan',
1143
+ args: [market, size, isLong, maxSlippage],
1144
+ })) as AlphaTypes.ExecutionPlan;
1145
+ }
1146
+
1147
+ async getExecutionStrategyAnalysis(
1148
+ market: Address,
1149
+ size: bigint,
1150
+ isLong: boolean,
1151
+ maxSlippage: bigint,
1152
+ ): Promise<AlphaTypes.ExecutionStrategyAnalysis> {
1153
+ return (await this.publicClient.readContract({
1154
+ address: this.contractAddress,
1155
+ abi: AlphaABI,
1156
+ functionName: 'getExecutionStrategyAnalysisStruct',
1157
+ args: [market, size, isLong, maxSlippage],
1158
+ })) as AlphaTypes.ExecutionStrategyAnalysis;
1159
+ }
1160
+
1161
+ // ============ View Functions - Market Depth ============
1162
+
1163
+ async getMarketDepth(
1164
+ market: Address,
1165
+ isBuy: boolean,
1166
+ levels: bigint,
1167
+ ): Promise<{ depth: AlphaTypes.DepthLevel[]; totalLiquidity: bigint }> {
1168
+ const result = (await this.publicClient.readContract({
1169
+ address: this.contractAddress,
1170
+ abi: AlphaABI,
1171
+ functionName: 'getMarketDepth',
1172
+ args: [market, isBuy, levels],
1173
+ })) as any[];
1174
+ return {
1175
+ depth: result[0],
1176
+ totalLiquidity: result[1],
1177
+ };
1178
+ }
1179
+
1180
+ async getOrderbookDepth(
1181
+ market: Address,
1182
+ levels: number,
1183
+ ): Promise<{ bidPrices: bigint[]; bidNotionals: bigint[]; askPrices: bigint[]; askNotionals: bigint[] }> {
1184
+ const result = (await this.publicClient.readContract({
1185
+ address: this.contractAddress,
1186
+ abi: AlphaABI,
1187
+ functionName: 'getOrderbookDepth',
1188
+ args: [market, levels],
1189
+ })) as [bigint[], bigint[], bigint[], bigint[]];
1190
+ return {
1191
+ bidPrices: result[0],
1192
+ bidNotionals: result[1],
1193
+ askPrices: result[2],
1194
+ askNotionals: result[3],
1195
+ };
1196
+ }
1197
+
1198
+ async getVWAP(market: Address, size: bigint, isBuy: boolean): Promise<AlphaTypes.VWAPResult> {
1199
+ return (await this.publicClient.readContract({
1200
+ address: this.contractAddress,
1201
+ abi: AlphaABI,
1202
+ functionName: 'getVWAP',
1203
+ args: [market, size, isBuy],
1204
+ })) as AlphaTypes.VWAPResult;
1205
+ }
1206
+
1207
+ async getBidAskSpread(market: Address): Promise<AlphaTypes.SpreadInfo> {
1208
+ return (await this.publicClient.readContract({
1209
+ address: this.contractAddress,
1210
+ abi: AlphaABI,
1211
+ functionName: 'getBidAskSpread',
1212
+ args: [market],
1213
+ })) as AlphaTypes.SpreadInfo;
1214
+ }
1215
+
1216
+ async estimateMarketImpact(
1217
+ market: Address,
1218
+ size: bigint,
1219
+ isBuy: boolean,
1220
+ ): Promise<AlphaTypes.MarketImpactEstimate> {
1221
+ const result = (await this.publicClient.readContract({
1222
+ address: this.contractAddress,
1223
+ abi: AlphaABI,
1224
+ functionName: 'estimateMarketImpact',
1225
+ args: [market, size, isBuy],
1226
+ })) as any[];
1227
+ return {
1228
+ averagePrice: result[0],
1229
+ worstPrice: result[1],
1230
+ priceImpact: result[2],
1231
+ filledFromOrderbook: result[3],
1232
+ };
1233
+ }
1234
+
1235
+ async getMarketLiquidityAnalysis(market: Address): Promise<AlphaTypes.MarketLiquidityAnalysis> {
1236
+ return (await this.publicClient.readContract({
1237
+ address: this.contractAddress,
1238
+ abi: AlphaABI,
1239
+ functionName: 'getMarketLiquidityAnalysisStruct',
1240
+ args: [market],
1241
+ })) as AlphaTypes.MarketLiquidityAnalysis;
1242
+ }
1243
+
1244
+ // ============ Event Parsing ============
1245
+
1246
+ parsePositionOpenedEvent(
1247
+ receipt: TransactionReceipt,
1248
+ ): AlphaTypes.PositionOpenedEvent | undefined {
1249
+ const logs = parseEventLogs({
1250
+ abi: AlphaABI,
1251
+ logs: receipt.logs,
1252
+ eventName: 'PositionOpened',
1253
+ });
1254
+
1255
+ if (logs.length > 0) {
1256
+ const event = logs[0] as any;
1257
+ // Convert bytes32 (padded) back to bytes16
1258
+ const positionId = this.bytes32ToBytes16(event.args.positionId);
1259
+ return {
1260
+ positionId: positionId,
1261
+ trader: event.args.trader,
1262
+ market: event.args.market,
1263
+ isLong: event.args.isLong,
1264
+ notionalValue: event.args.notionalValue,
1265
+ margin: event.args.margin,
1266
+ };
1267
+ }
1268
+ return undefined;
1269
+ }
1270
+
1271
+ parsePositionClosedEvent(
1272
+ receipt: TransactionReceipt,
1273
+ ): AlphaTypes.PositionClosedEvent | undefined {
1274
+ const logs = parseEventLogs({
1275
+ abi: AlphaABI,
1276
+ logs: receipt.logs,
1277
+ eventName: 'PositionClosed',
1278
+ });
1279
+
1280
+ if (logs.length > 0) {
1281
+ const event = logs[0] as any;
1282
+ // Convert bytes32 (padded) back to bytes16
1283
+ const positionId = this.bytes32ToBytes16(event.args.positionId);
1284
+ return {
1285
+ positionId: positionId,
1286
+ trader: event.args.trader,
1287
+ pnl: event.args.pnl,
1288
+ };
1289
+ }
1290
+ return undefined;
1291
+ }
1292
+
1293
+ parseOrderPlacedEvent(receipt: TransactionReceipt): AlphaTypes.OrderPlacedEvent | undefined {
1294
+ const logs = parseEventLogs({
1295
+ abi: AlphaABI,
1296
+ logs: receipt.logs,
1297
+ eventName: 'OrderPlaced',
1298
+ });
1299
+
1300
+ if (logs.length > 0) {
1301
+ const event = logs[0] as any;
1302
+ return {
1303
+ orderId: event.args.orderId,
1304
+ trader: event.args.trader,
1305
+ market: event.args.market,
1306
+ isBuy: event.args.isBuy,
1307
+ notionalValue: event.args.notionalValue,
1308
+ price: event.args.price,
1309
+ };
1310
+ }
1311
+ return undefined;
1312
+ }
1313
+
1314
+ parseHybridOrderExecutedEvent(
1315
+ receipt: TransactionReceipt,
1316
+ ): AlphaTypes.HybridOrderExecutedEvent | undefined {
1317
+ const logs = parseEventLogs({
1318
+ abi: AlphaABI,
1319
+ logs: receipt.logs,
1320
+ eventName: 'HybridOrderExecuted',
1321
+ });
1322
+
1323
+ if (logs.length > 0) {
1324
+ const event = logs[0] as any;
1325
+ return {
1326
+ trader: event.args.trader,
1327
+ market: event.args.market,
1328
+ orderbookFilled: event.args.orderbookFilled,
1329
+ vaultFilled: event.args.vaultFilled,
1330
+ avgPrice: event.args.avgPrice,
1331
+ };
1332
+ }
1333
+ return undefined;
1334
+ }
1335
+
1336
+ // ============ Helper Functions ============
1337
+
1338
+ async waitForTransaction(hash: Hash): Promise<TransactionReceipt> {
1339
+ return this.publicClient.waitForTransactionReceipt({ hash });
1340
+ }
1341
+
1342
+ getContractAddress(): Address {
1343
+ return this.contractAddress;
1344
+ }
1345
+
1346
+ // Generic readContract method for custom function calls
1347
+ async readContract({ functionName, args }: { functionName: string; args: any[] }): Promise<any> {
1348
+ return await this.publicClient.readContract({
1349
+ address: this.contractAddress,
1350
+ abi: AlphaABI,
1351
+ functionName,
1352
+ args,
1353
+ });
1354
+ }
1355
+
1356
+ async getConstants(): Promise<AlphaTypes.MonolithConfig> {
1357
+ const [
1358
+ precision,
1359
+ basisPoints,
1360
+ maxLeverage,
1361
+ defaultLeverage,
1362
+ minPositionSize,
1363
+ liquidationThreshold,
1364
+ partialLiquidationThreshold,
1365
+ liquidationFee,
1366
+ fundingInterval,
1367
+ maxFundingRate,
1368
+ maxExposurePerAsset,
1369
+ maxTotalUtilization,
1370
+ criticalUtilizationBps,
1371
+ maxLossRateBps,
1372
+ maxLiquidationsPerBlock,
1373
+ ] = await Promise.all([
1374
+ this.publicClient.readContract({
1375
+ address: this.contractAddress,
1376
+ abi: AlphaABI,
1377
+ functionName: 'PRECISION',
1378
+ args: [],
1379
+ }) as Promise<bigint>,
1380
+ this.publicClient.readContract({
1381
+ address: this.contractAddress,
1382
+ abi: AlphaABI,
1383
+ functionName: 'BASIS_POINTS',
1384
+ args: [],
1385
+ }) as Promise<bigint>,
1386
+ this.publicClient.readContract({
1387
+ address: this.contractAddress,
1388
+ abi: AlphaABI,
1389
+ functionName: 'MAX_LEVERAGE',
1390
+ args: [],
1391
+ }) as Promise<bigint>,
1392
+ this.publicClient.readContract({
1393
+ address: this.contractAddress,
1394
+ abi: AlphaABI,
1395
+ functionName: 'DEFAULT_LEVERAGE',
1396
+ args: [],
1397
+ }) as Promise<bigint>,
1398
+ this.publicClient.readContract({
1399
+ address: this.contractAddress,
1400
+ abi: AlphaABI,
1401
+ functionName: 'MIN_POSITION_SIZE',
1402
+ args: [],
1403
+ }) as Promise<bigint>,
1404
+ this.publicClient.readContract({
1405
+ address: this.contractAddress,
1406
+ abi: AlphaABI,
1407
+ functionName: 'LIQUIDATION_THRESHOLD',
1408
+ args: [],
1409
+ }) as Promise<bigint>,
1410
+ this.publicClient.readContract({
1411
+ address: this.contractAddress,
1412
+ abi: AlphaABI,
1413
+ functionName: 'PARTIAL_LIQUIDATION_THRESHOLD',
1414
+ args: [],
1415
+ }) as Promise<bigint>,
1416
+ this.publicClient.readContract({
1417
+ address: this.contractAddress,
1418
+ abi: AlphaABI,
1419
+ functionName: 'LIQUIDATION_FEE',
1420
+ args: [],
1421
+ }) as Promise<bigint>,
1422
+ this.publicClient.readContract({
1423
+ address: this.contractAddress,
1424
+ abi: AlphaABI,
1425
+ functionName: 'FUNDING_INTERVAL',
1426
+ args: [],
1427
+ }) as Promise<bigint>,
1428
+ this.publicClient.readContract({
1429
+ address: this.contractAddress,
1430
+ abi: AlphaABI,
1431
+ functionName: 'MAX_FUNDING_RATE',
1432
+ args: [],
1433
+ }) as Promise<bigint>,
1434
+ this.publicClient.readContract({
1435
+ address: this.contractAddress,
1436
+ abi: AlphaABI,
1437
+ functionName: 'MAX_EXPOSURE_PER_ASSET',
1438
+ args: [],
1439
+ }) as Promise<bigint>,
1440
+ this.publicClient.readContract({
1441
+ address: this.contractAddress,
1442
+ abi: AlphaABI,
1443
+ functionName: 'MAX_TOTAL_UTILIZATION',
1444
+ args: [],
1445
+ }) as Promise<bigint>,
1446
+ this.publicClient.readContract({
1447
+ address: this.contractAddress,
1448
+ abi: AlphaABI,
1449
+ functionName: 'CRITICAL_UTILIZATION_BPS',
1450
+ args: [],
1451
+ }) as Promise<bigint>,
1452
+ this.publicClient.readContract({
1453
+ address: this.contractAddress,
1454
+ abi: AlphaABI,
1455
+ functionName: 'MAX_LOSS_RATE_BPS',
1456
+ args: [],
1457
+ }) as Promise<bigint>,
1458
+ this.publicClient.readContract({
1459
+ address: this.contractAddress,
1460
+ abi: AlphaABI,
1461
+ functionName: 'MAX_LIQUIDATIONS_PER_BLOCK',
1462
+ args: [],
1463
+ }) as Promise<bigint>,
1464
+ ]);
1465
+
1466
+ return {
1467
+ precision,
1468
+ basisPoints,
1469
+ maxLeverage,
1470
+ defaultLeverage,
1471
+ minPositionSize,
1472
+ liquidationThreshold,
1473
+ partialLiquidationThreshold,
1474
+ liquidationFee,
1475
+ fundingInterval,
1476
+ maxFundingRate,
1477
+ maxExposurePerAsset,
1478
+ maxTotalUtilization,
1479
+ criticalUtilizationBps,
1480
+ maxLossRateBps,
1481
+ maxLiquidationsPerBlock,
1482
+ };
1483
+ }
1484
+
1485
+ // Event watching methods
1486
+
1487
+ /**
1488
+ * Watch for MarginDeposited events
1489
+ */
1490
+ watchMarginDepositedEvent(callback: (trader: Address, amount: bigint) => void) {
1491
+ return this.publicClient.watchContractEvent({
1492
+ address: this.contractAddress,
1493
+ abi: AlphaABI,
1494
+ eventName: 'MarginDeposited',
1495
+ onLogs: (logs) => {
1496
+ for (const log of logs) {
1497
+ const { trader, amount } = (log as any).args as { trader: Address; amount: bigint };
1498
+ callback(trader, amount);
1499
+ }
1500
+ },
1501
+ });
1502
+ }
1503
+
1504
+ /**
1505
+ * Watch for MarginWithdrawn events
1506
+ */
1507
+ watchMarginWithdrawnEvent(callback: (trader: Address, amount: bigint) => void) {
1508
+ return this.publicClient.watchContractEvent({
1509
+ address: this.contractAddress,
1510
+ abi: AlphaABI,
1511
+ eventName: 'MarginWithdrawn',
1512
+ onLogs: (logs) => {
1513
+ for (const log of logs) {
1514
+ const { trader, amount } = (log as any).args as { trader: Address; amount: bigint };
1515
+ callback(trader, amount);
1516
+ }
1517
+ },
1518
+ });
1519
+ }
1520
+
1521
+ /**
1522
+ * Watch for PositionOpened events
1523
+ */
1524
+ watchPositionOpenedEvent(
1525
+ callback: (
1526
+ positionId: `0x${string}`,
1527
+ trader: Address,
1528
+ market: Address,
1529
+ isLong: boolean,
1530
+ notionalValue: bigint,
1531
+ entryPrice: bigint,
1532
+ margin: bigint,
1533
+ ) => void,
1534
+ ) {
1535
+ return this.publicClient.watchContractEvent({
1536
+ address: this.contractAddress,
1537
+ abi: AlphaABI,
1538
+ eventName: 'PositionOpened',
1539
+ onLogs: (logs) => {
1540
+ for (const log of logs) {
1541
+ const { positionId, trader, market, isLong, notionalValue, entryPrice, margin } = (
1542
+ log as any
1543
+ ).args as any;
1544
+ callback(positionId, trader, market, isLong, notionalValue, entryPrice, margin);
1545
+ }
1546
+ },
1547
+ });
1548
+ }
1549
+
1550
+ /**
1551
+ * Get past MarginDeposited events
1552
+ */
1553
+ async getMarginDepositedEvents(fromBlock?: bigint, toBlock?: bigint, trader?: Address) {
1554
+ return await this.publicClient.getContractEvents({
1555
+ address: this.contractAddress,
1556
+ abi: AlphaABI,
1557
+ eventName: 'MarginDeposited',
1558
+ fromBlock: fromBlock || 'earliest',
1559
+ toBlock: toBlock || 'latest',
1560
+ args: trader ? { trader } : undefined,
1561
+ });
1562
+ }
1563
+
1564
+ /**
1565
+ * Get past MarginWithdrawn events
1566
+ */
1567
+ async getMarginWithdrawnEvents(fromBlock?: bigint, toBlock?: bigint, trader?: Address) {
1568
+ return await this.publicClient.getContractEvents({
1569
+ address: this.contractAddress,
1570
+ abi: AlphaABI,
1571
+ eventName: 'MarginWithdrawn',
1572
+ fromBlock: fromBlock || 'earliest',
1573
+ toBlock: toBlock || 'latest',
1574
+ args: trader ? { trader } : undefined,
1575
+ });
1576
+ }
1577
+
1578
+ /**
1579
+ * Get past PositionOpened events
1580
+ */
1581
+ async getPositionOpenedEvents(fromBlock?: bigint, toBlock?: bigint, trader?: Address) {
1582
+ return await this.publicClient.getContractEvents({
1583
+ address: this.contractAddress,
1584
+ abi: AlphaABI,
1585
+ eventName: 'PositionOpened',
1586
+ fromBlock: fromBlock || 'earliest',
1587
+ toBlock: toBlock || 'latest',
1588
+ args: trader ? { trader } : undefined,
1589
+ });
1590
+ }
1591
+
1592
+ /**
1593
+ * Estimate gas for a transaction
1594
+ */
1595
+ async estimateGas(
1596
+ functionName: string,
1597
+ args: any[],
1598
+ options?: TransactionOptions,
1599
+ ): Promise<bigint> {
1600
+ if (!this.walletClient) {
1601
+ throw new Error('Wallet client is required for gas estimation');
1602
+ }
1603
+
1604
+ const { gasPrice: _gasPrice, waitForConfirmation: _waitForConfirmation, ...estimateOptions } = options || {};
1605
+
1606
+ return await this.publicClient.estimateContractGas({
1607
+ address: this.contractAddress,
1608
+ abi: AlphaABI,
1609
+ functionName,
1610
+ args,
1611
+ account: this.walletClient.account,
1612
+ ...estimateOptions,
1613
+ });
1614
+ }
1615
+ }