@trufnetwork/sdk-js 0.5.9 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +45 -0
- package/dist/cjs/client/client.cjs +45 -20
- package/dist/cjs/client/client.cjs.map +2 -2
- package/dist/cjs/contracts-api/action.cjs +51 -26
- package/dist/cjs/contracts-api/action.cjs.map +2 -2
- package/dist/cjs/contracts-api/orderbookAction.cjs +880 -0
- package/dist/cjs/contracts-api/orderbookAction.cjs.map +7 -0
- package/dist/cjs/internal.cjs +9 -0
- package/dist/cjs/internal.cjs.map +2 -2
- package/dist/cjs/types/bridge.cjs.map +1 -1
- package/dist/cjs/types/orderbook.cjs +19 -0
- package/dist/cjs/types/orderbook.cjs.map +7 -0
- package/dist/cjs/util/AttestationEncoding.cjs +3 -2
- package/dist/cjs/util/AttestationEncoding.cjs.map +2 -2
- package/dist/cjs/util/orderbookHelpers.cjs +194 -0
- package/dist/cjs/util/orderbookHelpers.cjs.map +7 -0
- package/dist/cjs/util/orderbookHelpers.test.cjs +217 -0
- package/dist/cjs/util/orderbookHelpers.test.cjs.map +7 -0
- package/dist/esm/client/client.mjs +45 -20
- package/dist/esm/client/client.mjs.map +2 -2
- package/dist/esm/contracts-api/action.mjs +51 -26
- package/dist/esm/contracts-api/action.mjs.map +2 -2
- package/dist/esm/contracts-api/orderbookAction.mjs +875 -0
- package/dist/esm/contracts-api/orderbookAction.mjs.map +7 -0
- package/dist/esm/internal.mjs +16 -0
- package/dist/esm/internal.mjs.map +2 -2
- package/dist/esm/types/orderbook.mjs +1 -0
- package/dist/esm/types/orderbook.mjs.map +7 -0
- package/dist/esm/util/AttestationEncoding.mjs +3 -2
- package/dist/esm/util/AttestationEncoding.mjs.map +2 -2
- package/dist/esm/util/orderbookHelpers.mjs +173 -0
- package/dist/esm/util/orderbookHelpers.mjs.map +7 -0
- package/dist/esm/util/orderbookHelpers.test.mjs +229 -0
- package/dist/esm/util/orderbookHelpers.test.mjs.map +7 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/types/client/client.d.ts +36 -16
- package/dist/types/client/client.d.ts.map +1 -1
- package/dist/types/contracts-api/action.d.ts +47 -22
- package/dist/types/contracts-api/action.d.ts.map +1 -1
- package/dist/types/contracts-api/orderbookAction.d.ts +303 -0
- package/dist/types/contracts-api/orderbookAction.d.ts.map +1 -0
- package/dist/types/internal.d.ts +3 -0
- package/dist/types/internal.d.ts.map +1 -1
- package/dist/types/types/bridge.d.ts +3 -2
- package/dist/types/types/bridge.d.ts.map +1 -1
- package/dist/types/types/orderbook.d.ts +376 -0
- package/dist/types/types/orderbook.d.ts.map +1 -0
- package/dist/types/util/AttestationEncoding.d.ts +9 -1
- package/dist/types/util/AttestationEncoding.d.ts.map +1 -1
- package/dist/types/util/orderbookHelpers.d.ts +161 -0
- package/dist/types/util/orderbookHelpers.d.ts.map +1 -0
- package/dist/types/util/orderbookHelpers.test.d.ts +2 -0
- package/dist/types/util/orderbookHelpers.test.d.ts.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,875 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
|
+
|
|
5
|
+
// src/contracts-api/orderbookAction.ts
|
|
6
|
+
import {
|
|
7
|
+
encodeActionArgs,
|
|
8
|
+
encodeQueryComponents,
|
|
9
|
+
encodeRangeActionArgs,
|
|
10
|
+
encodeEqualsActionArgs,
|
|
11
|
+
dbBytesToUint8Array,
|
|
12
|
+
validatePrice,
|
|
13
|
+
validateAmount,
|
|
14
|
+
validateBridge,
|
|
15
|
+
validateMaxSpread,
|
|
16
|
+
validateSettleTime,
|
|
17
|
+
settledFilterToBoolean
|
|
18
|
+
} from "../util/orderbookHelpers.mjs";
|
|
19
|
+
var OrderbookAction = class {
|
|
20
|
+
constructor(kwilClient, kwilSigner) {
|
|
21
|
+
__publicField(this, "kwilClient");
|
|
22
|
+
__publicField(this, "kwilSigner");
|
|
23
|
+
this.kwilClient = kwilClient;
|
|
24
|
+
this.kwilSigner = kwilSigner;
|
|
25
|
+
}
|
|
26
|
+
// ==========================================
|
|
27
|
+
// Market Operations
|
|
28
|
+
// ==========================================
|
|
29
|
+
/**
|
|
30
|
+
* Creates a new binary prediction market.
|
|
31
|
+
*
|
|
32
|
+
* @param input - Market creation parameters
|
|
33
|
+
* @returns Transaction receipt with tx_hash
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```typescript
|
|
37
|
+
* const args = OrderbookAction.encodeActionArgs(
|
|
38
|
+
* dataProvider, streamId, timestamp, threshold, frozenAt
|
|
39
|
+
* );
|
|
40
|
+
* const queryComponents = OrderbookAction.encodeQueryComponents(
|
|
41
|
+
* dataProvider, streamId, "price_above_threshold", args
|
|
42
|
+
* );
|
|
43
|
+
*
|
|
44
|
+
* const result = await orderbook.createMarket({
|
|
45
|
+
* bridge: "hoodi_tt2",
|
|
46
|
+
* queryComponents,
|
|
47
|
+
* settleTime: Math.floor(Date.now() / 1000) + 3600,
|
|
48
|
+
* maxSpread: 10,
|
|
49
|
+
* minOrderSize: 1,
|
|
50
|
+
* });
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
async createMarket(input) {
|
|
54
|
+
validateBridge(input.bridge);
|
|
55
|
+
validateMaxSpread(input.maxSpread);
|
|
56
|
+
validateSettleTime(input.settleTime);
|
|
57
|
+
return this.kwilClient.execute(
|
|
58
|
+
{
|
|
59
|
+
namespace: "main",
|
|
60
|
+
name: "create_market",
|
|
61
|
+
inputs: [
|
|
62
|
+
{
|
|
63
|
+
$bridge: input.bridge,
|
|
64
|
+
$query_components: input.queryComponents,
|
|
65
|
+
$settle_time: input.settleTime,
|
|
66
|
+
$max_spread: input.maxSpread,
|
|
67
|
+
$min_order_size: input.minOrderSize
|
|
68
|
+
}
|
|
69
|
+
],
|
|
70
|
+
description: "TN SDK - Create market"
|
|
71
|
+
},
|
|
72
|
+
this.kwilSigner
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Gets detailed information about a market.
|
|
77
|
+
*
|
|
78
|
+
* @param queryId - Market identifier
|
|
79
|
+
* @returns Full market information
|
|
80
|
+
*/
|
|
81
|
+
async getMarketInfo(queryId) {
|
|
82
|
+
const result = await this.kwilClient.call(
|
|
83
|
+
{
|
|
84
|
+
namespace: "main",
|
|
85
|
+
name: "get_market_info",
|
|
86
|
+
inputs: { $query_id: queryId }
|
|
87
|
+
},
|
|
88
|
+
this.kwilSigner
|
|
89
|
+
);
|
|
90
|
+
if (result.status !== 200) {
|
|
91
|
+
throw new Error(`Failed to get market info: ${result.status}`);
|
|
92
|
+
}
|
|
93
|
+
const rows = result.data?.result;
|
|
94
|
+
if (!rows || rows.length === 0) {
|
|
95
|
+
throw new Error(`Market not found: ${queryId}`);
|
|
96
|
+
}
|
|
97
|
+
return this.parseMarketInfo(rows[0], queryId);
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Gets market information by query hash.
|
|
101
|
+
*
|
|
102
|
+
* @param queryHash - SHA256 hash of query components (32 bytes)
|
|
103
|
+
* @returns Full market information
|
|
104
|
+
*/
|
|
105
|
+
async getMarketByHash(queryHash) {
|
|
106
|
+
if (queryHash.length !== 32) {
|
|
107
|
+
throw new Error("Query hash must be exactly 32 bytes");
|
|
108
|
+
}
|
|
109
|
+
const result = await this.kwilClient.call(
|
|
110
|
+
{
|
|
111
|
+
namespace: "main",
|
|
112
|
+
name: "get_market_by_hash",
|
|
113
|
+
inputs: { $query_hash: queryHash }
|
|
114
|
+
},
|
|
115
|
+
this.kwilSigner
|
|
116
|
+
);
|
|
117
|
+
if (result.status !== 200) {
|
|
118
|
+
throw new Error(`Failed to get market by hash: ${result.status}`);
|
|
119
|
+
}
|
|
120
|
+
const rows = result.data?.result;
|
|
121
|
+
if (!rows || rows.length === 0) {
|
|
122
|
+
throw new Error("Market not found for given hash");
|
|
123
|
+
}
|
|
124
|
+
return this.parseMarketInfo(rows[0]);
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Lists markets with optional filtering.
|
|
128
|
+
*
|
|
129
|
+
* @param input - Filter and pagination options
|
|
130
|
+
* @returns Array of market summaries
|
|
131
|
+
*/
|
|
132
|
+
async listMarkets(input) {
|
|
133
|
+
const settledFilter = settledFilterToBoolean(input?.settledFilter);
|
|
134
|
+
const result = await this.kwilClient.call(
|
|
135
|
+
{
|
|
136
|
+
namespace: "main",
|
|
137
|
+
name: "list_markets",
|
|
138
|
+
inputs: {
|
|
139
|
+
$settled_filter: settledFilter,
|
|
140
|
+
$limit_val: input?.limit ?? 100,
|
|
141
|
+
$offset_val: input?.offset ?? 0
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
this.kwilSigner
|
|
145
|
+
);
|
|
146
|
+
if (result.status !== 200) {
|
|
147
|
+
throw new Error(`Failed to list markets: ${result.status}`);
|
|
148
|
+
}
|
|
149
|
+
const rows = result.data?.result || [];
|
|
150
|
+
return rows.map((row) => this.parseMarketSummary(row));
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Checks if a market exists for the given query hash.
|
|
154
|
+
*
|
|
155
|
+
* @param queryHash - SHA256 hash of query components (32 bytes)
|
|
156
|
+
* @returns true if market exists
|
|
157
|
+
*/
|
|
158
|
+
async marketExists(queryHash) {
|
|
159
|
+
if (queryHash.length !== 32) {
|
|
160
|
+
throw new Error("Query hash must be exactly 32 bytes");
|
|
161
|
+
}
|
|
162
|
+
const result = await this.kwilClient.call(
|
|
163
|
+
{
|
|
164
|
+
namespace: "main",
|
|
165
|
+
name: "market_exists",
|
|
166
|
+
inputs: { $query_hash: queryHash }
|
|
167
|
+
},
|
|
168
|
+
this.kwilSigner
|
|
169
|
+
);
|
|
170
|
+
if (result.status !== 200) {
|
|
171
|
+
throw new Error(`Failed to check market exists: ${result.status}`);
|
|
172
|
+
}
|
|
173
|
+
const rows = result.data?.result;
|
|
174
|
+
return rows && rows.length > 0 && rows[0].exists;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Validates market collateral integrity.
|
|
178
|
+
*
|
|
179
|
+
* Checks that:
|
|
180
|
+
* - YES and NO token counts match (binary pairs)
|
|
181
|
+
* - Vault balance matches expected collateral
|
|
182
|
+
*
|
|
183
|
+
* @param queryId - Market identifier
|
|
184
|
+
* @returns Validation result with detailed breakdown
|
|
185
|
+
*/
|
|
186
|
+
async validateMarketCollateral(queryId) {
|
|
187
|
+
const result = await this.kwilClient.call(
|
|
188
|
+
{
|
|
189
|
+
namespace: "main",
|
|
190
|
+
name: "validate_market_collateral",
|
|
191
|
+
inputs: { $query_id: queryId }
|
|
192
|
+
},
|
|
193
|
+
this.kwilSigner
|
|
194
|
+
);
|
|
195
|
+
if (result.status !== 200) {
|
|
196
|
+
throw new Error(`Failed to validate market collateral: ${result.status}`);
|
|
197
|
+
}
|
|
198
|
+
const rows = result.data?.result;
|
|
199
|
+
if (!rows || rows.length === 0) {
|
|
200
|
+
throw new Error(`Market not found: ${queryId}`);
|
|
201
|
+
}
|
|
202
|
+
const row = rows[0];
|
|
203
|
+
return {
|
|
204
|
+
validTokenBinaries: row.valid_token_binaries,
|
|
205
|
+
validCollateral: row.valid_collateral,
|
|
206
|
+
totalTrue: row.total_true,
|
|
207
|
+
totalFalse: row.total_false,
|
|
208
|
+
vaultBalance: row.vault_balance,
|
|
209
|
+
expectedCollateral: row.expected_collateral,
|
|
210
|
+
openBuysValue: row.open_buys_value
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
// ==========================================
|
|
214
|
+
// Order Placement Operations
|
|
215
|
+
// ==========================================
|
|
216
|
+
/**
|
|
217
|
+
* Places a buy order for shares.
|
|
218
|
+
*
|
|
219
|
+
* Locks collateral: amount × price × 10^16 wei
|
|
220
|
+
*
|
|
221
|
+
* @param input - Order parameters
|
|
222
|
+
* @returns Transaction receipt
|
|
223
|
+
*/
|
|
224
|
+
async placeBuyOrder(input) {
|
|
225
|
+
validatePrice(input.price, "placeBuyOrder");
|
|
226
|
+
validateAmount(input.amount, "placeBuyOrder");
|
|
227
|
+
return this.kwilClient.execute(
|
|
228
|
+
{
|
|
229
|
+
namespace: "main",
|
|
230
|
+
name: "place_buy_order",
|
|
231
|
+
inputs: [
|
|
232
|
+
{
|
|
233
|
+
$query_id: input.queryId,
|
|
234
|
+
$outcome: input.outcome,
|
|
235
|
+
$price: input.price,
|
|
236
|
+
$amount: input.amount
|
|
237
|
+
}
|
|
238
|
+
],
|
|
239
|
+
description: "TN SDK - Place buy order"
|
|
240
|
+
},
|
|
241
|
+
this.kwilSigner
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Places a sell order for owned shares.
|
|
246
|
+
*
|
|
247
|
+
* @param input - Order parameters
|
|
248
|
+
* @returns Transaction receipt
|
|
249
|
+
*/
|
|
250
|
+
async placeSellOrder(input) {
|
|
251
|
+
validatePrice(input.price, "placeSellOrder");
|
|
252
|
+
validateAmount(input.amount, "placeSellOrder");
|
|
253
|
+
return this.kwilClient.execute(
|
|
254
|
+
{
|
|
255
|
+
namespace: "main",
|
|
256
|
+
name: "place_sell_order",
|
|
257
|
+
inputs: [
|
|
258
|
+
{
|
|
259
|
+
$query_id: input.queryId,
|
|
260
|
+
$outcome: input.outcome,
|
|
261
|
+
$price: input.price,
|
|
262
|
+
$amount: input.amount
|
|
263
|
+
}
|
|
264
|
+
],
|
|
265
|
+
description: "TN SDK - Place sell order"
|
|
266
|
+
},
|
|
267
|
+
this.kwilSigner
|
|
268
|
+
);
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Places a split limit order for market making.
|
|
272
|
+
*
|
|
273
|
+
* Atomically:
|
|
274
|
+
* 1. Locks collateral (amount × $1.00)
|
|
275
|
+
* 2. Mints a YES/NO share pair
|
|
276
|
+
* 3. Keeps YES shares as holdings
|
|
277
|
+
* 4. Places NO shares as a sell order at (100 - truePrice) cents
|
|
278
|
+
*
|
|
279
|
+
* @param input - Order parameters
|
|
280
|
+
* @returns Transaction receipt
|
|
281
|
+
*
|
|
282
|
+
* @example
|
|
283
|
+
* ```typescript
|
|
284
|
+
* // Create 100 pairs at YES=55¢, NO=45¢
|
|
285
|
+
* await orderbook.placeSplitLimitOrder({
|
|
286
|
+
* queryId: market.id,
|
|
287
|
+
* truePrice: 55,
|
|
288
|
+
* amount: 100,
|
|
289
|
+
* });
|
|
290
|
+
* // Result: 100 YES holdings + 100 NO sell orders at 45¢
|
|
291
|
+
* ```
|
|
292
|
+
*/
|
|
293
|
+
async placeSplitLimitOrder(input) {
|
|
294
|
+
validatePrice(input.truePrice, "placeSplitLimitOrder");
|
|
295
|
+
validateAmount(input.amount, "placeSplitLimitOrder");
|
|
296
|
+
return this.kwilClient.execute(
|
|
297
|
+
{
|
|
298
|
+
namespace: "main",
|
|
299
|
+
name: "place_split_limit_order",
|
|
300
|
+
inputs: [
|
|
301
|
+
{
|
|
302
|
+
$query_id: input.queryId,
|
|
303
|
+
$true_price: input.truePrice,
|
|
304
|
+
$amount: input.amount
|
|
305
|
+
}
|
|
306
|
+
],
|
|
307
|
+
description: "TN SDK - Place split limit order"
|
|
308
|
+
},
|
|
309
|
+
this.kwilSigner
|
|
310
|
+
);
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Cancels an open order.
|
|
314
|
+
*
|
|
315
|
+
* Cannot cancel holdings (price = 0).
|
|
316
|
+
*
|
|
317
|
+
* @param input - Order to cancel
|
|
318
|
+
* @returns Transaction receipt
|
|
319
|
+
*/
|
|
320
|
+
async cancelOrder(input) {
|
|
321
|
+
if (input.price === 0) {
|
|
322
|
+
throw new Error("Cannot cancel holdings (price = 0)");
|
|
323
|
+
}
|
|
324
|
+
return this.kwilClient.execute(
|
|
325
|
+
{
|
|
326
|
+
namespace: "main",
|
|
327
|
+
name: "cancel_order",
|
|
328
|
+
inputs: [
|
|
329
|
+
{
|
|
330
|
+
$query_id: input.queryId,
|
|
331
|
+
$outcome: input.outcome,
|
|
332
|
+
$price: input.price
|
|
333
|
+
}
|
|
334
|
+
],
|
|
335
|
+
description: "TN SDK - Cancel order"
|
|
336
|
+
},
|
|
337
|
+
this.kwilSigner
|
|
338
|
+
);
|
|
339
|
+
}
|
|
340
|
+
/**
|
|
341
|
+
* Modifies a buy order atomically.
|
|
342
|
+
*
|
|
343
|
+
* Preserves FIFO queue position via timestamp inheritance.
|
|
344
|
+
*
|
|
345
|
+
* @param input - Bid modification parameters
|
|
346
|
+
* @returns Transaction receipt
|
|
347
|
+
*/
|
|
348
|
+
async changeBid(input) {
|
|
349
|
+
if (input.oldPrice >= 0 || input.newPrice >= 0) {
|
|
350
|
+
throw new Error("changeBid: Prices must be negative (buy orders)");
|
|
351
|
+
}
|
|
352
|
+
validateAmount(input.newAmount, "changeBid");
|
|
353
|
+
return this.kwilClient.execute(
|
|
354
|
+
{
|
|
355
|
+
namespace: "main",
|
|
356
|
+
name: "change_bid",
|
|
357
|
+
inputs: [
|
|
358
|
+
{
|
|
359
|
+
$query_id: input.queryId,
|
|
360
|
+
$outcome: input.outcome,
|
|
361
|
+
$old_price: input.oldPrice,
|
|
362
|
+
$new_price: input.newPrice,
|
|
363
|
+
$new_amount: input.newAmount
|
|
364
|
+
}
|
|
365
|
+
],
|
|
366
|
+
description: "TN SDK - Change bid"
|
|
367
|
+
},
|
|
368
|
+
this.kwilSigner
|
|
369
|
+
);
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* Modifies a sell order atomically.
|
|
373
|
+
*
|
|
374
|
+
* Preserves FIFO queue position via timestamp inheritance.
|
|
375
|
+
*
|
|
376
|
+
* @param input - Ask modification parameters
|
|
377
|
+
* @returns Transaction receipt
|
|
378
|
+
*/
|
|
379
|
+
async changeAsk(input) {
|
|
380
|
+
if (input.oldPrice <= 0 || input.newPrice <= 0) {
|
|
381
|
+
throw new Error(
|
|
382
|
+
"changeAsk: Prices must be strictly positive (sell orders, price 0 is holdings)"
|
|
383
|
+
);
|
|
384
|
+
}
|
|
385
|
+
validateAmount(input.newAmount, "changeAsk");
|
|
386
|
+
return this.kwilClient.execute(
|
|
387
|
+
{
|
|
388
|
+
namespace: "main",
|
|
389
|
+
name: "change_ask",
|
|
390
|
+
inputs: [
|
|
391
|
+
{
|
|
392
|
+
$query_id: input.queryId,
|
|
393
|
+
$outcome: input.outcome,
|
|
394
|
+
$old_price: input.oldPrice,
|
|
395
|
+
$new_price: input.newPrice,
|
|
396
|
+
$new_amount: input.newAmount
|
|
397
|
+
}
|
|
398
|
+
],
|
|
399
|
+
description: "TN SDK - Change ask"
|
|
400
|
+
},
|
|
401
|
+
this.kwilSigner
|
|
402
|
+
);
|
|
403
|
+
}
|
|
404
|
+
// ==========================================
|
|
405
|
+
// Query Operations (Read-only)
|
|
406
|
+
// ==========================================
|
|
407
|
+
/**
|
|
408
|
+
* Gets the order book for a market outcome.
|
|
409
|
+
*
|
|
410
|
+
* Returns all buy and sell orders (excludes holdings).
|
|
411
|
+
*
|
|
412
|
+
* @param queryId - Market identifier
|
|
413
|
+
* @param outcome - true=YES, false=NO
|
|
414
|
+
* @returns Array of order book entries
|
|
415
|
+
*/
|
|
416
|
+
async getOrderBook(queryId, outcome) {
|
|
417
|
+
const result = await this.kwilClient.call(
|
|
418
|
+
{
|
|
419
|
+
namespace: "main",
|
|
420
|
+
name: "get_order_book",
|
|
421
|
+
inputs: {
|
|
422
|
+
$query_id: queryId,
|
|
423
|
+
$outcome: outcome
|
|
424
|
+
}
|
|
425
|
+
},
|
|
426
|
+
this.kwilSigner
|
|
427
|
+
);
|
|
428
|
+
if (result.status !== 200) {
|
|
429
|
+
throw new Error(`Failed to get order book: ${result.status}`);
|
|
430
|
+
}
|
|
431
|
+
const rows = result.data?.result || [];
|
|
432
|
+
return rows.map((row) => ({
|
|
433
|
+
walletAddress: dbBytesToUint8Array(row.wallet_address),
|
|
434
|
+
price: row.price,
|
|
435
|
+
amount: row.amount,
|
|
436
|
+
lastUpdated: row.last_updated
|
|
437
|
+
}));
|
|
438
|
+
}
|
|
439
|
+
/**
|
|
440
|
+
* Gets the caller's positions across all markets.
|
|
441
|
+
*
|
|
442
|
+
* @returns Array of user positions (holdings and orders)
|
|
443
|
+
*/
|
|
444
|
+
async getUserPositions() {
|
|
445
|
+
const result = await this.kwilClient.call(
|
|
446
|
+
{
|
|
447
|
+
namespace: "main",
|
|
448
|
+
name: "get_user_positions",
|
|
449
|
+
inputs: {}
|
|
450
|
+
},
|
|
451
|
+
this.kwilSigner
|
|
452
|
+
);
|
|
453
|
+
if (result.status !== 200) {
|
|
454
|
+
throw new Error(`Failed to get user positions: ${result.status}`);
|
|
455
|
+
}
|
|
456
|
+
const rows = result.data?.result || [];
|
|
457
|
+
return rows.map((row) => ({
|
|
458
|
+
queryId: row.query_id,
|
|
459
|
+
outcome: row.outcome,
|
|
460
|
+
price: row.price,
|
|
461
|
+
amount: row.amount,
|
|
462
|
+
lastUpdated: row.last_updated
|
|
463
|
+
}));
|
|
464
|
+
}
|
|
465
|
+
/**
|
|
466
|
+
* Gets aggregated market depth for an outcome.
|
|
467
|
+
*
|
|
468
|
+
* @param queryId - Market identifier
|
|
469
|
+
* @param outcome - true=YES, false=NO
|
|
470
|
+
* @returns Array of depth levels (price + total volume)
|
|
471
|
+
*/
|
|
472
|
+
async getMarketDepth(queryId, outcome) {
|
|
473
|
+
const result = await this.kwilClient.call(
|
|
474
|
+
{
|
|
475
|
+
namespace: "main",
|
|
476
|
+
name: "get_market_depth",
|
|
477
|
+
inputs: {
|
|
478
|
+
$query_id: queryId,
|
|
479
|
+
$outcome: outcome
|
|
480
|
+
}
|
|
481
|
+
},
|
|
482
|
+
this.kwilSigner
|
|
483
|
+
);
|
|
484
|
+
if (result.status !== 200) {
|
|
485
|
+
throw new Error(`Failed to get market depth: ${result.status}`);
|
|
486
|
+
}
|
|
487
|
+
const rows = result.data?.result || [];
|
|
488
|
+
return rows.map((row) => ({
|
|
489
|
+
price: Number(row.price),
|
|
490
|
+
buyVolume: Number(row.buy_volume),
|
|
491
|
+
sellVolume: Number(row.sell_volume)
|
|
492
|
+
}));
|
|
493
|
+
}
|
|
494
|
+
/**
|
|
495
|
+
* Gets the best bid and ask prices for an outcome.
|
|
496
|
+
*
|
|
497
|
+
* @param queryId - Market identifier
|
|
498
|
+
* @param outcome - true=YES, false=NO
|
|
499
|
+
* @returns Best prices and spread
|
|
500
|
+
*/
|
|
501
|
+
async getBestPrices(queryId, outcome) {
|
|
502
|
+
const result = await this.kwilClient.call(
|
|
503
|
+
{
|
|
504
|
+
namespace: "main",
|
|
505
|
+
name: "get_best_prices",
|
|
506
|
+
inputs: {
|
|
507
|
+
$query_id: queryId,
|
|
508
|
+
$outcome: outcome
|
|
509
|
+
}
|
|
510
|
+
},
|
|
511
|
+
this.kwilSigner
|
|
512
|
+
);
|
|
513
|
+
if (result.status !== 200) {
|
|
514
|
+
throw new Error(`Failed to get best prices: ${result.status}`);
|
|
515
|
+
}
|
|
516
|
+
const rows = result.data?.result;
|
|
517
|
+
if (!rows || rows.length === 0) {
|
|
518
|
+
return { bestBid: null, bestAsk: null, spread: null };
|
|
519
|
+
}
|
|
520
|
+
const row = rows[0];
|
|
521
|
+
return {
|
|
522
|
+
bestBid: row.best_bid,
|
|
523
|
+
bestAsk: row.best_ask,
|
|
524
|
+
spread: row.spread
|
|
525
|
+
};
|
|
526
|
+
}
|
|
527
|
+
/**
|
|
528
|
+
* Gets the caller's total locked collateral.
|
|
529
|
+
*
|
|
530
|
+
* @returns Collateral breakdown
|
|
531
|
+
*/
|
|
532
|
+
async getUserCollateral() {
|
|
533
|
+
const result = await this.kwilClient.call(
|
|
534
|
+
{
|
|
535
|
+
namespace: "main",
|
|
536
|
+
name: "get_user_collateral",
|
|
537
|
+
inputs: {}
|
|
538
|
+
},
|
|
539
|
+
this.kwilSigner
|
|
540
|
+
);
|
|
541
|
+
if (result.status !== 200) {
|
|
542
|
+
throw new Error(`Failed to get user collateral: ${result.status}`);
|
|
543
|
+
}
|
|
544
|
+
const rows = result.data?.result;
|
|
545
|
+
if (!rows || rows.length === 0) {
|
|
546
|
+
return {
|
|
547
|
+
totalLocked: "0",
|
|
548
|
+
buyOrdersLocked: "0",
|
|
549
|
+
sharesValue: "0"
|
|
550
|
+
};
|
|
551
|
+
}
|
|
552
|
+
const row = rows[0];
|
|
553
|
+
return {
|
|
554
|
+
totalLocked: row.total_locked,
|
|
555
|
+
buyOrdersLocked: row.buy_orders_locked,
|
|
556
|
+
sharesValue: row.shares_value
|
|
557
|
+
};
|
|
558
|
+
}
|
|
559
|
+
// ==========================================
|
|
560
|
+
// Settlement & Rewards
|
|
561
|
+
// ==========================================
|
|
562
|
+
/**
|
|
563
|
+
* Settles a market using attestation results.
|
|
564
|
+
*
|
|
565
|
+
* Can only be called after settle_time has passed.
|
|
566
|
+
* Automatically distributes payouts and LP rewards.
|
|
567
|
+
*
|
|
568
|
+
* @param queryId - Market identifier
|
|
569
|
+
* @returns Transaction receipt
|
|
570
|
+
*/
|
|
571
|
+
async settleMarket(queryId) {
|
|
572
|
+
return this.kwilClient.execute(
|
|
573
|
+
{
|
|
574
|
+
namespace: "main",
|
|
575
|
+
name: "settle_market",
|
|
576
|
+
inputs: [{ $query_id: queryId }],
|
|
577
|
+
description: "TN SDK - Settle market"
|
|
578
|
+
},
|
|
579
|
+
this.kwilSigner
|
|
580
|
+
);
|
|
581
|
+
}
|
|
582
|
+
/**
|
|
583
|
+
* Samples LP rewards for a specific block.
|
|
584
|
+
*
|
|
585
|
+
* Should be called periodically to track LP eligibility.
|
|
586
|
+
*
|
|
587
|
+
* @param queryId - Market identifier
|
|
588
|
+
* @param block - Block height to sample
|
|
589
|
+
* @returns Transaction receipt
|
|
590
|
+
*/
|
|
591
|
+
async sampleLPRewards(queryId, block) {
|
|
592
|
+
return this.kwilClient.execute(
|
|
593
|
+
{
|
|
594
|
+
namespace: "main",
|
|
595
|
+
name: "sample_lp_rewards",
|
|
596
|
+
inputs: [
|
|
597
|
+
{
|
|
598
|
+
$query_id: queryId,
|
|
599
|
+
$block: block
|
|
600
|
+
}
|
|
601
|
+
],
|
|
602
|
+
description: "TN SDK - Sample LP rewards"
|
|
603
|
+
},
|
|
604
|
+
this.kwilSigner
|
|
605
|
+
);
|
|
606
|
+
}
|
|
607
|
+
/**
|
|
608
|
+
* Gets the fee distribution summary for a market.
|
|
609
|
+
*
|
|
610
|
+
* @param queryId - Market identifier
|
|
611
|
+
* @returns Distribution summary
|
|
612
|
+
*/
|
|
613
|
+
async getDistributionSummary(queryId) {
|
|
614
|
+
const result = await this.kwilClient.call(
|
|
615
|
+
{
|
|
616
|
+
namespace: "main",
|
|
617
|
+
name: "get_distribution_summary",
|
|
618
|
+
inputs: { $query_id: queryId }
|
|
619
|
+
},
|
|
620
|
+
this.kwilSigner
|
|
621
|
+
);
|
|
622
|
+
if (result.status !== 200) {
|
|
623
|
+
throw new Error(`Failed to get distribution summary: ${result.status}`);
|
|
624
|
+
}
|
|
625
|
+
const rows = result.data?.result;
|
|
626
|
+
if (!rows || rows.length === 0) {
|
|
627
|
+
throw new Error(`No distribution found for market: ${queryId}`);
|
|
628
|
+
}
|
|
629
|
+
const row = rows[0];
|
|
630
|
+
return {
|
|
631
|
+
distributionId: row.distribution_id,
|
|
632
|
+
queryId: row.query_id,
|
|
633
|
+
totalFees: row.total_fees,
|
|
634
|
+
distributedAt: row.distributed_at
|
|
635
|
+
};
|
|
636
|
+
}
|
|
637
|
+
/**
|
|
638
|
+
* Gets detailed reward breakdown for a distribution.
|
|
639
|
+
*
|
|
640
|
+
* @param distributionId - Distribution identifier
|
|
641
|
+
* @returns Array of per-LP reward details
|
|
642
|
+
*/
|
|
643
|
+
async getDistributionDetails(distributionId) {
|
|
644
|
+
const result = await this.kwilClient.call(
|
|
645
|
+
{
|
|
646
|
+
namespace: "main",
|
|
647
|
+
name: "get_distribution_details",
|
|
648
|
+
inputs: { $distribution_id: distributionId }
|
|
649
|
+
},
|
|
650
|
+
this.kwilSigner
|
|
651
|
+
);
|
|
652
|
+
if (result.status !== 200) {
|
|
653
|
+
throw new Error(`Failed to get distribution details: ${result.status}`);
|
|
654
|
+
}
|
|
655
|
+
const rows = result.data?.result || [];
|
|
656
|
+
return rows.map((row) => ({
|
|
657
|
+
walletAddress: dbBytesToUint8Array(row.wallet_address),
|
|
658
|
+
rewardAmount: row.reward_amount,
|
|
659
|
+
sharePercentage: row.share_percentage
|
|
660
|
+
}));
|
|
661
|
+
}
|
|
662
|
+
/**
|
|
663
|
+
* Gets reward history for a participant.
|
|
664
|
+
*
|
|
665
|
+
* @param walletHex - Wallet address (0x-prefixed hex)
|
|
666
|
+
* @returns Array of reward history entries
|
|
667
|
+
*/
|
|
668
|
+
async getParticipantRewardHistory(walletHex) {
|
|
669
|
+
const result = await this.kwilClient.call(
|
|
670
|
+
{
|
|
671
|
+
namespace: "main",
|
|
672
|
+
name: "get_participant_reward_history",
|
|
673
|
+
inputs: { $wallet_hex: walletHex }
|
|
674
|
+
},
|
|
675
|
+
this.kwilSigner
|
|
676
|
+
);
|
|
677
|
+
if (result.status !== 200) {
|
|
678
|
+
throw new Error(
|
|
679
|
+
`Failed to get participant reward history: ${result.status}`
|
|
680
|
+
);
|
|
681
|
+
}
|
|
682
|
+
const rows = result.data?.result || [];
|
|
683
|
+
return rows.map((row) => ({
|
|
684
|
+
distributionId: row.distribution_id,
|
|
685
|
+
queryId: row.query_id,
|
|
686
|
+
rewardAmount: row.reward_amount,
|
|
687
|
+
totalRewardPercent: row.total_reward_percent,
|
|
688
|
+
distributedAt: row.distributed_at
|
|
689
|
+
}));
|
|
690
|
+
}
|
|
691
|
+
// ==========================================
|
|
692
|
+
// Binary Market Convenience Creators
|
|
693
|
+
// ==========================================
|
|
694
|
+
/**
|
|
695
|
+
* Creates a "price above threshold" market.
|
|
696
|
+
*
|
|
697
|
+
* YES wins if price > threshold at settlement time.
|
|
698
|
+
*
|
|
699
|
+
* @param input - Market parameters
|
|
700
|
+
* @returns Transaction receipt
|
|
701
|
+
*/
|
|
702
|
+
async createPriceAboveThresholdMarket(input) {
|
|
703
|
+
const args = encodeActionArgs(
|
|
704
|
+
input.dataProvider,
|
|
705
|
+
input.streamId,
|
|
706
|
+
input.timestamp,
|
|
707
|
+
input.threshold,
|
|
708
|
+
input.frozenAt
|
|
709
|
+
);
|
|
710
|
+
const queryComponents = encodeQueryComponents(
|
|
711
|
+
input.dataProvider,
|
|
712
|
+
input.streamId,
|
|
713
|
+
"price_above_threshold",
|
|
714
|
+
args
|
|
715
|
+
);
|
|
716
|
+
return this.createMarket({
|
|
717
|
+
bridge: input.bridge,
|
|
718
|
+
queryComponents,
|
|
719
|
+
settleTime: input.settleTime,
|
|
720
|
+
maxSpread: input.maxSpread,
|
|
721
|
+
minOrderSize: input.minOrderSize
|
|
722
|
+
});
|
|
723
|
+
}
|
|
724
|
+
/**
|
|
725
|
+
* Creates a "price below threshold" market.
|
|
726
|
+
*
|
|
727
|
+
* YES wins if price < threshold at settlement time.
|
|
728
|
+
*
|
|
729
|
+
* @param input - Market parameters
|
|
730
|
+
* @returns Transaction receipt
|
|
731
|
+
*/
|
|
732
|
+
async createPriceBelowThresholdMarket(input) {
|
|
733
|
+
const args = encodeActionArgs(
|
|
734
|
+
input.dataProvider,
|
|
735
|
+
input.streamId,
|
|
736
|
+
input.timestamp,
|
|
737
|
+
input.threshold,
|
|
738
|
+
input.frozenAt
|
|
739
|
+
);
|
|
740
|
+
const queryComponents = encodeQueryComponents(
|
|
741
|
+
input.dataProvider,
|
|
742
|
+
input.streamId,
|
|
743
|
+
"price_below_threshold",
|
|
744
|
+
args
|
|
745
|
+
);
|
|
746
|
+
return this.createMarket({
|
|
747
|
+
bridge: input.bridge,
|
|
748
|
+
queryComponents,
|
|
749
|
+
settleTime: input.settleTime,
|
|
750
|
+
maxSpread: input.maxSpread,
|
|
751
|
+
minOrderSize: input.minOrderSize
|
|
752
|
+
});
|
|
753
|
+
}
|
|
754
|
+
/**
|
|
755
|
+
* Creates a "value in range" market.
|
|
756
|
+
*
|
|
757
|
+
* YES wins if minValue <= value <= maxValue at settlement time.
|
|
758
|
+
*
|
|
759
|
+
* @param input - Market parameters
|
|
760
|
+
* @returns Transaction receipt
|
|
761
|
+
*/
|
|
762
|
+
async createValueInRangeMarket(input) {
|
|
763
|
+
const args = encodeRangeActionArgs(
|
|
764
|
+
input.dataProvider,
|
|
765
|
+
input.streamId,
|
|
766
|
+
input.timestamp,
|
|
767
|
+
input.minValue,
|
|
768
|
+
input.maxValue,
|
|
769
|
+
input.frozenAt
|
|
770
|
+
);
|
|
771
|
+
const queryComponents = encodeQueryComponents(
|
|
772
|
+
input.dataProvider,
|
|
773
|
+
input.streamId,
|
|
774
|
+
"value_in_range",
|
|
775
|
+
args
|
|
776
|
+
);
|
|
777
|
+
return this.createMarket({
|
|
778
|
+
bridge: input.bridge,
|
|
779
|
+
queryComponents,
|
|
780
|
+
settleTime: input.settleTime,
|
|
781
|
+
maxSpread: input.maxSpread,
|
|
782
|
+
minOrderSize: input.minOrderSize
|
|
783
|
+
});
|
|
784
|
+
}
|
|
785
|
+
/**
|
|
786
|
+
* Creates a "value equals" market.
|
|
787
|
+
*
|
|
788
|
+
* YES wins if |value - targetValue| <= tolerance at settlement time.
|
|
789
|
+
*
|
|
790
|
+
* @param input - Market parameters
|
|
791
|
+
* @returns Transaction receipt
|
|
792
|
+
*/
|
|
793
|
+
async createValueEqualsMarket(input) {
|
|
794
|
+
const args = encodeEqualsActionArgs(
|
|
795
|
+
input.dataProvider,
|
|
796
|
+
input.streamId,
|
|
797
|
+
input.timestamp,
|
|
798
|
+
input.targetValue,
|
|
799
|
+
input.tolerance,
|
|
800
|
+
input.frozenAt
|
|
801
|
+
);
|
|
802
|
+
const queryComponents = encodeQueryComponents(
|
|
803
|
+
input.dataProvider,
|
|
804
|
+
input.streamId,
|
|
805
|
+
"value_equals",
|
|
806
|
+
args
|
|
807
|
+
);
|
|
808
|
+
return this.createMarket({
|
|
809
|
+
bridge: input.bridge,
|
|
810
|
+
queryComponents,
|
|
811
|
+
settleTime: input.settleTime,
|
|
812
|
+
maxSpread: input.maxSpread,
|
|
813
|
+
minOrderSize: input.minOrderSize
|
|
814
|
+
});
|
|
815
|
+
}
|
|
816
|
+
// ==========================================
|
|
817
|
+
// Private Helper Methods
|
|
818
|
+
// ==========================================
|
|
819
|
+
parseMarketInfo(row, queryId) {
|
|
820
|
+
return {
|
|
821
|
+
// get_market_info doesn't return id, so use the passed queryId if available
|
|
822
|
+
id: queryId ?? Number(row.id),
|
|
823
|
+
hash: dbBytesToUint8Array(row.hash),
|
|
824
|
+
queryComponents: dbBytesToUint8Array(row.query_components),
|
|
825
|
+
bridge: row.bridge,
|
|
826
|
+
settleTime: Number(row.settle_time),
|
|
827
|
+
settled: row.settled,
|
|
828
|
+
winningOutcome: row.winning_outcome,
|
|
829
|
+
settledAt: row.settled_at !== null ? Number(row.settled_at) : null,
|
|
830
|
+
maxSpread: Number(row.max_spread),
|
|
831
|
+
minOrderSize: String(row.min_order_size),
|
|
832
|
+
createdAt: Number(row.created_at),
|
|
833
|
+
creator: dbBytesToUint8Array(row.creator)
|
|
834
|
+
};
|
|
835
|
+
}
|
|
836
|
+
parseMarketSummary(row) {
|
|
837
|
+
return {
|
|
838
|
+
id: Number(row.id),
|
|
839
|
+
hash: dbBytesToUint8Array(row.hash),
|
|
840
|
+
settleTime: Number(row.settle_time),
|
|
841
|
+
settled: row.settled,
|
|
842
|
+
winningOutcome: row.winning_outcome,
|
|
843
|
+
maxSpread: Number(row.max_spread),
|
|
844
|
+
minOrderSize: String(row.min_order_size),
|
|
845
|
+
createdAt: Number(row.created_at)
|
|
846
|
+
};
|
|
847
|
+
}
|
|
848
|
+
};
|
|
849
|
+
// ==========================================
|
|
850
|
+
// Static Helper Methods
|
|
851
|
+
// ==========================================
|
|
852
|
+
/**
|
|
853
|
+
* Encodes action arguments for query components.
|
|
854
|
+
* @see encodeActionArgs
|
|
855
|
+
*/
|
|
856
|
+
__publicField(OrderbookAction, "encodeActionArgs", encodeActionArgs);
|
|
857
|
+
/**
|
|
858
|
+
* Encodes query components for market creation.
|
|
859
|
+
* @see encodeQueryComponents
|
|
860
|
+
*/
|
|
861
|
+
__publicField(OrderbookAction, "encodeQueryComponents", encodeQueryComponents);
|
|
862
|
+
/**
|
|
863
|
+
* Encodes action arguments for range markets.
|
|
864
|
+
* @see encodeRangeActionArgs
|
|
865
|
+
*/
|
|
866
|
+
__publicField(OrderbookAction, "encodeRangeActionArgs", encodeRangeActionArgs);
|
|
867
|
+
/**
|
|
868
|
+
* Encodes action arguments for equals markets.
|
|
869
|
+
* @see encodeEqualsActionArgs
|
|
870
|
+
*/
|
|
871
|
+
__publicField(OrderbookAction, "encodeEqualsActionArgs", encodeEqualsActionArgs);
|
|
872
|
+
export {
|
|
873
|
+
OrderbookAction
|
|
874
|
+
};
|
|
875
|
+
//# sourceMappingURL=orderbookAction.mjs.map
|