@strobelabs/perpcity-sdk 0.1.4 → 0.1.6

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/dist/index.mjs CHANGED
@@ -1,18 +1,53 @@
1
1
  // src/context.ts
2
2
  import { GraphQLClient } from "graphql-request";
3
+
4
+ // src/deployments.ts
5
+ var DEPLOYMENTS = {
6
+ // Base Sepolia
7
+ [84532]: {
8
+ perpManager: "0x59F1766b77fd67af6c80217C2025A0D536998000",
9
+ usdc: "0xC1a5D4E99BB224713dd179eA9CA2Fa6600706210",
10
+ goldskyPublic: "https://api.goldsky.com/api/public/project_cmbawn40q70fj01ws4jmsfj7f/subgraphs/perp-city/36ac28e6-20250925_150813/gn",
11
+ goldskyPrivate: "https://api.goldsky.com/api/private/project_cmbawn40q70fj01ws4jmsfj7f/subgraphs/perp-city/36ac28e6-20250925_150813/gn"
12
+ }
13
+ };
14
+
15
+ // src/context.ts
16
+ import { publicActions } from "viem";
3
17
  var PerpCityContext = class {
4
18
  constructor(config) {
5
- this.publicClient = config.publicClient;
6
- this.walletClient = config.walletClient;
7
- this.goldskyClient = new GraphQLClient(config.goldskyEndpoint);
8
- this.perpManagerAddress = config.perpManagerAddress;
9
- this.perpManagerAbi = config.perpManagerAbi;
10
- this.beaconAbi = config.beaconAbi;
19
+ this.walletClient = config.walletClient.extend(publicActions);
20
+ const chainId = this.validateChainId();
21
+ const deployments = DEPLOYMENTS[chainId];
22
+ const headers = {};
23
+ let goldskyEndpoint;
24
+ if (config.goldskyBearerToken) {
25
+ headers.authorization = `Bearer ${config.goldskyBearerToken}`;
26
+ goldskyEndpoint = deployments.goldskyPrivate;
27
+ } else {
28
+ goldskyEndpoint = deployments.goldskyPublic;
29
+ }
30
+ this.goldskyClient = new GraphQLClient(goldskyEndpoint, {
31
+ headers
32
+ });
33
+ }
34
+ validateChainId() {
35
+ const chainId = this.walletClient.chain?.id;
36
+ if (!chainId) throw new Error(`Chain ID is not set.`);
37
+ if (!DEPLOYMENTS[chainId]) throw new Error(`Unsupported chainId: ${chainId}.`);
38
+ return chainId;
39
+ }
40
+ deployments() {
41
+ return DEPLOYMENTS[this.validateChainId()];
11
42
  }
12
43
  };
13
44
 
45
+ // src/entities/openPosition.ts
46
+ import { publicActions as publicActions2 } from "viem";
47
+
14
48
  // src/utils/constants.ts
15
- var DECIMAL_PRECISION_6 = 1e6;
49
+ var NUMBER_1E6 = 1e6;
50
+ var BIGINT_1E6 = 1000000n;
16
51
  var Q96 = 79228162514264337593543950336n;
17
52
 
18
53
  // src/utils/conversions.ts
@@ -20,21 +55,1389 @@ function priceToSqrtPriceX96(price) {
20
55
  if (price > Number.MAX_SAFE_INTEGER) {
21
56
  throw new Error("Price too large");
22
57
  }
23
- const scaledSqrtPrice = Math.sqrt(price) * DECIMAL_PRECISION_6;
24
- return BigInt(Math.floor(scaledSqrtPrice)) * Q96 / BigInt(DECIMAL_PRECISION_6);
58
+ const scaledSqrtPrice = Math.sqrt(price) * NUMBER_1E6;
59
+ return BigInt(Math.floor(scaledSqrtPrice)) * Q96 / BigInt(NUMBER_1E6);
25
60
  }
26
61
  function scale6Decimals(amount) {
27
- if (amount > Number.MAX_SAFE_INTEGER / DECIMAL_PRECISION_6) {
62
+ if (amount > Number.MAX_SAFE_INTEGER / NUMBER_1E6) {
28
63
  throw new Error("Amount too large");
29
64
  }
30
- return BigInt(Math.floor(amount * DECIMAL_PRECISION_6));
65
+ return BigInt(Math.floor(amount * NUMBER_1E6));
66
+ }
67
+ function scaleToX96(amount) {
68
+ return BigInt(scale6Decimals(amount)) * Q96 / BigInt(NUMBER_1E6);
69
+ }
70
+ function scaleFromX96(valueX96) {
71
+ const valueScaled6Decimals = valueX96 * BIGINT_1E6 / Q96;
72
+ if (valueScaled6Decimals > Number.MAX_SAFE_INTEGER) {
73
+ throw new Error("Value too large");
74
+ }
75
+ return Number(valueScaled6Decimals) / NUMBER_1E6;
76
+ }
77
+ function priceToTick(price, roundDown) {
78
+ const logPrice = Math.log(price) / Math.log(1.0001);
79
+ return roundDown ? Math.floor(logPrice) : Math.ceil(logPrice);
80
+ }
81
+ function sqrtPriceX96ToPrice(sqrtPriceX96) {
82
+ const priceX96 = sqrtPriceX96 * sqrtPriceX96 / Q96;
83
+ return scaleFromX96(priceX96);
84
+ }
85
+ function marginRatioToLeverage(marginRatio) {
86
+ return NUMBER_1E6 / marginRatio;
87
+ }
88
+ function scaleFrom6Decimals(value) {
89
+ return value / NUMBER_1E6;
90
+ }
91
+
92
+ // src/utils/approve.ts
93
+ import { erc20Abi } from "viem";
94
+ var DEFAULT_CONFIRMATIONS = 2;
95
+ async function approveUsdc(context, amount, confirmations = DEFAULT_CONFIRMATIONS) {
96
+ const deployments = context.deployments();
97
+ const { request } = await context.walletClient.simulateContract({
98
+ address: deployments.usdc,
99
+ abi: erc20Abi,
100
+ functionName: "approve",
101
+ args: [deployments.perpManager, amount],
102
+ account: context.walletClient.account
103
+ });
104
+ const hash = await context.walletClient.writeContract(request);
105
+ await context.walletClient.waitForTransactionReceipt({
106
+ confirmations,
107
+ hash
108
+ });
31
109
  }
32
- function scaleX96(amount) {
33
- return BigInt(scale6Decimals(amount)) * Q96 / BigInt(DECIMAL_PRECISION_6);
110
+
111
+ // src/abis/perp-manager.ts
112
+ var PERP_MANAGER_ABI = [
113
+ {
114
+ "inputs": [
115
+ {
116
+ "internalType": "contract IPoolManager",
117
+ "name": "poolManager",
118
+ "type": "address"
119
+ },
120
+ {
121
+ "internalType": "address",
122
+ "name": "usdc",
123
+ "type": "address"
124
+ }
125
+ ],
126
+ "stateMutability": "nonpayable",
127
+ "type": "constructor"
128
+ },
129
+ {
130
+ "inputs": [
131
+ {
132
+ "internalType": "uint8",
133
+ "name": "action",
134
+ "type": "uint8"
135
+ }
136
+ ],
137
+ "name": "InvalidAction",
138
+ "type": "error"
139
+ },
140
+ {
141
+ "inputs": [
142
+ {
143
+ "internalType": "address",
144
+ "name": "caller",
145
+ "type": "address"
146
+ },
147
+ {
148
+ "internalType": "address",
149
+ "name": "expectedCaller",
150
+ "type": "address"
151
+ }
152
+ ],
153
+ "name": "InvalidCaller",
154
+ "type": "error"
155
+ },
156
+ {
157
+ "inputs": [
158
+ {
159
+ "internalType": "address",
160
+ "name": "caller",
161
+ "type": "address"
162
+ },
163
+ {
164
+ "internalType": "address",
165
+ "name": "holder",
166
+ "type": "address"
167
+ },
168
+ {
169
+ "internalType": "bool",
170
+ "name": "isLiquidated",
171
+ "type": "bool"
172
+ }
173
+ ],
174
+ "name": "InvalidClose",
175
+ "type": "error"
176
+ },
177
+ {
178
+ "inputs": [
179
+ {
180
+ "internalType": "uint128",
181
+ "name": "liquidity",
182
+ "type": "uint128"
183
+ }
184
+ ],
185
+ "name": "InvalidLiquidity",
186
+ "type": "error"
187
+ },
188
+ {
189
+ "inputs": [
190
+ {
191
+ "internalType": "uint256",
192
+ "name": "margin",
193
+ "type": "uint256"
194
+ }
195
+ ],
196
+ "name": "InvalidMargin",
197
+ "type": "error"
198
+ },
199
+ {
200
+ "inputs": [
201
+ {
202
+ "internalType": "uint256",
203
+ "name": "currentTimestamp",
204
+ "type": "uint256"
205
+ },
206
+ {
207
+ "internalType": "uint256",
208
+ "name": "lockupPeriodEnd",
209
+ "type": "uint256"
210
+ }
211
+ ],
212
+ "name": "MakerPositionLocked",
213
+ "type": "error"
214
+ },
215
+ {
216
+ "inputs": [
217
+ {
218
+ "internalType": "uint256",
219
+ "name": "maximumAmount",
220
+ "type": "uint256"
221
+ },
222
+ {
223
+ "internalType": "uint256",
224
+ "name": "amountRequested",
225
+ "type": "uint256"
226
+ }
227
+ ],
228
+ "name": "MaximumAmountExceeded",
229
+ "type": "error"
230
+ },
231
+ {
232
+ "inputs": [
233
+ {
234
+ "internalType": "uint256",
235
+ "name": "minimumAmount",
236
+ "type": "uint256"
237
+ },
238
+ {
239
+ "internalType": "uint256",
240
+ "name": "amountReceived",
241
+ "type": "uint256"
242
+ }
243
+ ],
244
+ "name": "MinimumAmountInsufficient",
245
+ "type": "error"
246
+ },
247
+ {
248
+ "inputs": [],
249
+ "name": "NotPoolManager",
250
+ "type": "error"
251
+ },
252
+ {
253
+ "inputs": [
254
+ {
255
+ "internalType": "bytes",
256
+ "name": "reason",
257
+ "type": "bytes"
258
+ }
259
+ ],
260
+ "name": "UnexpectedRevertBytes",
261
+ "type": "error"
262
+ },
263
+ {
264
+ "inputs": [
265
+ {
266
+ "internalType": "int256",
267
+ "name": "perpDelta",
268
+ "type": "int256"
269
+ },
270
+ {
271
+ "internalType": "int256",
272
+ "name": "usdDelta",
273
+ "type": "int256"
274
+ }
275
+ ],
276
+ "name": "ZeroSizePosition",
277
+ "type": "error"
278
+ },
279
+ {
280
+ "anonymous": false,
281
+ "inputs": [
282
+ {
283
+ "indexed": false,
284
+ "internalType": "PoolId",
285
+ "name": "perpId",
286
+ "type": "bytes32"
287
+ },
288
+ {
289
+ "indexed": false,
290
+ "internalType": "uint256",
291
+ "name": "posId",
292
+ "type": "uint256"
293
+ },
294
+ {
295
+ "indexed": false,
296
+ "internalType": "uint256",
297
+ "name": "newMargin",
298
+ "type": "uint256"
299
+ }
300
+ ],
301
+ "name": "MarginAdded",
302
+ "type": "event"
303
+ },
304
+ {
305
+ "anonymous": false,
306
+ "inputs": [
307
+ {
308
+ "indexed": false,
309
+ "internalType": "PoolId",
310
+ "name": "perpId",
311
+ "type": "bytes32"
312
+ },
313
+ {
314
+ "indexed": false,
315
+ "internalType": "address",
316
+ "name": "beacon",
317
+ "type": "address"
318
+ },
319
+ {
320
+ "indexed": false,
321
+ "internalType": "uint256",
322
+ "name": "startingSqrtPriceX96",
323
+ "type": "uint256"
324
+ },
325
+ {
326
+ "indexed": false,
327
+ "internalType": "uint256",
328
+ "name": "indexPriceX96",
329
+ "type": "uint256"
330
+ }
331
+ ],
332
+ "name": "PerpCreated",
333
+ "type": "event"
334
+ },
335
+ {
336
+ "anonymous": false,
337
+ "inputs": [
338
+ {
339
+ "indexed": false,
340
+ "internalType": "PoolId",
341
+ "name": "perpId",
342
+ "type": "bytes32"
343
+ },
344
+ {
345
+ "indexed": false,
346
+ "internalType": "uint256",
347
+ "name": "posId",
348
+ "type": "uint256"
349
+ },
350
+ {
351
+ "indexed": false,
352
+ "internalType": "address",
353
+ "name": "holder",
354
+ "type": "address"
355
+ },
356
+ {
357
+ "indexed": false,
358
+ "internalType": "bool",
359
+ "name": "wasMaker",
360
+ "type": "bool"
361
+ },
362
+ {
363
+ "indexed": false,
364
+ "internalType": "int256",
365
+ "name": "perpDelta",
366
+ "type": "int256"
367
+ },
368
+ {
369
+ "indexed": false,
370
+ "internalType": "int256",
371
+ "name": "pnl",
372
+ "type": "int256"
373
+ },
374
+ {
375
+ "indexed": false,
376
+ "internalType": "bool",
377
+ "name": "wasLiquidated",
378
+ "type": "bool"
379
+ },
380
+ {
381
+ "indexed": false,
382
+ "internalType": "uint256",
383
+ "name": "sqrtPriceX96",
384
+ "type": "uint256"
385
+ },
386
+ {
387
+ "indexed": false,
388
+ "internalType": "int256",
389
+ "name": "fundingPremiumPerSecX96",
390
+ "type": "int256"
391
+ }
392
+ ],
393
+ "name": "PositionClosed",
394
+ "type": "event"
395
+ },
396
+ {
397
+ "anonymous": false,
398
+ "inputs": [
399
+ {
400
+ "indexed": false,
401
+ "internalType": "PoolId",
402
+ "name": "perpId",
403
+ "type": "bytes32"
404
+ },
405
+ {
406
+ "indexed": false,
407
+ "internalType": "uint256",
408
+ "name": "posId",
409
+ "type": "uint256"
410
+ },
411
+ {
412
+ "indexed": false,
413
+ "internalType": "address",
414
+ "name": "holder",
415
+ "type": "address"
416
+ },
417
+ {
418
+ "indexed": false,
419
+ "internalType": "bool",
420
+ "name": "isMaker",
421
+ "type": "bool"
422
+ },
423
+ {
424
+ "indexed": false,
425
+ "internalType": "int256",
426
+ "name": "perpDelta",
427
+ "type": "int256"
428
+ },
429
+ {
430
+ "indexed": false,
431
+ "internalType": "uint256",
432
+ "name": "sqrtPriceX96",
433
+ "type": "uint256"
434
+ },
435
+ {
436
+ "indexed": false,
437
+ "internalType": "int256",
438
+ "name": "fundingPremiumPerSecX96",
439
+ "type": "int256"
440
+ }
441
+ ],
442
+ "name": "PositionOpened",
443
+ "type": "event"
444
+ },
445
+ {
446
+ "inputs": [],
447
+ "name": "POOL_MANAGER",
448
+ "outputs": [
449
+ {
450
+ "internalType": "contract IPoolManager",
451
+ "name": "",
452
+ "type": "address"
453
+ }
454
+ ],
455
+ "stateMutability": "view",
456
+ "type": "function"
457
+ },
458
+ {
459
+ "inputs": [],
460
+ "name": "USDC",
461
+ "outputs": [
462
+ {
463
+ "internalType": "address",
464
+ "name": "",
465
+ "type": "address"
466
+ }
467
+ ],
468
+ "stateMutability": "view",
469
+ "type": "function"
470
+ },
471
+ {
472
+ "inputs": [
473
+ {
474
+ "internalType": "PoolId",
475
+ "name": "perpId",
476
+ "type": "bytes32"
477
+ },
478
+ {
479
+ "components": [
480
+ {
481
+ "internalType": "uint128",
482
+ "name": "posId",
483
+ "type": "uint128"
484
+ },
485
+ {
486
+ "internalType": "uint256",
487
+ "name": "margin",
488
+ "type": "uint256"
489
+ }
490
+ ],
491
+ "internalType": "struct IPerpManager.AddMarginParams",
492
+ "name": "params",
493
+ "type": "tuple"
494
+ }
495
+ ],
496
+ "name": "addMargin",
497
+ "outputs": [],
498
+ "stateMutability": "nonpayable",
499
+ "type": "function"
500
+ },
501
+ {
502
+ "inputs": [
503
+ {
504
+ "internalType": "PoolId",
505
+ "name": "perpId",
506
+ "type": "bytes32"
507
+ },
508
+ {
509
+ "components": [
510
+ {
511
+ "internalType": "uint128",
512
+ "name": "posId",
513
+ "type": "uint128"
514
+ },
515
+ {
516
+ "internalType": "uint128",
517
+ "name": "minAmt0Out",
518
+ "type": "uint128"
519
+ },
520
+ {
521
+ "internalType": "uint128",
522
+ "name": "minAmt1Out",
523
+ "type": "uint128"
524
+ },
525
+ {
526
+ "internalType": "uint128",
527
+ "name": "maxAmt1In",
528
+ "type": "uint128"
529
+ }
530
+ ],
531
+ "internalType": "struct IPerpManager.ClosePositionParams",
532
+ "name": "params",
533
+ "type": "tuple"
534
+ }
535
+ ],
536
+ "name": "closePosition",
537
+ "outputs": [
538
+ {
539
+ "internalType": "uint128",
540
+ "name": "posId",
541
+ "type": "uint128"
542
+ }
543
+ ],
544
+ "stateMutability": "nonpayable",
545
+ "type": "function"
546
+ },
547
+ {
548
+ "inputs": [
549
+ {
550
+ "components": [
551
+ {
552
+ "internalType": "uint160",
553
+ "name": "startingSqrtPriceX96",
554
+ "type": "uint160"
555
+ },
556
+ {
557
+ "internalType": "address",
558
+ "name": "beacon",
559
+ "type": "address"
560
+ }
561
+ ],
562
+ "internalType": "struct IPerpManager.CreatePerpParams",
563
+ "name": "params",
564
+ "type": "tuple"
565
+ }
566
+ ],
567
+ "name": "createPerp",
568
+ "outputs": [
569
+ {
570
+ "internalType": "PoolId",
571
+ "name": "perpId",
572
+ "type": "bytes32"
573
+ }
574
+ ],
575
+ "stateMutability": "nonpayable",
576
+ "type": "function"
577
+ },
578
+ {
579
+ "inputs": [
580
+ {
581
+ "internalType": "int24",
582
+ "name": "tickA",
583
+ "type": "int24"
584
+ },
585
+ {
586
+ "internalType": "int24",
587
+ "name": "tickB",
588
+ "type": "int24"
589
+ },
590
+ {
591
+ "internalType": "uint256",
592
+ "name": "amount1",
593
+ "type": "uint256"
594
+ }
595
+ ],
596
+ "name": "estimateLiquidityForAmount1",
597
+ "outputs": [
598
+ {
599
+ "internalType": "uint128",
600
+ "name": "liquidity",
601
+ "type": "uint128"
602
+ }
603
+ ],
604
+ "stateMutability": "pure",
605
+ "type": "function"
606
+ },
607
+ {
608
+ "inputs": [
609
+ {
610
+ "internalType": "PoolId",
611
+ "name": "perpId",
612
+ "type": "bytes32"
613
+ }
614
+ ],
615
+ "name": "fees",
616
+ "outputs": [
617
+ {
618
+ "internalType": "uint24",
619
+ "name": "creatorFee",
620
+ "type": "uint24"
621
+ },
622
+ {
623
+ "internalType": "uint24",
624
+ "name": "insurnaceFee",
625
+ "type": "uint24"
626
+ },
627
+ {
628
+ "internalType": "uint24",
629
+ "name": "lpFee",
630
+ "type": "uint24"
631
+ },
632
+ {
633
+ "internalType": "uint24",
634
+ "name": "liquidationFee",
635
+ "type": "uint24"
636
+ }
637
+ ],
638
+ "stateMutability": "view",
639
+ "type": "function"
640
+ },
641
+ {
642
+ "inputs": [
643
+ {
644
+ "internalType": "PoolId",
645
+ "name": "perpId",
646
+ "type": "bytes32"
647
+ },
648
+ {
649
+ "internalType": "uint128",
650
+ "name": "posId",
651
+ "type": "uint128"
652
+ }
653
+ ],
654
+ "name": "getPosition",
655
+ "outputs": [
656
+ {
657
+ "components": [
658
+ {
659
+ "internalType": "address",
660
+ "name": "holder",
661
+ "type": "address"
662
+ },
663
+ {
664
+ "internalType": "uint256",
665
+ "name": "margin",
666
+ "type": "uint256"
667
+ },
668
+ {
669
+ "internalType": "int256",
670
+ "name": "perpDelta",
671
+ "type": "int256"
672
+ },
673
+ {
674
+ "internalType": "int256",
675
+ "name": "usdDelta",
676
+ "type": "int256"
677
+ },
678
+ {
679
+ "internalType": "int256",
680
+ "name": "entryTwPremiumX96",
681
+ "type": "int256"
682
+ },
683
+ {
684
+ "components": [
685
+ {
686
+ "internalType": "uint32",
687
+ "name": "entryTimestamp",
688
+ "type": "uint32"
689
+ },
690
+ {
691
+ "internalType": "int24",
692
+ "name": "tickLower",
693
+ "type": "int24"
694
+ },
695
+ {
696
+ "internalType": "int24",
697
+ "name": "tickUpper",
698
+ "type": "int24"
699
+ },
700
+ {
701
+ "internalType": "uint128",
702
+ "name": "liquidity",
703
+ "type": "uint128"
704
+ },
705
+ {
706
+ "internalType": "int256",
707
+ "name": "entryTwPremiumGrowthInsideX96",
708
+ "type": "int256"
709
+ },
710
+ {
711
+ "internalType": "int256",
712
+ "name": "entryTwPremiumDivBySqrtPriceGrowthInsideX96",
713
+ "type": "int256"
714
+ },
715
+ {
716
+ "internalType": "int256",
717
+ "name": "entryTwPremiumGrowthBelowX96",
718
+ "type": "int256"
719
+ }
720
+ ],
721
+ "internalType": "struct IPerpManager.MakerDetails",
722
+ "name": "makerDetails",
723
+ "type": "tuple"
724
+ }
725
+ ],
726
+ "internalType": "struct IPerpManager.Position",
727
+ "name": "",
728
+ "type": "tuple"
729
+ }
730
+ ],
731
+ "stateMutability": "view",
732
+ "type": "function"
733
+ },
734
+ {
735
+ "inputs": [
736
+ {
737
+ "internalType": "PoolId",
738
+ "name": "perpId",
739
+ "type": "bytes32"
740
+ },
741
+ {
742
+ "internalType": "uint32",
743
+ "name": "secondsAgo",
744
+ "type": "uint32"
745
+ }
746
+ ],
747
+ "name": "getTimeWeightedAvg",
748
+ "outputs": [
749
+ {
750
+ "internalType": "uint256",
751
+ "name": "",
752
+ "type": "uint256"
753
+ }
754
+ ],
755
+ "stateMutability": "view",
756
+ "type": "function"
757
+ },
758
+ {
759
+ "inputs": [
760
+ {
761
+ "internalType": "PoolId",
762
+ "name": "perpId",
763
+ "type": "bytes32"
764
+ },
765
+ {
766
+ "internalType": "uint32",
767
+ "name": "cardinalityNext",
768
+ "type": "uint32"
769
+ }
770
+ ],
771
+ "name": "increaseCardinalityNext",
772
+ "outputs": [],
773
+ "stateMutability": "nonpayable",
774
+ "type": "function"
775
+ },
776
+ {
777
+ "inputs": [
778
+ {
779
+ "internalType": "PoolId",
780
+ "name": "perpId",
781
+ "type": "bytes32"
782
+ },
783
+ {
784
+ "internalType": "uint128",
785
+ "name": "posId",
786
+ "type": "uint128"
787
+ }
788
+ ],
789
+ "name": "livePositionDetails",
790
+ "outputs": [
791
+ {
792
+ "internalType": "int256",
793
+ "name": "pnl",
794
+ "type": "int256"
795
+ },
796
+ {
797
+ "internalType": "int256",
798
+ "name": "fundingPayment",
799
+ "type": "int256"
800
+ },
801
+ {
802
+ "internalType": "int256",
803
+ "name": "effectiveMargin",
804
+ "type": "int256"
805
+ },
806
+ {
807
+ "internalType": "bool",
808
+ "name": "isLiquidatable",
809
+ "type": "bool"
810
+ },
811
+ {
812
+ "internalType": "uint256",
813
+ "name": "newPriceX96",
814
+ "type": "uint256"
815
+ }
816
+ ],
817
+ "stateMutability": "nonpayable",
818
+ "type": "function"
819
+ },
820
+ {
821
+ "inputs": [
822
+ {
823
+ "internalType": "PoolId",
824
+ "name": "perpId",
825
+ "type": "bytes32"
826
+ },
827
+ {
828
+ "components": [
829
+ {
830
+ "internalType": "uint256",
831
+ "name": "margin",
832
+ "type": "uint256"
833
+ },
834
+ {
835
+ "internalType": "uint128",
836
+ "name": "liquidity",
837
+ "type": "uint128"
838
+ },
839
+ {
840
+ "internalType": "int24",
841
+ "name": "tickLower",
842
+ "type": "int24"
843
+ },
844
+ {
845
+ "internalType": "int24",
846
+ "name": "tickUpper",
847
+ "type": "int24"
848
+ },
849
+ {
850
+ "internalType": "uint128",
851
+ "name": "maxAmt0In",
852
+ "type": "uint128"
853
+ },
854
+ {
855
+ "internalType": "uint128",
856
+ "name": "maxAmt1In",
857
+ "type": "uint128"
858
+ }
859
+ ],
860
+ "internalType": "struct IPerpManager.OpenMakerPositionParams",
861
+ "name": "params",
862
+ "type": "tuple"
863
+ }
864
+ ],
865
+ "name": "openMakerPosition",
866
+ "outputs": [
867
+ {
868
+ "internalType": "uint128",
869
+ "name": "makerPosId",
870
+ "type": "uint128"
871
+ }
872
+ ],
873
+ "stateMutability": "nonpayable",
874
+ "type": "function"
875
+ },
876
+ {
877
+ "inputs": [
878
+ {
879
+ "internalType": "PoolId",
880
+ "name": "perpId",
881
+ "type": "bytes32"
882
+ },
883
+ {
884
+ "components": [
885
+ {
886
+ "internalType": "bool",
887
+ "name": "isLong",
888
+ "type": "bool"
889
+ },
890
+ {
891
+ "internalType": "uint256",
892
+ "name": "margin",
893
+ "type": "uint256"
894
+ },
895
+ {
896
+ "internalType": "uint256",
897
+ "name": "levX96",
898
+ "type": "uint256"
899
+ },
900
+ {
901
+ "internalType": "uint128",
902
+ "name": "unspecifiedAmountLimit",
903
+ "type": "uint128"
904
+ }
905
+ ],
906
+ "internalType": "struct IPerpManager.OpenTakerPositionParams",
907
+ "name": "params",
908
+ "type": "tuple"
909
+ }
910
+ ],
911
+ "name": "openTakerPosition",
912
+ "outputs": [
913
+ {
914
+ "internalType": "uint128",
915
+ "name": "takerPosId",
916
+ "type": "uint128"
917
+ }
918
+ ],
919
+ "stateMutability": "nonpayable",
920
+ "type": "function"
921
+ },
922
+ {
923
+ "inputs": [
924
+ {
925
+ "internalType": "PoolId",
926
+ "name": "",
927
+ "type": "bytes32"
928
+ }
929
+ ],
930
+ "name": "perps",
931
+ "outputs": [
932
+ {
933
+ "internalType": "address",
934
+ "name": "vault",
935
+ "type": "address"
936
+ },
937
+ {
938
+ "internalType": "address",
939
+ "name": "beacon",
940
+ "type": "address"
941
+ },
942
+ {
943
+ "internalType": "address",
944
+ "name": "creator",
945
+ "type": "address"
946
+ },
947
+ {
948
+ "internalType": "uint32",
949
+ "name": "creationTimestamp",
950
+ "type": "uint32"
951
+ },
952
+ {
953
+ "internalType": "uint32",
954
+ "name": "makerLockupPeriod",
955
+ "type": "uint32"
956
+ },
957
+ {
958
+ "internalType": "uint32",
959
+ "name": "twapWindow",
960
+ "type": "uint32"
961
+ },
962
+ {
963
+ "internalType": "uint32",
964
+ "name": "lastTwPremiumsUpdate",
965
+ "type": "uint32"
966
+ },
967
+ {
968
+ "internalType": "uint24",
969
+ "name": "creatorFee",
970
+ "type": "uint24"
971
+ },
972
+ {
973
+ "internalType": "uint24",
974
+ "name": "insuranceFee",
975
+ "type": "uint24"
976
+ },
977
+ {
978
+ "internalType": "uint24",
979
+ "name": "liquidationFee",
980
+ "type": "uint24"
981
+ },
982
+ {
983
+ "internalType": "uint24",
984
+ "name": "liquidatorFeeSplit",
985
+ "type": "uint24"
986
+ },
987
+ {
988
+ "internalType": "uint128",
989
+ "name": "nextPosId",
990
+ "type": "uint128"
991
+ },
992
+ {
993
+ "internalType": "uint256",
994
+ "name": "sqrtPriceLowerMultiX96",
995
+ "type": "uint256"
996
+ },
997
+ {
998
+ "internalType": "uint256",
999
+ "name": "sqrtPriceUpperMultiX96",
1000
+ "type": "uint256"
1001
+ },
1002
+ {
1003
+ "internalType": "uint24",
1004
+ "name": "minOpeningMargin",
1005
+ "type": "uint24"
1006
+ },
1007
+ {
1008
+ "internalType": "uint24",
1009
+ "name": "minMakerOpeningMarginRatio",
1010
+ "type": "uint24"
1011
+ },
1012
+ {
1013
+ "internalType": "uint24",
1014
+ "name": "maxMakerOpeningMarginRatio",
1015
+ "type": "uint24"
1016
+ },
1017
+ {
1018
+ "internalType": "uint24",
1019
+ "name": "makerLiquidationMarginRatio",
1020
+ "type": "uint24"
1021
+ },
1022
+ {
1023
+ "internalType": "uint24",
1024
+ "name": "minTakerOpeningMarginRatio",
1025
+ "type": "uint24"
1026
+ },
1027
+ {
1028
+ "internalType": "uint24",
1029
+ "name": "maxTakerOpeningMarginRatio",
1030
+ "type": "uint24"
1031
+ },
1032
+ {
1033
+ "internalType": "uint24",
1034
+ "name": "takerLiquidationMarginRatio",
1035
+ "type": "uint24"
1036
+ },
1037
+ {
1038
+ "internalType": "int256",
1039
+ "name": "twPremiumX96",
1040
+ "type": "int256"
1041
+ },
1042
+ {
1043
+ "internalType": "int256",
1044
+ "name": "twPremiumDivBySqrtPriceX96",
1045
+ "type": "int256"
1046
+ },
1047
+ {
1048
+ "internalType": "int256",
1049
+ "name": "premiumPerSecondX96",
1050
+ "type": "int256"
1051
+ },
1052
+ {
1053
+ "components": [
1054
+ {
1055
+ "internalType": "Currency",
1056
+ "name": "currency0",
1057
+ "type": "address"
1058
+ },
1059
+ {
1060
+ "internalType": "Currency",
1061
+ "name": "currency1",
1062
+ "type": "address"
1063
+ },
1064
+ {
1065
+ "internalType": "uint24",
1066
+ "name": "fee",
1067
+ "type": "uint24"
1068
+ },
1069
+ {
1070
+ "internalType": "int24",
1071
+ "name": "tickSpacing",
1072
+ "type": "int24"
1073
+ },
1074
+ {
1075
+ "internalType": "contract IHooks",
1076
+ "name": "hooks",
1077
+ "type": "address"
1078
+ }
1079
+ ],
1080
+ "internalType": "struct PoolKey",
1081
+ "name": "key",
1082
+ "type": "tuple"
1083
+ },
1084
+ {
1085
+ "components": [
1086
+ {
1087
+ "internalType": "uint128",
1088
+ "name": "baseFeeX96",
1089
+ "type": "uint128"
1090
+ },
1091
+ {
1092
+ "internalType": "uint128",
1093
+ "name": "startFeeX96",
1094
+ "type": "uint128"
1095
+ },
1096
+ {
1097
+ "internalType": "uint128",
1098
+ "name": "targetFeeX96",
1099
+ "type": "uint128"
1100
+ },
1101
+ {
1102
+ "internalType": "uint128",
1103
+ "name": "decay",
1104
+ "type": "uint128"
1105
+ },
1106
+ {
1107
+ "internalType": "uint128",
1108
+ "name": "volatilityScalerX96",
1109
+ "type": "uint128"
1110
+ },
1111
+ {
1112
+ "internalType": "uint128",
1113
+ "name": "maxFeeMultiplierX96",
1114
+ "type": "uint128"
1115
+ }
1116
+ ],
1117
+ "internalType": "struct TradingFee.Config",
1118
+ "name": "tradingFeeConfig",
1119
+ "type": "tuple"
1120
+ },
1121
+ {
1122
+ "components": [
1123
+ {
1124
+ "internalType": "uint32",
1125
+ "name": "index",
1126
+ "type": "uint32"
1127
+ },
1128
+ {
1129
+ "internalType": "uint32",
1130
+ "name": "cardinality",
1131
+ "type": "uint32"
1132
+ },
1133
+ {
1134
+ "internalType": "uint32",
1135
+ "name": "cardinalityNext",
1136
+ "type": "uint32"
1137
+ },
1138
+ {
1139
+ "components": [
1140
+ {
1141
+ "internalType": "uint32",
1142
+ "name": "blockTimestamp",
1143
+ "type": "uint32"
1144
+ },
1145
+ {
1146
+ "internalType": "uint216",
1147
+ "name": "cumulativeValue",
1148
+ "type": "uint216"
1149
+ },
1150
+ {
1151
+ "internalType": "bool",
1152
+ "name": "initialized",
1153
+ "type": "bool"
1154
+ }
1155
+ ],
1156
+ "internalType": "struct TimeWeightedAvg.Observation[65535]",
1157
+ "name": "observations",
1158
+ "type": "tuple[65535]"
1159
+ }
1160
+ ],
1161
+ "internalType": "struct TimeWeightedAvg.State",
1162
+ "name": "twapState",
1163
+ "type": "tuple"
1164
+ }
1165
+ ],
1166
+ "stateMutability": "view",
1167
+ "type": "function"
1168
+ },
1169
+ {
1170
+ "inputs": [
1171
+ {
1172
+ "internalType": "PoolId",
1173
+ "name": "perpId",
1174
+ "type": "bytes32"
1175
+ },
1176
+ {
1177
+ "components": [
1178
+ {
1179
+ "internalType": "uint256",
1180
+ "name": "margin",
1181
+ "type": "uint256"
1182
+ },
1183
+ {
1184
+ "internalType": "uint128",
1185
+ "name": "liquidity",
1186
+ "type": "uint128"
1187
+ },
1188
+ {
1189
+ "internalType": "int24",
1190
+ "name": "tickLower",
1191
+ "type": "int24"
1192
+ },
1193
+ {
1194
+ "internalType": "int24",
1195
+ "name": "tickUpper",
1196
+ "type": "int24"
1197
+ },
1198
+ {
1199
+ "internalType": "uint128",
1200
+ "name": "maxAmt0In",
1201
+ "type": "uint128"
1202
+ },
1203
+ {
1204
+ "internalType": "uint128",
1205
+ "name": "maxAmt1In",
1206
+ "type": "uint128"
1207
+ }
1208
+ ],
1209
+ "internalType": "struct IPerpManager.OpenMakerPositionParams",
1210
+ "name": "params",
1211
+ "type": "tuple"
1212
+ }
1213
+ ],
1214
+ "name": "quoteMakerPosition",
1215
+ "outputs": [
1216
+ {
1217
+ "internalType": "bool",
1218
+ "name": "success",
1219
+ "type": "bool"
1220
+ },
1221
+ {
1222
+ "internalType": "int256",
1223
+ "name": "perpDelta",
1224
+ "type": "int256"
1225
+ },
1226
+ {
1227
+ "internalType": "int256",
1228
+ "name": "usdDelta",
1229
+ "type": "int256"
1230
+ },
1231
+ {
1232
+ "internalType": "uint256",
1233
+ "name": "creatorFeeAmt",
1234
+ "type": "uint256"
1235
+ },
1236
+ {
1237
+ "internalType": "uint256",
1238
+ "name": "insuranceFeeAmt",
1239
+ "type": "uint256"
1240
+ },
1241
+ {
1242
+ "internalType": "uint256",
1243
+ "name": "lpFeeAmt",
1244
+ "type": "uint256"
1245
+ }
1246
+ ],
1247
+ "stateMutability": "nonpayable",
1248
+ "type": "function"
1249
+ },
1250
+ {
1251
+ "inputs": [
1252
+ {
1253
+ "internalType": "PoolId",
1254
+ "name": "perpId",
1255
+ "type": "bytes32"
1256
+ },
1257
+ {
1258
+ "components": [
1259
+ {
1260
+ "internalType": "bool",
1261
+ "name": "isLong",
1262
+ "type": "bool"
1263
+ },
1264
+ {
1265
+ "internalType": "uint256",
1266
+ "name": "margin",
1267
+ "type": "uint256"
1268
+ },
1269
+ {
1270
+ "internalType": "uint256",
1271
+ "name": "levX96",
1272
+ "type": "uint256"
1273
+ },
1274
+ {
1275
+ "internalType": "uint128",
1276
+ "name": "unspecifiedAmountLimit",
1277
+ "type": "uint128"
1278
+ }
1279
+ ],
1280
+ "internalType": "struct IPerpManager.OpenTakerPositionParams",
1281
+ "name": "params",
1282
+ "type": "tuple"
1283
+ }
1284
+ ],
1285
+ "name": "quoteTakerPosition",
1286
+ "outputs": [
1287
+ {
1288
+ "internalType": "bool",
1289
+ "name": "success",
1290
+ "type": "bool"
1291
+ },
1292
+ {
1293
+ "internalType": "int256",
1294
+ "name": "perpDelta",
1295
+ "type": "int256"
1296
+ },
1297
+ {
1298
+ "internalType": "int256",
1299
+ "name": "usdDelta",
1300
+ "type": "int256"
1301
+ },
1302
+ {
1303
+ "internalType": "uint256",
1304
+ "name": "creatorFeeAmt",
1305
+ "type": "uint256"
1306
+ },
1307
+ {
1308
+ "internalType": "uint256",
1309
+ "name": "insuranceFeeAmt",
1310
+ "type": "uint256"
1311
+ },
1312
+ {
1313
+ "internalType": "uint256",
1314
+ "name": "lpFeeAmt",
1315
+ "type": "uint256"
1316
+ }
1317
+ ],
1318
+ "stateMutability": "nonpayable",
1319
+ "type": "function"
1320
+ },
1321
+ {
1322
+ "inputs": [
1323
+ {
1324
+ "internalType": "PoolId",
1325
+ "name": "perpId",
1326
+ "type": "bytes32"
1327
+ }
1328
+ ],
1329
+ "name": "sqrtPriceX96",
1330
+ "outputs": [
1331
+ {
1332
+ "internalType": "uint160",
1333
+ "name": "sqrtPrice",
1334
+ "type": "uint160"
1335
+ }
1336
+ ],
1337
+ "stateMutability": "view",
1338
+ "type": "function"
1339
+ },
1340
+ {
1341
+ "inputs": [
1342
+ {
1343
+ "internalType": "PoolId",
1344
+ "name": "perpId",
1345
+ "type": "bytes32"
1346
+ }
1347
+ ],
1348
+ "name": "tickSpacing",
1349
+ "outputs": [
1350
+ {
1351
+ "internalType": "int24",
1352
+ "name": "",
1353
+ "type": "int24"
1354
+ }
1355
+ ],
1356
+ "stateMutability": "view",
1357
+ "type": "function"
1358
+ },
1359
+ {
1360
+ "inputs": [
1361
+ {
1362
+ "internalType": "PoolId",
1363
+ "name": "perpId",
1364
+ "type": "bytes32"
1365
+ }
1366
+ ],
1367
+ "name": "tradingBounds",
1368
+ "outputs": [
1369
+ {
1370
+ "internalType": "uint24",
1371
+ "name": "minOpeningMargin",
1372
+ "type": "uint24"
1373
+ },
1374
+ {
1375
+ "internalType": "uint24",
1376
+ "name": "minMakerMarginRatio",
1377
+ "type": "uint24"
1378
+ },
1379
+ {
1380
+ "internalType": "uint24",
1381
+ "name": "maxMakerMarginRatio",
1382
+ "type": "uint24"
1383
+ },
1384
+ {
1385
+ "internalType": "uint24",
1386
+ "name": "makerLiquidationMarginRatio",
1387
+ "type": "uint24"
1388
+ },
1389
+ {
1390
+ "internalType": "uint24",
1391
+ "name": "minTakerMarginRatio",
1392
+ "type": "uint24"
1393
+ },
1394
+ {
1395
+ "internalType": "uint24",
1396
+ "name": "maxTakerMarginRatio",
1397
+ "type": "uint24"
1398
+ },
1399
+ {
1400
+ "internalType": "uint24",
1401
+ "name": "takerLiquidationMarginRatio",
1402
+ "type": "uint24"
1403
+ }
1404
+ ],
1405
+ "stateMutability": "view",
1406
+ "type": "function"
1407
+ },
1408
+ {
1409
+ "inputs": [
1410
+ {
1411
+ "internalType": "bytes",
1412
+ "name": "data",
1413
+ "type": "bytes"
1414
+ }
1415
+ ],
1416
+ "name": "unlockCallback",
1417
+ "outputs": [
1418
+ {
1419
+ "internalType": "bytes",
1420
+ "name": "encodedDelta",
1421
+ "type": "bytes"
1422
+ }
1423
+ ],
1424
+ "stateMutability": "nonpayable",
1425
+ "type": "function"
1426
+ }
1427
+ ];
1428
+
1429
+ // src/utils/liquidity.ts
1430
+ async function estimateLiquidity(context, tickLower, tickUpper, usdScaled) {
1431
+ return await context.walletClient.readContract({
1432
+ address: context.deployments().perpManager,
1433
+ abi: PERP_MANAGER_ABI,
1434
+ functionName: "estimateLiquidityForAmount1",
1435
+ args: [tickLower, tickUpper, usdScaled]
1436
+ });
34
1437
  }
35
1438
 
36
- // src/entities/position.ts
37
- var Position = class _Position {
1439
+ // src/entities/openPosition.ts
1440
+ var OpenPosition = class _OpenPosition {
38
1441
  constructor(context, perpId, positionId) {
39
1442
  this.context = context;
40
1443
  this.perpId = perpId;
@@ -42,92 +1445,377 @@ var Position = class _Position {
42
1445
  }
43
1446
  async closePosition(params) {
44
1447
  const contractParams = {
45
- positionId: this.positionId,
1448
+ posId: this.positionId,
46
1449
  minAmt0Out: scale6Decimals(params.minAmt0Out),
47
1450
  minAmt1Out: scale6Decimals(params.minAmt1Out),
48
1451
  maxAmt1In: scale6Decimals(params.maxAmt1In)
49
1452
  };
50
- const { result, request } = await this.context.publicClient.simulateContract({
51
- address: this.context.perpManagerAddress,
52
- abi: this.context.perpManagerAbi,
1453
+ const { result, request } = await this.context.walletClient.extend(publicActions2).simulateContract({
1454
+ address: this.context.deployments().perpManager,
1455
+ abi: PERP_MANAGER_ABI,
53
1456
  functionName: "closePosition",
54
1457
  args: [this.perpId, contractParams],
55
1458
  account: this.context.walletClient.account
56
1459
  });
57
1460
  await this.context.walletClient.writeContract(request);
58
- const takerPositionId = result[0];
59
- if (takerPositionId === 0n) {
60
- return null;
61
- }
62
- return new _Position(this.context, this.perpId, takerPositionId);
1461
+ return result === null ? null : new _OpenPosition(this.context, this.perpId, result);
1462
+ }
1463
+ async liveDetails() {
1464
+ const { result, request } = await this.context.walletClient.simulateContract({
1465
+ address: this.context.deployments().perpManager,
1466
+ abi: PERP_MANAGER_ABI,
1467
+ functionName: "livePositionDetails",
1468
+ args: [this.perpId, this.positionId],
1469
+ account: this.context.walletClient.account
1470
+ });
1471
+ return {
1472
+ pnl: scaleFrom6Decimals(Number(result[0])),
1473
+ fundingPayment: scaleFrom6Decimals(Number(result[1])),
1474
+ effectiveMargin: scaleFrom6Decimals(Number(result[2])),
1475
+ isLiquidatable: result[3]
1476
+ };
63
1477
  }
64
1478
  };
65
1479
 
66
1480
  // src/entities/perp.ts
1481
+ import { nearestUsableTick } from "@uniswap/v3-sdk";
1482
+ import { gql } from "graphql-request";
1483
+ import { parse } from "graphql";
67
1484
  var Perp = class {
68
1485
  constructor(context, id) {
69
1486
  this.context = context;
70
1487
  this.id = id;
71
1488
  }
72
1489
  // READS
1490
+ async tickSpacing() {
1491
+ return await this.context.walletClient.readContract({
1492
+ address: this.context.deployments().perpManager,
1493
+ abi: PERP_MANAGER_ABI,
1494
+ functionName: "tickSpacing",
1495
+ args: [this.id]
1496
+ });
1497
+ }
1498
+ async mark() {
1499
+ const sqrtPriceX96 = await this.context.walletClient.readContract({
1500
+ address: this.context.deployments().perpManager,
1501
+ abi: PERP_MANAGER_ABI,
1502
+ functionName: "sqrtPriceX96",
1503
+ args: [this.id]
1504
+ });
1505
+ return sqrtPriceX96ToPrice(sqrtPriceX96);
1506
+ }
1507
+ async index() {
1508
+ const beacon = await this.beacon();
1509
+ const query = parse(gql`
1510
+ query ($beaconAddr: Bytes!) {
1511
+ beaconSnapshots(
1512
+ first: 1
1513
+ orderBy: timestamp
1514
+ orderDirection: desc
1515
+ where: { beacon: $beaconAddr }
1516
+ ) { indexPrice }
1517
+ }
1518
+ `);
1519
+ const response = await this.context.goldskyClient.request(query, { beaconAddr: beacon });
1520
+ return Number(response.beaconSnapshots[0].indexPrice);
1521
+ }
1522
+ async beacon() {
1523
+ const query = parse(gql`
1524
+ query ($perpId: Bytes!) {
1525
+ perp(id: $perpId) {
1526
+ beacon { id }
1527
+ }
1528
+ }
1529
+ `);
1530
+ const response = await this.context.goldskyClient.request(query, { perpId: this.id });
1531
+ return response.perp.beacon.id;
1532
+ }
1533
+ async lastIndexUpdate() {
1534
+ const beacon = await this.beacon();
1535
+ const query = parse(gql`
1536
+ query ($beaconAddr: Bytes!) {
1537
+ beaconSnapshots(
1538
+ first: 1
1539
+ orderBy: timestamp
1540
+ orderDirection: desc
1541
+ where: { beacon: $beaconAddr }
1542
+ ) { timestamp }
1543
+ }
1544
+ `);
1545
+ const response = await this.context.goldskyClient.request(query, { beaconAddr: beacon });
1546
+ return Number(response.beaconSnapshots[0].timestamp);
1547
+ }
1548
+ async openInterest() {
1549
+ const query = parse(gql`
1550
+ query ($perpId: Bytes!) {
1551
+ perpSnapshots(
1552
+ first: 1
1553
+ orderBy: timestamp
1554
+ orderDirection: desc
1555
+ where: { perp: $perpId }
1556
+ ) {
1557
+ takerLongNotional
1558
+ takerShortNotional
1559
+ }
1560
+ }
1561
+ `);
1562
+ const response = await this.context.goldskyClient.request(query, { perpId: this.id });
1563
+ return {
1564
+ takerLongNotional: Number(response.perpSnapshots[0].takerLongNotional),
1565
+ takerShortNotional: Number(response.perpSnapshots[0].takerShortNotional)
1566
+ };
1567
+ }
1568
+ async markTimeSeries() {
1569
+ const query = parse(gql`
1570
+ query ($perpId: Bytes!) {
1571
+ perpSnapshots(
1572
+ orderBy: timestamp
1573
+ orderDirection: asc
1574
+ where: { perp: $perpId }
1575
+ ) {
1576
+ timestamp
1577
+ markPrice
1578
+ }
1579
+ }
1580
+ `);
1581
+ const response = await this.context.goldskyClient.request(query, { perpId: this.id });
1582
+ return response.perpSnapshots.map((snapshot) => ({
1583
+ timestamp: Number(snapshot.timestamp),
1584
+ value: Number(snapshot.markPrice)
1585
+ }));
1586
+ }
1587
+ async indexTimeSeries() {
1588
+ const beacon = await this.beacon();
1589
+ const query = parse(gql`
1590
+ query ($beaconAddr: Bytes!) {
1591
+ beaconSnapshots(
1592
+ orderBy: timestamp
1593
+ orderDirection: asc
1594
+ where: { beacon: $beaconAddr }
1595
+ ) {
1596
+ timestamp
1597
+ indexPrice
1598
+ }
1599
+ }
1600
+ `);
1601
+ const response = await this.context.goldskyClient.request(query, { beaconAddr: beacon });
1602
+ return response.beaconSnapshots.map((snapshot) => ({
1603
+ timestamp: Number(snapshot.timestamp),
1604
+ value: Number(snapshot.indexPrice)
1605
+ }));
1606
+ }
1607
+ async fundingRate() {
1608
+ const query = parse(gql`
1609
+ query ($perpId: Bytes!) {
1610
+ perpSnapshots(
1611
+ first: 1
1612
+ orderBy: timestamp
1613
+ orderDirection: desc
1614
+ where: { perp: $perpId }
1615
+ ) {
1616
+ fundingRate
1617
+ }
1618
+ }
1619
+ `);
1620
+ const response = await this.context.goldskyClient.request(query, { perpId: this.id });
1621
+ return Number(response.perpSnapshots[0].fundingRate);
1622
+ }
1623
+ async bounds() {
1624
+ const result = await this.context.walletClient.readContract({
1625
+ address: this.context.deployments().perpManager,
1626
+ abi: PERP_MANAGER_ABI,
1627
+ functionName: "tradingBounds",
1628
+ args: [this.id]
1629
+ });
1630
+ return {
1631
+ minMargin: Number(result[0]),
1632
+ minTakerLeverage: marginRatioToLeverage(result[5]),
1633
+ maxTakerLeverage: marginRatioToLeverage(result[4])
1634
+ };
1635
+ }
1636
+ // TODO
1637
+ async maxTakerNotional(isLong) {
1638
+ return 0;
1639
+ }
1640
+ async simulateTaker(params) {
1641
+ const contractParams = {
1642
+ isLong: params.isLong,
1643
+ margin: scale6Decimals(params.margin),
1644
+ levX96: scaleToX96(params.leverage),
1645
+ unspecifiedAmountLimit: scale6Decimals(params.unspecifiedAmountLimit)
1646
+ };
1647
+ const { result, request } = await this.context.walletClient.simulateContract({
1648
+ address: this.context.deployments().perpManager,
1649
+ abi: PERP_MANAGER_ABI,
1650
+ functionName: "quoteTakerPosition",
1651
+ args: [this.id, contractParams],
1652
+ account: this.context.walletClient.account
1653
+ });
1654
+ return {
1655
+ success: result[0],
1656
+ size: scaleFrom6Decimals(Math.abs(Number(result[1]))),
1657
+ notional: scaleFrom6Decimals(Math.abs(Number(result[2]))),
1658
+ creatorFeeAmt: scaleFrom6Decimals(Number(result[3])),
1659
+ insuranceFeeAmt: scaleFrom6Decimals(Number(result[4])),
1660
+ lpFeeAmt: scaleFrom6Decimals(Number(result[5]))
1661
+ };
1662
+ }
1663
+ async allMakerPositions() {
1664
+ const query = parse(gql`
1665
+ query ($perpId: Bytes!) {
1666
+ openPositions(
1667
+ where: { perp: $perpId, isMaker: true }
1668
+ ) {
1669
+ perp { id }
1670
+ inContractPosId
1671
+ }
1672
+ }
1673
+ `);
1674
+ const response = await this.context.goldskyClient.request(query, { perpId: this.id });
1675
+ return response.openPositions.map((position) => new OpenPosition(this.context, position.perp.id, position.inContractPosId));
1676
+ }
1677
+ async allTakerPositions() {
1678
+ const query = parse(gql`
1679
+ query ($perpId: Bytes!) {
1680
+ openPositions(
1681
+ where: { perp: $perpId, isMaker: false }
1682
+ ) {
1683
+ perp { id }
1684
+ inContractPosId
1685
+ }
1686
+ }
1687
+ `);
1688
+ const response = await this.context.goldskyClient.request(query, { perpId: this.id });
1689
+ return response.openPositions.map((position) => new OpenPosition(this.context, position.perp.id, position.inContractPosId));
1690
+ }
1691
+ async totalOpenMakerPnl() {
1692
+ const positions = await this.allMakerPositions();
1693
+ const liveDetails = await Promise.all(positions.map((position) => position.liveDetails()));
1694
+ return liveDetails.reduce((acc, detail) => acc + detail.pnl - detail.fundingPayment, 0);
1695
+ }
1696
+ async totalOpenTakerPnl() {
1697
+ const positions = await this.allTakerPositions();
1698
+ const liveDetails = await Promise.all(positions.map((position) => position.liveDetails()));
1699
+ return liveDetails.reduce((acc, detail) => acc + detail.pnl - detail.fundingPayment, 0);
1700
+ }
1701
+ async fees() {
1702
+ const result = await this.context.walletClient.readContract({
1703
+ address: this.context.deployments().perpManager,
1704
+ abi: PERP_MANAGER_ABI,
1705
+ functionName: "fees",
1706
+ args: [this.id]
1707
+ });
1708
+ return {
1709
+ creatorFee: scaleFrom6Decimals(result[0]),
1710
+ insuranceFee: scaleFrom6Decimals(result[1]),
1711
+ lpFee: scaleFrom6Decimals(result[2]),
1712
+ liquidationFee: scaleFrom6Decimals(result[3])
1713
+ };
1714
+ }
1715
+ async openInterestTimeSeries() {
1716
+ const query = parse(gql`
1717
+ query ($perpId: Bytes!) {
1718
+ perpSnapshots(
1719
+ orderBy: timestamp
1720
+ orderDirection: asc
1721
+ where: { perp: $perpId }
1722
+ ) {
1723
+ timestamp
1724
+ takerLongNotional
1725
+ takerShortNotional
1726
+ }
1727
+ }
1728
+ `);
1729
+ const response = await this.context.goldskyClient.request(query, { perpId: this.id });
1730
+ return response.perpSnapshots.map((snapshot) => ({
1731
+ timestamp: Number(snapshot.timestamp),
1732
+ value: {
1733
+ takerLongNotional: Number(snapshot.takerLongNotional),
1734
+ takerShortNotional: Number(snapshot.takerShortNotional)
1735
+ }
1736
+ }));
1737
+ }
1738
+ async fundingRateTimeSeries() {
1739
+ const query = parse(gql`
1740
+ query ($perpId: Bytes!) {
1741
+ perpSnapshots(
1742
+ orderBy: timestamp
1743
+ orderDirection: asc
1744
+ where: { perp: $perpId }
1745
+ ) {
1746
+ timestamp
1747
+ fundingRate
1748
+ }
1749
+ }
1750
+ `);
1751
+ const response = await this.context.goldskyClient.request(query, { perpId: this.id });
1752
+ return response.perpSnapshots.map((snapshot) => ({
1753
+ timestamp: Number(snapshot.timestamp),
1754
+ value: Number(snapshot.fundingRate)
1755
+ }));
1756
+ }
73
1757
  // WRITES
74
- // TODO: read tickspacing from perp to adjust tickLower and tickUpper
1758
+ async approveAndOpenMakerPosition(params) {
1759
+ await approveUsdc(this.context, scale6Decimals(params.margin));
1760
+ return await this.openMakerPosition(params);
1761
+ }
1762
+ async approveAndOpenTakerPosition(params) {
1763
+ await approveUsdc(this.context, scale6Decimals(params.margin));
1764
+ return await this.openTakerPosition(params);
1765
+ }
75
1766
  async openMakerPosition(params) {
1767
+ const deployments = this.context.deployments();
1768
+ const tickSpacing = await this.tickSpacing();
1769
+ const scaledUsd = scale6Decimals(params.margin);
1770
+ const tickLower = nearestUsableTick(priceToTick(params.priceLower, true), tickSpacing);
1771
+ const tickUpper = nearestUsableTick(priceToTick(params.priceUpper, false), tickSpacing);
76
1772
  const contractParams = {
77
- margin: scale6Decimals(params.margin),
78
- liquidity: BigInt(params.liquidity),
79
- tickLower: BigInt(params.tickLower),
80
- tickUpper: BigInt(params.tickUpper),
1773
+ margin: scaledUsd,
1774
+ liquidity: await estimateLiquidity(this.context, tickLower, tickUpper, scaledUsd),
1775
+ tickLower,
1776
+ tickUpper,
81
1777
  maxAmt0In: scale6Decimals(params.maxAmt0In),
82
1778
  maxAmt1In: scale6Decimals(params.maxAmt1In)
83
1779
  };
84
- const { result, request } = await this.context.publicClient.simulateContract({
85
- address: this.context.perpManagerAddress,
86
- abi: this.context.perpManagerAbi,
1780
+ const { result, request } = await this.context.walletClient.simulateContract({
1781
+ address: deployments.perpManager,
1782
+ abi: PERP_MANAGER_ABI,
87
1783
  functionName: "openMakerPosition",
88
1784
  args: [this.id, contractParams],
89
1785
  account: this.context.walletClient.account
90
1786
  });
91
1787
  await this.context.walletClient.writeContract(request);
92
- return new Position(this.context, this.id, result[0]);
1788
+ return new OpenPosition(this.context, this.id, result);
93
1789
  }
94
1790
  async openTakerPosition(params) {
95
1791
  const contractParams = {
96
1792
  isLong: params.isLong,
97
1793
  margin: scale6Decimals(params.margin),
98
- leverage: scaleX96(params.leverage),
1794
+ levX96: scaleToX96(params.leverage),
99
1795
  unspecifiedAmountLimit: scale6Decimals(params.unspecifiedAmountLimit)
100
1796
  };
101
- const { result, request } = await this.context.publicClient.simulateContract({
102
- address: this.context.perpManagerAddress,
103
- abi: this.context.perpManagerAbi,
1797
+ const { result, request } = await this.context.walletClient.simulateContract({
1798
+ address: this.context.deployments().perpManager,
1799
+ abi: PERP_MANAGER_ABI,
104
1800
  functionName: "openTakerPosition",
105
1801
  args: [this.id, contractParams],
106
1802
  account: this.context.walletClient.account
107
1803
  });
108
1804
  await this.context.walletClient.writeContract(request);
109
- return new Position(this.context, this.id, result[0]);
110
- }
111
- };
112
-
113
- // src/entities/perp-collection.ts
114
- var PerpCollection = class {
115
- constructor(context, perps) {
116
- this.context = context;
117
- this.perps = perps;
1805
+ return new OpenPosition(this.context, this.id, result);
118
1806
  }
119
1807
  };
120
1808
 
121
1809
  // src/entities/perp-manager.ts
122
- import { gql } from "graphql-request";
123
- import { parse } from "graphql";
1810
+ import { gql as gql2 } from "graphql-request";
1811
+ import { parse as parse2 } from "graphql";
124
1812
  var PerpManager = class {
125
1813
  constructor(context) {
126
1814
  this.context = context;
127
1815
  }
128
1816
  // READS
129
1817
  async getPerps() {
130
- const query = parse(gql`
1818
+ const query = parse2(gql2`
131
1819
  {
132
1820
  perps {
133
1821
  id
@@ -135,32 +1823,369 @@ var PerpManager = class {
135
1823
  }
136
1824
  `);
137
1825
  const response = await this.context.goldskyClient.request(query);
138
- const perps = response.perps.map(
1826
+ return response.perps.map(
139
1827
  (perpData) => new Perp(this.context, perpData.id)
140
1828
  );
141
- return new PerpCollection(this.context, perps);
142
1829
  }
143
1830
  // WRITES
144
1831
  async createPerp(params) {
145
1832
  const sqrtPriceX96 = priceToSqrtPriceX96(params.startingPrice);
146
- const { result, request } = await this.context.publicClient.simulateContract({
147
- address: this.context.perpManagerAddress,
148
- abi: this.context.perpManagerAbi,
1833
+ const contractParams = {
1834
+ startingSqrtPriceX96: sqrtPriceX96,
1835
+ beacon: params.beacon
1836
+ };
1837
+ const { result, request } = await this.context.walletClient.simulateContract({
1838
+ address: this.context.deployments().perpManager,
1839
+ abi: PERP_MANAGER_ABI,
149
1840
  functionName: "createPerp",
150
- args: [sqrtPriceX96, params.beacon],
151
- account: this.context.walletClient.account,
152
- chain: this.context.walletClient.chain
1841
+ args: [contractParams],
1842
+ account: this.context.walletClient.account
153
1843
  });
154
1844
  await this.context.walletClient.writeContract(request);
155
- return new Perp(this.context, result[0]);
1845
+ return new Perp(this.context, result);
156
1846
  }
157
1847
  };
1848
+
1849
+ // src/entities/user.ts
1850
+ import { erc20Abi as erc20Abi2 } from "viem";
1851
+ import { parse as parse3 } from "graphql";
1852
+ import { gql as gql3 } from "graphql-request";
1853
+ var User = class {
1854
+ constructor(context) {
1855
+ this.context = context;
1856
+ if (!context.walletClient.account) throw new Error("Wallet client account not found");
1857
+ this.walletAddress = context.walletClient.account.address;
1858
+ }
1859
+ async usdcBalance() {
1860
+ const result = await this.context.walletClient.readContract({
1861
+ address: this.context.deployments().usdc,
1862
+ abi: erc20Abi2,
1863
+ functionName: "balanceOf",
1864
+ args: [this.walletAddress]
1865
+ });
1866
+ return scaleFrom6Decimals(Number(result));
1867
+ }
1868
+ async openPositions() {
1869
+ const query = parse3(gql3`
1870
+ query ($holder: Bytes!) {
1871
+ openPositions(
1872
+ where: { holder: $holder }
1873
+ ) {
1874
+ perp { id }
1875
+ inContractPosId
1876
+ }
1877
+ }
1878
+ `);
1879
+ const response = await this.context.goldskyClient.request(query, { holder: this.walletAddress });
1880
+ return response.openPositions.map((position) => new OpenPosition(this.context, position.perp.id, position.inContractPosId));
1881
+ }
1882
+ async closedPositions() {
1883
+ const query = parse3(gql3`
1884
+ query ($holder: Bytes!) {
1885
+ closedPositions(
1886
+ where: { holder: $holder }
1887
+ ) {
1888
+ perp { id }
1889
+ wasMaker
1890
+ wasLong
1891
+ pnlAtClose
1892
+ }
1893
+ }
1894
+ `);
1895
+ const response = await this.context.goldskyClient.request(query, { holder: this.walletAddress });
1896
+ return response.closedPositions.map((position) => ({
1897
+ perpId: position.perp.id,
1898
+ wasMaker: position.wasMaker,
1899
+ wasLong: position.wasLong,
1900
+ pnlAtClose: Number(position.pnlAtClose)
1901
+ }));
1902
+ }
1903
+ async realizedPnl() {
1904
+ return (await this.closedPositions()).reduce((acc, position) => acc + position.pnlAtClose, 0);
1905
+ }
1906
+ async unrealizedPnl() {
1907
+ const openPositions = await this.openPositions();
1908
+ const liveDetails = await Promise.all(openPositions.map((position) => position.liveDetails()));
1909
+ return liveDetails.reduce((acc, detail) => acc + detail.pnl - detail.fundingPayment, 0);
1910
+ }
1911
+ };
1912
+
1913
+ // src/abis/beacon.ts
1914
+ var BEACON_ABI = [
1915
+ {
1916
+ "inputs": [
1917
+ {
1918
+ "internalType": "contract IVerifierWrapper",
1919
+ "name": "verifierWrapper",
1920
+ "type": "address"
1921
+ },
1922
+ {
1923
+ "internalType": "uint256",
1924
+ "name": "initialData",
1925
+ "type": "uint256"
1926
+ },
1927
+ {
1928
+ "internalType": "uint32",
1929
+ "name": "initialCardinalityNext",
1930
+ "type": "uint32"
1931
+ }
1932
+ ],
1933
+ "stateMutability": "nonpayable",
1934
+ "type": "constructor"
1935
+ },
1936
+ {
1937
+ "inputs": [
1938
+ {
1939
+ "internalType": "bytes",
1940
+ "name": "proof",
1941
+ "type": "bytes"
1942
+ },
1943
+ {
1944
+ "internalType": "bytes",
1945
+ "name": "publicSignals",
1946
+ "type": "bytes"
1947
+ }
1948
+ ],
1949
+ "name": "InvalidProof",
1950
+ "type": "error"
1951
+ },
1952
+ {
1953
+ "inputs": [
1954
+ {
1955
+ "internalType": "bytes",
1956
+ "name": "proof",
1957
+ "type": "bytes"
1958
+ },
1959
+ {
1960
+ "internalType": "bytes",
1961
+ "name": "publicSignals",
1962
+ "type": "bytes"
1963
+ }
1964
+ ],
1965
+ "name": "ProofAlreadyUsed",
1966
+ "type": "error"
1967
+ },
1968
+ {
1969
+ "anonymous": false,
1970
+ "inputs": [
1971
+ {
1972
+ "indexed": false,
1973
+ "internalType": "uint256",
1974
+ "name": "data",
1975
+ "type": "uint256"
1976
+ }
1977
+ ],
1978
+ "name": "DataUpdated",
1979
+ "type": "event"
1980
+ },
1981
+ {
1982
+ "inputs": [],
1983
+ "name": "MAX_DATA",
1984
+ "outputs": [
1985
+ {
1986
+ "internalType": "int256",
1987
+ "name": "",
1988
+ "type": "int256"
1989
+ }
1990
+ ],
1991
+ "stateMutability": "view",
1992
+ "type": "function"
1993
+ },
1994
+ {
1995
+ "inputs": [],
1996
+ "name": "MIN_DATA",
1997
+ "outputs": [
1998
+ {
1999
+ "internalType": "int256",
2000
+ "name": "",
2001
+ "type": "int256"
2002
+ }
2003
+ ],
2004
+ "stateMutability": "view",
2005
+ "type": "function"
2006
+ },
2007
+ {
2008
+ "inputs": [],
2009
+ "name": "VERIFIER_WRAPPER",
2010
+ "outputs": [
2011
+ {
2012
+ "internalType": "contract IVerifierWrapper",
2013
+ "name": "",
2014
+ "type": "address"
2015
+ }
2016
+ ],
2017
+ "stateMutability": "view",
2018
+ "type": "function"
2019
+ },
2020
+ {
2021
+ "inputs": [],
2022
+ "name": "data",
2023
+ "outputs": [
2024
+ {
2025
+ "internalType": "uint256",
2026
+ "name": "",
2027
+ "type": "uint256"
2028
+ }
2029
+ ],
2030
+ "stateMutability": "view",
2031
+ "type": "function"
2032
+ },
2033
+ {
2034
+ "inputs": [],
2035
+ "name": "getData",
2036
+ "outputs": [
2037
+ {
2038
+ "internalType": "uint256",
2039
+ "name": "",
2040
+ "type": "uint256"
2041
+ },
2042
+ {
2043
+ "internalType": "uint256",
2044
+ "name": "",
2045
+ "type": "uint256"
2046
+ }
2047
+ ],
2048
+ "stateMutability": "view",
2049
+ "type": "function"
2050
+ },
2051
+ {
2052
+ "inputs": [
2053
+ {
2054
+ "internalType": "uint32",
2055
+ "name": "twapSecondsAgo",
2056
+ "type": "uint32"
2057
+ }
2058
+ ],
2059
+ "name": "getTwap",
2060
+ "outputs": [
2061
+ {
2062
+ "internalType": "uint256",
2063
+ "name": "twapPrice",
2064
+ "type": "uint256"
2065
+ }
2066
+ ],
2067
+ "stateMutability": "view",
2068
+ "type": "function"
2069
+ },
2070
+ {
2071
+ "inputs": [
2072
+ {
2073
+ "internalType": "uint32",
2074
+ "name": "cardinalityNext",
2075
+ "type": "uint32"
2076
+ }
2077
+ ],
2078
+ "name": "increaseCardinalityNext",
2079
+ "outputs": [
2080
+ {
2081
+ "internalType": "uint32",
2082
+ "name": "cardinalityNextOld",
2083
+ "type": "uint32"
2084
+ },
2085
+ {
2086
+ "internalType": "uint32",
2087
+ "name": "cardinalityNextNew",
2088
+ "type": "uint32"
2089
+ }
2090
+ ],
2091
+ "stateMutability": "nonpayable",
2092
+ "type": "function"
2093
+ },
2094
+ {
2095
+ "inputs": [],
2096
+ "name": "timestamp",
2097
+ "outputs": [
2098
+ {
2099
+ "internalType": "uint256",
2100
+ "name": "",
2101
+ "type": "uint256"
2102
+ }
2103
+ ],
2104
+ "stateMutability": "view",
2105
+ "type": "function"
2106
+ },
2107
+ {
2108
+ "inputs": [],
2109
+ "name": "twapState",
2110
+ "outputs": [
2111
+ {
2112
+ "internalType": "uint32",
2113
+ "name": "index",
2114
+ "type": "uint32"
2115
+ },
2116
+ {
2117
+ "internalType": "uint32",
2118
+ "name": "cardinality",
2119
+ "type": "uint32"
2120
+ },
2121
+ {
2122
+ "internalType": "uint32",
2123
+ "name": "cardinalityNext",
2124
+ "type": "uint32"
2125
+ }
2126
+ ],
2127
+ "stateMutability": "view",
2128
+ "type": "function"
2129
+ },
2130
+ {
2131
+ "inputs": [
2132
+ {
2133
+ "internalType": "bytes",
2134
+ "name": "proof",
2135
+ "type": "bytes"
2136
+ },
2137
+ {
2138
+ "internalType": "bytes",
2139
+ "name": "publicSignals",
2140
+ "type": "bytes"
2141
+ }
2142
+ ],
2143
+ "name": "updateData",
2144
+ "outputs": [],
2145
+ "stateMutability": "nonpayable",
2146
+ "type": "function"
2147
+ },
2148
+ {
2149
+ "inputs": [
2150
+ {
2151
+ "internalType": "bytes",
2152
+ "name": "",
2153
+ "type": "bytes"
2154
+ }
2155
+ ],
2156
+ "name": "usedProofs",
2157
+ "outputs": [
2158
+ {
2159
+ "internalType": "bool",
2160
+ "name": "",
2161
+ "type": "bool"
2162
+ }
2163
+ ],
2164
+ "stateMutability": "view",
2165
+ "type": "function"
2166
+ }
2167
+ ];
158
2168
  export {
2169
+ BEACON_ABI,
2170
+ BIGINT_1E6,
2171
+ DEPLOYMENTS,
2172
+ NUMBER_1E6,
2173
+ OpenPosition,
2174
+ PERP_MANAGER_ABI,
159
2175
  Perp,
160
2176
  PerpCityContext,
161
2177
  PerpManager,
2178
+ Q96,
2179
+ User,
2180
+ approveUsdc,
2181
+ estimateLiquidity,
2182
+ marginRatioToLeverage,
162
2183
  priceToSqrtPriceX96,
2184
+ priceToTick,
163
2185
  scale6Decimals,
164
- scaleX96
2186
+ scaleFrom6Decimals,
2187
+ scaleFromX96,
2188
+ scaleToX96,
2189
+ sqrtPriceX96ToPrice
165
2190
  };
166
2191
  //# sourceMappingURL=index.mjs.map