@vultisig/rujira 12.0.0 → 13.0.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.
@@ -1,214 +0,0 @@
1
- /**
2
- * Perpetual futures module for Levana perps on Rujira
3
- * @module modules/perps
4
- */
5
- import { RujiraError, RujiraErrorCode, wrapError } from '../errors.js';
6
- import { isPositiveBigInt, isPositiveNumber } from '../utils/format.js';
7
- // GraphQL endpoint
8
- const RUJIRA_GRAPHQL_URL = 'https://api.rujira.network/api/graphql';
9
- const PERPS_MARKETS_QUERY = `
10
- {
11
- perps {
12
- id
13
- name
14
- address
15
- baseAsset { asset }
16
- quoteAsset { asset }
17
- }
18
- }
19
- `;
20
- /**
21
- * Levana perpetual futures module.
22
- *
23
- * @example
24
- * ```typescript
25
- * const client = new RujiraClient();
26
- * await client.connect();
27
- *
28
- * // List markets
29
- * const markets = await client.perps.getMarkets();
30
- *
31
- * // Build open position
32
- * const tx = client.perps.buildOpenPosition({
33
- * market: 'thor1cyd6...',
34
- * direction: 'long',
35
- * leverage: '10',
36
- * collateralDenom: 'eth-usdc-0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
37
- * collateralAmount: '100000000',
38
- * });
39
- * ```
40
- */
41
- export class RujiraPerps {
42
- constructor(client) {
43
- this.client = client;
44
- }
45
- // --- Market Discovery ---
46
- /**
47
- * Get available perps markets from GraphQL.
48
- */
49
- async getMarkets() {
50
- try {
51
- const response = await fetch(RUJIRA_GRAPHQL_URL, {
52
- method: 'POST',
53
- headers: { 'Content-Type': 'application/json' },
54
- body: JSON.stringify({ query: PERPS_MARKETS_QUERY }),
55
- });
56
- if (!response.ok) {
57
- throw new RujiraError(RujiraErrorCode.NETWORK_ERROR, `GraphQL request failed: ${response.status}`);
58
- }
59
- const json = (await response.json());
60
- if (json.errors?.length) {
61
- throw new RujiraError(RujiraErrorCode.NETWORK_ERROR, `GraphQL errors: ${json.errors[0].message}`);
62
- }
63
- return (json.data?.perps ?? []).map(m => ({
64
- address: m.address,
65
- name: m.name,
66
- baseAsset: m.baseAsset.asset,
67
- quoteAsset: m.quoteAsset.asset,
68
- }));
69
- }
70
- catch (error) {
71
- throw wrapError(error);
72
- }
73
- }
74
- // --- Market Queries ---
75
- /**
76
- * Query market status from the Levana contract.
77
- */
78
- async getMarketStatus(marketAddress) {
79
- try {
80
- return await this.client.queryContract(marketAddress, { status: { price: null } });
81
- }
82
- catch (error) {
83
- throw wrapError(error);
84
- }
85
- }
86
- /**
87
- * Query positions for an owner on a market.
88
- */
89
- async getPositions(marketAddress, owner) {
90
- try {
91
- return await this.client.queryContract(marketAddress, {
92
- positions: { owner, start_after: null, limit: 50 },
93
- });
94
- }
95
- catch (error) {
96
- throw wrapError(error);
97
- }
98
- }
99
- /**
100
- * Query limit orders for an owner on a market.
101
- */
102
- async getLimitOrders(marketAddress, owner) {
103
- try {
104
- return await this.client.queryContract(marketAddress, {
105
- limit_orders: { owner, start_after: null, limit: 50 },
106
- });
107
- }
108
- catch (error) {
109
- throw wrapError(error);
110
- }
111
- }
112
- // --- Position Management ---
113
- /**
114
- * Build open position transaction.
115
- */
116
- buildOpenPosition(params) {
117
- if (!params.leverage || !isPositiveNumber(params.leverage)) {
118
- throw new RujiraError(RujiraErrorCode.INVALID_AMOUNT, 'Leverage must be a positive number string (e.g. "2", "1.5")');
119
- }
120
- if (!params.collateralAmount || !isPositiveBigInt(params.collateralAmount)) {
121
- throw new RujiraError(RujiraErrorCode.INVALID_AMOUNT, 'Collateral amount must be a positive integer string');
122
- }
123
- return {
124
- contractAddress: params.market,
125
- executeMsg: {
126
- open_position: {
127
- slippage_assert: null,
128
- leverage: params.leverage,
129
- direction: params.direction,
130
- stop_loss_override: params.stopLoss ?? null,
131
- take_profit: params.takeProfit ?? '+Inf',
132
- },
133
- },
134
- funds: [{ denom: params.collateralDenom, amount: params.collateralAmount }],
135
- };
136
- }
137
- /**
138
- * Build close position transaction.
139
- */
140
- buildClosePosition(params) {
141
- return {
142
- contractAddress: params.market,
143
- executeMsg: { close_position: { id: params.positionId, slippage_assert: null } },
144
- funds: [],
145
- };
146
- }
147
- /**
148
- * Build update take profit transaction.
149
- */
150
- buildUpdateTakeProfit(params) {
151
- return {
152
- contractAddress: params.market,
153
- executeMsg: { update_position_take_profit_price: { id: params.positionId, price: params.price } },
154
- funds: [],
155
- };
156
- }
157
- /**
158
- * Build update stop loss transaction.
159
- */
160
- buildUpdateStopLoss(params) {
161
- return {
162
- contractAddress: params.market,
163
- executeMsg: { update_position_stop_loss_price: { id: params.positionId, stop_loss: params.stopLoss } },
164
- funds: [],
165
- };
166
- }
167
- /**
168
- * Build add collateral transaction.
169
- */
170
- buildAddCollateral(params) {
171
- if (!params.amount || !isPositiveBigInt(params.amount)) {
172
- throw new RujiraError(RujiraErrorCode.INVALID_AMOUNT, 'Collateral amount must be a positive integer string');
173
- }
174
- return {
175
- contractAddress: params.market,
176
- executeMsg: { update_position_add_collateral_impact_leverage: { id: params.positionId } },
177
- funds: [{ denom: params.denom, amount: params.amount }],
178
- };
179
- }
180
- /**
181
- * Build place limit order transaction.
182
- */
183
- buildPlaceLimitOrder(params) {
184
- if (!params.leverage || !isPositiveNumber(params.leverage)) {
185
- throw new RujiraError(RujiraErrorCode.INVALID_AMOUNT, 'Leverage must be a positive number string (e.g. "2", "1.5")');
186
- }
187
- if (!params.collateralAmount || !isPositiveBigInt(params.collateralAmount)) {
188
- throw new RujiraError(RujiraErrorCode.INVALID_AMOUNT, 'Collateral amount must be a positive integer string');
189
- }
190
- return {
191
- contractAddress: params.market,
192
- executeMsg: {
193
- place_limit_order: {
194
- trigger_price: params.triggerPrice,
195
- leverage: params.leverage,
196
- direction: params.direction,
197
- stop_loss_override: params.stopLoss ?? null,
198
- take_profit: params.takeProfit ?? '+Inf',
199
- },
200
- },
201
- funds: [{ denom: params.collateralDenom, amount: params.collateralAmount }],
202
- };
203
- }
204
- /**
205
- * Build cancel limit order transaction.
206
- */
207
- buildCancelLimitOrder(params) {
208
- return {
209
- contractAddress: params.market,
210
- executeMsg: { cancel_limit_order: { order_id: params.orderId } },
211
- funds: [],
212
- };
213
- }
214
- }