@strobelabs/perpcity-sdk 0.1.7 → 0.2.1

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.js CHANGED
@@ -22,74 +22,75 @@ var index_exports = {};
22
22
  __export(index_exports, {
23
23
  BEACON_ABI: () => BEACON_ABI,
24
24
  BIGINT_1E6: () => BIGINT_1E6,
25
- DEPLOYMENTS: () => DEPLOYMENTS,
25
+ ContractError: () => ContractError,
26
+ GraphQLError: () => GraphQLError,
27
+ InsufficientFundsError: () => InsufficientFundsError,
26
28
  NUMBER_1E6: () => NUMBER_1E6,
27
29
  OpenPosition: () => OpenPosition,
28
30
  PERP_MANAGER_ABI: () => PERP_MANAGER_ABI,
29
- Perp: () => Perp,
30
31
  PerpCityContext: () => PerpCityContext,
31
- PerpManager: () => PerpManager,
32
+ PerpCityError: () => PerpCityError,
32
33
  Q96: () => Q96,
33
- User: () => User,
34
+ RPCError: () => RPCError,
35
+ TransactionRejectedError: () => TransactionRejectedError,
36
+ ValidationError: () => ValidationError,
34
37
  approveUsdc: () => approveUsdc,
38
+ closePosition: () => closePosition,
39
+ createPerp: () => createPerp,
35
40
  estimateLiquidity: () => estimateLiquidity,
41
+ getAllMakerPositions: () => getAllMakerPositions,
42
+ getAllTakerPositions: () => getAllTakerPositions,
43
+ getPerpBeacon: () => getPerpBeacon,
44
+ getPerpBounds: () => getPerpBounds,
45
+ getPerpFees: () => getPerpFees,
46
+ getPerpFundingRate: () => getPerpFundingRate,
47
+ getPerpFundingRateTimeSeries: () => getPerpFundingRateTimeSeries,
48
+ getPerpIndex: () => getPerpIndex,
49
+ getPerpIndexTimeSeries: () => getPerpIndexTimeSeries,
50
+ getPerpLastIndexUpdate: () => getPerpLastIndexUpdate,
51
+ getPerpMark: () => getPerpMark,
52
+ getPerpMarkTimeSeries: () => getPerpMarkTimeSeries,
53
+ getPerpOpenInterest: () => getPerpOpenInterest,
54
+ getPerpOpenInterestTimeSeries: () => getPerpOpenInterestTimeSeries,
55
+ getPerpTickSpacing: () => getPerpTickSpacing,
56
+ getPerps: () => getPerps,
57
+ getPositionEffectiveMargin: () => getPositionEffectiveMargin,
58
+ getPositionFundingPayment: () => getPositionFundingPayment,
59
+ getPositionId: () => getPositionId,
60
+ getPositionIsLiquidatable: () => getPositionIsLiquidatable,
61
+ getPositionIsLong: () => getPositionIsLong,
62
+ getPositionIsMaker: () => getPositionIsMaker,
63
+ getPositionLiveDetails: () => getPositionLiveDetails,
64
+ getPositionLiveDetailsFromContract: () => getPositionLiveDetailsFromContract,
65
+ getPositionPerpId: () => getPositionPerpId,
66
+ getPositionPnl: () => getPositionPnl,
67
+ getTotalOpenMakerPnl: () => getTotalOpenMakerPnl,
68
+ getTotalOpenTakerPnl: () => getTotalOpenTakerPnl,
69
+ getUserClosedPositions: () => getUserClosedPositions,
70
+ getUserOpenPositions: () => getUserOpenPositions,
71
+ getUserRealizedPnl: () => getUserRealizedPnl,
72
+ getUserUnrealizedPnl: () => getUserUnrealizedPnl,
73
+ getUserUsdcBalance: () => getUserUsdcBalance,
74
+ getUserWalletAddress: () => getUserWalletAddress,
36
75
  marginRatioToLeverage: () => marginRatioToLeverage,
76
+ openMakerPosition: () => openMakerPosition,
77
+ openTakerPosition: () => openTakerPosition,
78
+ parseContractError: () => parseContractError,
37
79
  priceToSqrtPriceX96: () => priceToSqrtPriceX96,
38
80
  priceToTick: () => priceToTick,
39
81
  scale6Decimals: () => scale6Decimals,
40
82
  scaleFrom6Decimals: () => scaleFrom6Decimals,
41
83
  scaleFromX96: () => scaleFromX96,
42
84
  scaleToX96: () => scaleToX96,
43
- sqrtPriceX96ToPrice: () => sqrtPriceX96ToPrice
85
+ sqrtPriceX96ToPrice: () => sqrtPriceX96ToPrice,
86
+ withErrorHandling: () => withErrorHandling
44
87
  });
45
88
  module.exports = __toCommonJS(index_exports);
46
89
 
47
90
  // src/context.ts
48
91
  var import_graphql_request = require("graphql-request");
49
-
50
- // src/deployments.ts
51
- var DEPLOYMENTS = {
52
- // Base Sepolia
53
- [84532]: {
54
- perpManager: "0x59F1766b77fd67af6c80217C2025A0D536998000",
55
- usdc: "0xC1a5D4E99BB224713dd179eA9CA2Fa6600706210",
56
- goldskyPublic: "https://api.goldsky.com/api/public/project_cmbawn40q70fj01ws4jmsfj7f/subgraphs/perp-city/36ac28e6-20250925_150813/gn",
57
- goldskyPrivate: "https://api.goldsky.com/api/private/project_cmbawn40q70fj01ws4jmsfj7f/subgraphs/perp-city/36ac28e6-20250925_150813/gn"
58
- }
59
- };
60
-
61
- // src/context.ts
62
- var import_viem = require("viem");
63
- var PerpCityContext = class {
64
- constructor(config) {
65
- this.walletClient = config.walletClient.extend(import_viem.publicActions);
66
- const chainId = this.validateChainId();
67
- const deployments = DEPLOYMENTS[chainId];
68
- const headers = {};
69
- let goldskyEndpoint;
70
- if (config.goldskyBearerToken) {
71
- headers.authorization = `Bearer ${config.goldskyBearerToken}`;
72
- goldskyEndpoint = deployments.goldskyPrivate;
73
- } else {
74
- goldskyEndpoint = deployments.goldskyPublic;
75
- }
76
- this.goldskyClient = new import_graphql_request.GraphQLClient(goldskyEndpoint, {
77
- headers
78
- });
79
- }
80
- validateChainId() {
81
- const chainId = this.walletClient.chain?.id;
82
- if (!chainId) throw new Error(`Chain ID is not set.`);
83
- if (!DEPLOYMENTS[chainId]) throw new Error(`Unsupported chainId: ${chainId}.`);
84
- return chainId;
85
- }
86
- deployments() {
87
- return DEPLOYMENTS[this.validateChainId()];
88
- }
89
- };
90
-
91
- // src/entities/openPosition.ts
92
92
  var import_viem3 = require("viem");
93
+ var import_graphql = require("graphql");
93
94
 
94
95
  // src/utils/constants.ts
95
96
  var NUMBER_1E6 = 1e6;
@@ -136,13 +137,13 @@ function scaleFrom6Decimals(value) {
136
137
  }
137
138
 
138
139
  // src/utils/approve.ts
139
- var import_viem2 = require("viem");
140
+ var import_viem = require("viem");
140
141
  var DEFAULT_CONFIRMATIONS = 2;
141
142
  async function approveUsdc(context, amount, confirmations = DEFAULT_CONFIRMATIONS) {
142
143
  const deployments = context.deployments();
143
144
  const { request } = await context.walletClient.simulateContract({
144
145
  address: deployments.usdc,
145
- abi: import_viem2.erc20Abi,
146
+ abi: import_viem.erc20Abi,
146
147
  functionName: "approve",
147
148
  args: [deployments.perpManager, amount],
148
149
  account: context.walletClient.account
@@ -1482,451 +1483,524 @@ async function estimateLiquidity(context, tickLower, tickUpper, usdScaled) {
1482
1483
  });
1483
1484
  }
1484
1485
 
1485
- // src/entities/openPosition.ts
1486
- var OpenPosition = class _OpenPosition {
1487
- constructor(context, perpId, positionId) {
1488
- this.context = context;
1489
- this.perpId = perpId;
1490
- this.positionId = positionId;
1491
- }
1492
- async closePosition(params) {
1493
- const contractParams = {
1494
- posId: this.positionId,
1495
- minAmt0Out: scale6Decimals(params.minAmt0Out),
1496
- minAmt1Out: scale6Decimals(params.minAmt1Out),
1497
- maxAmt1In: scale6Decimals(params.maxAmt1In)
1498
- };
1499
- const { result, request } = await this.context.walletClient.extend(import_viem3.publicActions).simulateContract({
1500
- address: this.context.deployments().perpManager,
1501
- abi: PERP_MANAGER_ABI,
1502
- functionName: "closePosition",
1503
- args: [this.perpId, contractParams],
1504
- account: this.context.walletClient.account
1505
- });
1506
- await this.context.walletClient.writeContract(request);
1507
- return result === null ? null : new _OpenPosition(this.context, this.perpId, result);
1486
+ // src/utils/errors.ts
1487
+ var import_viem2 = require("viem");
1488
+ var PerpCityError = class extends Error {
1489
+ constructor(message, cause) {
1490
+ super(message);
1491
+ this.cause = cause;
1492
+ this.name = "PerpCityError";
1508
1493
  }
1509
- async liveDetails() {
1510
- const { result, request } = await this.context.walletClient.simulateContract({
1511
- address: this.context.deployments().perpManager,
1512
- abi: PERP_MANAGER_ABI,
1513
- functionName: "livePositionDetails",
1514
- args: [this.perpId, this.positionId],
1515
- account: this.context.walletClient.account
1516
- });
1517
- return {
1518
- pnl: scaleFrom6Decimals(Number(result[0])),
1519
- fundingPayment: scaleFrom6Decimals(Number(result[1])),
1520
- effectiveMargin: scaleFrom6Decimals(Number(result[2])),
1521
- isLiquidatable: result[3]
1522
- };
1494
+ };
1495
+ var ContractError = class extends PerpCityError {
1496
+ constructor(message, errorName, args, cause) {
1497
+ super(message, cause);
1498
+ this.errorName = errorName;
1499
+ this.args = args;
1500
+ this.name = "ContractError";
1523
1501
  }
1524
1502
  };
1525
-
1526
- // src/entities/perp.ts
1527
- var import_v3_sdk = require("@uniswap/v3-sdk");
1528
- var import_graphql_request2 = require("graphql-request");
1529
- var import_graphql = require("graphql");
1530
- var Perp = class {
1531
- constructor(context, id) {
1532
- this.context = context;
1533
- this.id = id;
1503
+ var TransactionRejectedError = class extends PerpCityError {
1504
+ constructor(message = "Transaction rejected by user", cause) {
1505
+ super(message, cause);
1506
+ this.name = "TransactionRejectedError";
1534
1507
  }
1535
- // READS
1536
- async tickSpacing() {
1537
- return await this.context.walletClient.readContract({
1538
- address: this.context.deployments().perpManager,
1539
- abi: PERP_MANAGER_ABI,
1540
- functionName: "tickSpacing",
1541
- args: [this.id]
1542
- });
1508
+ };
1509
+ var InsufficientFundsError = class extends PerpCityError {
1510
+ constructor(message = "Insufficient funds for transaction", cause) {
1511
+ super(message, cause);
1512
+ this.name = "InsufficientFundsError";
1543
1513
  }
1544
- async mark() {
1545
- const sqrtPriceX96 = await this.context.walletClient.readContract({
1546
- address: this.context.deployments().perpManager,
1547
- abi: PERP_MANAGER_ABI,
1548
- functionName: "sqrtPriceX96",
1549
- args: [this.id]
1550
- });
1551
- return sqrtPriceX96ToPrice(sqrtPriceX96);
1514
+ };
1515
+ var GraphQLError = class extends PerpCityError {
1516
+ constructor(message, cause) {
1517
+ super(message, cause);
1518
+ this.name = "GraphQLError";
1552
1519
  }
1553
- async index() {
1554
- const beacon = await this.beacon();
1555
- const query = (0, import_graphql.parse)(import_graphql_request2.gql`
1556
- query ($beaconAddr: Bytes!) {
1557
- beaconSnapshots(
1558
- first: 1
1559
- orderBy: timestamp
1560
- orderDirection: desc
1561
- where: { beacon: $beaconAddr }
1562
- ) { indexPrice }
1563
- }
1564
- `);
1565
- const response = await this.context.goldskyClient.request(query, { beaconAddr: beacon });
1566
- return Number(response.beaconSnapshots[0].indexPrice);
1520
+ };
1521
+ var RPCError = class extends PerpCityError {
1522
+ constructor(message, cause) {
1523
+ super(message, cause);
1524
+ this.name = "RPCError";
1567
1525
  }
1568
- async beacon() {
1569
- const query = (0, import_graphql.parse)(import_graphql_request2.gql`
1570
- query ($perpId: Bytes!) {
1571
- perp(id: $perpId) {
1572
- beacon { id }
1573
- }
1574
- }
1575
- `);
1576
- const response = await this.context.goldskyClient.request(query, { perpId: this.id });
1577
- return response.perp.beacon.id;
1526
+ };
1527
+ var ValidationError = class extends PerpCityError {
1528
+ constructor(message, cause) {
1529
+ super(message, cause);
1530
+ this.name = "ValidationError";
1578
1531
  }
1579
- async lastIndexUpdate() {
1580
- const beacon = await this.beacon();
1581
- const query = (0, import_graphql.parse)(import_graphql_request2.gql`
1582
- query ($beaconAddr: Bytes!) {
1583
- beaconSnapshots(
1584
- first: 1
1585
- orderBy: timestamp
1586
- orderDirection: desc
1587
- where: { beacon: $beaconAddr }
1588
- ) { timestamp }
1589
- }
1590
- `);
1591
- const response = await this.context.goldskyClient.request(query, { beaconAddr: beacon });
1592
- return Number(response.beaconSnapshots[0].timestamp);
1532
+ };
1533
+ function parseContractError(error) {
1534
+ if (error instanceof PerpCityError) {
1535
+ return error;
1593
1536
  }
1594
- async openInterest() {
1595
- const query = (0, import_graphql.parse)(import_graphql_request2.gql`
1596
- query ($perpId: Bytes!) {
1597
- perpSnapshots(
1598
- first: 1
1599
- orderBy: timestamp
1600
- orderDirection: desc
1601
- where: { perp: $perpId }
1602
- ) {
1603
- takerLongNotional
1604
- takerShortNotional
1605
- }
1606
- }
1607
- `);
1608
- const response = await this.context.goldskyClient.request(query, { perpId: this.id });
1609
- return {
1610
- takerLongNotional: Number(response.perpSnapshots[0].takerLongNotional),
1611
- takerShortNotional: Number(response.perpSnapshots[0].takerShortNotional)
1612
- };
1537
+ if (error instanceof import_viem2.BaseError) {
1538
+ const revertError = error.walk((err) => err instanceof import_viem2.ContractFunctionRevertedError);
1539
+ if (revertError instanceof import_viem2.ContractFunctionRevertedError) {
1540
+ const errorName = revertError.data?.errorName ?? "Unknown";
1541
+ const args = revertError.data?.args ?? [];
1542
+ const message = formatContractError(errorName, args);
1543
+ return new ContractError(message, errorName, args, error);
1544
+ }
1545
+ if (error.message?.includes("User rejected") || error.code === 4001) {
1546
+ return new TransactionRejectedError(error.message, error);
1547
+ }
1548
+ if (error.message?.includes("insufficient funds")) {
1549
+ return new InsufficientFundsError(error.message, error);
1550
+ }
1551
+ return new PerpCityError(error.shortMessage || error.message, error);
1613
1552
  }
1614
- async markTimeSeries() {
1615
- const query = (0, import_graphql.parse)(import_graphql_request2.gql`
1616
- query ($perpId: Bytes!) {
1617
- perpSnapshots(
1618
- orderBy: timestamp
1619
- orderDirection: asc
1620
- where: { perp: $perpId }
1621
- ) {
1622
- timestamp
1623
- markPrice
1624
- }
1625
- }
1626
- `);
1627
- const response = await this.context.goldskyClient.request(query, { perpId: this.id });
1628
- return response.perpSnapshots.map((snapshot) => ({
1629
- timestamp: Number(snapshot.timestamp),
1630
- value: Number(snapshot.markPrice)
1631
- }));
1553
+ if (error instanceof Error) {
1554
+ return new PerpCityError(error.message, error);
1632
1555
  }
1633
- async indexTimeSeries() {
1634
- const beacon = await this.beacon();
1635
- const query = (0, import_graphql.parse)(import_graphql_request2.gql`
1636
- query ($beaconAddr: Bytes!) {
1637
- beaconSnapshots(
1638
- orderBy: timestamp
1639
- orderDirection: asc
1640
- where: { beacon: $beaconAddr }
1641
- ) {
1642
- timestamp
1643
- indexPrice
1644
- }
1645
- }
1646
- `);
1647
- const response = await this.context.goldskyClient.request(query, { beaconAddr: beacon });
1648
- return response.beaconSnapshots.map((snapshot) => ({
1649
- timestamp: Number(snapshot.timestamp),
1650
- value: Number(snapshot.indexPrice)
1651
- }));
1556
+ return new PerpCityError(String(error));
1557
+ }
1558
+ function formatContractError(errorName, args) {
1559
+ switch (errorName) {
1560
+ case "InvalidBeaconAddress":
1561
+ return `Invalid beacon address: ${args[0]}`;
1562
+ case "InvalidTradingFeeSplits":
1563
+ return `Invalid trading fee splits. Insurance split: ${args[0]}, Creator split: ${args[1]}`;
1564
+ case "InvalidMaxOpeningLev":
1565
+ return `Invalid maximum opening leverage: ${args[0]}`;
1566
+ case "InvalidLiquidationLev":
1567
+ return `Invalid liquidation leverage: ${args[0]}. Must be less than max opening leverage: ${args[1]}`;
1568
+ case "InvalidLiquidationFee":
1569
+ return `Invalid liquidation fee: ${args[0]}`;
1570
+ case "InvalidLiquidatorFeeSplit":
1571
+ return `Invalid liquidator fee split: ${args[0]}`;
1572
+ case "InvalidClose":
1573
+ return `Cannot close position. Caller: ${args[0]}, Holder: ${args[1]}, Is Liquidated: ${args[2]}`;
1574
+ case "InvalidCaller":
1575
+ return `Invalid caller. Expected: ${args[1]}, Got: ${args[0]}`;
1576
+ case "InvalidLiquidity":
1577
+ return `Invalid liquidity amount: ${args[0]}`;
1578
+ case "InvalidMargin":
1579
+ return `Invalid margin amount: ${args[0]}`;
1580
+ case "InvalidLevX96":
1581
+ return `Invalid leverage: ${args[0]}. Maximum allowed: ${args[1]}`;
1582
+ case "MakerPositionLocked":
1583
+ return `Maker position is locked until ${new Date(Number(args[1]) * 1e3).toISOString()}. Current time: ${new Date(Number(args[0]) * 1e3).toISOString()}`;
1584
+ case "MaximumAmountExceeded":
1585
+ return `Maximum amount exceeded. Maximum: ${args[0]}, Requested: ${args[1]}`;
1586
+ case "MinimumAmountInsufficient":
1587
+ return `Minimum amount not met. Required: ${args[0]}, Received: ${args[1]}`;
1588
+ case "PriceImpactTooHigh":
1589
+ return `Price impact too high. Current price: ${args[0]}, Min acceptable: ${args[1]}, Max acceptable: ${args[2]}`;
1590
+ case "SwapReverted":
1591
+ return "Swap failed. This may be due to insufficient liquidity or slippage tolerance.";
1592
+ case "ZeroSizePosition":
1593
+ return `Cannot create zero-size position. Perp delta: ${args[0]}, USD delta: ${args[1]}`;
1594
+ case "InvalidFundingInterval":
1595
+ return `Invalid funding interval: ${args[0]}`;
1596
+ case "InvalidPriceImpactBand":
1597
+ return `Invalid price impact band: ${args[0]}`;
1598
+ case "InvalidMarketDeathThreshold":
1599
+ return `Invalid market death threshold: ${args[0]}`;
1600
+ case "InvalidTickRange":
1601
+ return `Invalid tick range. Lower: ${args[0]}, Upper: ${args[1]}`;
1602
+ case "MarketNotKillable":
1603
+ return `Market health (${args[0]}) is above death threshold (${args[1]}). Market cannot be killed yet.`;
1604
+ case "InvalidStartingSqrtPriceX96":
1605
+ return `Invalid starting sqrt price: ${args[0]}`;
1606
+ default:
1607
+ return `Contract error: ${errorName}${args.length > 0 ? ` (${args.join(", ")})` : ""}`;
1652
1608
  }
1653
- async fundingRate() {
1654
- const query = (0, import_graphql.parse)(import_graphql_request2.gql`
1655
- query ($perpId: Bytes!) {
1656
- perpSnapshots(
1657
- first: 1
1658
- orderBy: timestamp
1659
- orderDirection: desc
1660
- where: { perp: $perpId }
1661
- ) {
1662
- fundingRate
1663
- }
1664
- }
1665
- `);
1666
- const response = await this.context.goldskyClient.request(query, { perpId: this.id });
1667
- return Number(response.perpSnapshots[0].fundingRate);
1609
+ }
1610
+ async function withErrorHandling(fn, context) {
1611
+ try {
1612
+ return await fn();
1613
+ } catch (error) {
1614
+ const parsedError = parseContractError(error);
1615
+ parsedError.message = `${context}: ${parsedError.message}`;
1616
+ throw parsedError;
1668
1617
  }
1669
- async bounds() {
1670
- const result = await this.context.walletClient.readContract({
1671
- address: this.context.deployments().perpManager,
1672
- abi: PERP_MANAGER_ABI,
1673
- functionName: "tradingBounds",
1674
- args: [this.id]
1618
+ }
1619
+
1620
+ // src/context.ts
1621
+ var import_viem4 = require("viem");
1622
+ var PerpCityContext = class {
1623
+ constructor(config) {
1624
+ this.walletClient = config.walletClient.extend(import_viem3.publicActions);
1625
+ this._deployments = config.deployments;
1626
+ const headers = {};
1627
+ if (config.goldskyBearerToken) {
1628
+ headers.authorization = `Bearer ${config.goldskyBearerToken}`;
1629
+ }
1630
+ this.goldskyClient = new import_graphql_request.GraphQLClient(config.goldskyEndpoint, {
1631
+ headers
1675
1632
  });
1676
- return {
1677
- minMargin: Number(result[0]),
1678
- minTakerLeverage: marginRatioToLeverage(result[5]),
1679
- maxTakerLeverage: marginRatioToLeverage(result[4])
1680
- };
1681
- }
1682
- // TODO
1683
- async maxTakerNotional(isLong) {
1684
- return 0;
1685
1633
  }
1686
- async simulateTaker(params) {
1687
- const contractParams = {
1688
- isLong: params.isLong,
1689
- margin: scale6Decimals(params.margin),
1690
- levX96: scaleToX96(params.leverage),
1691
- unspecifiedAmountLimit: scale6Decimals(params.unspecifiedAmountLimit)
1692
- };
1693
- const { result, request } = await this.context.walletClient.simulateContract({
1694
- address: this.context.deployments().perpManager,
1695
- abi: PERP_MANAGER_ABI,
1696
- functionName: "quoteTakerPosition",
1697
- args: [this.id, contractParams],
1698
- account: this.context.walletClient.account
1699
- });
1700
- return {
1701
- success: result[0],
1702
- size: scaleFrom6Decimals(Math.abs(Number(result[1]))),
1703
- notional: scaleFrom6Decimals(Math.abs(Number(result[2]))),
1704
- creatorFeeAmt: scaleFrom6Decimals(Number(result[3])),
1705
- insuranceFeeAmt: scaleFrom6Decimals(Number(result[4])),
1706
- lpFeeAmt: scaleFrom6Decimals(Number(result[5]))
1707
- };
1634
+ deployments() {
1635
+ return this._deployments;
1708
1636
  }
1709
- async allMakerPositions() {
1710
- const query = (0, import_graphql.parse)(import_graphql_request2.gql`
1711
- query ($perpId: Bytes!) {
1712
- openPositions(
1713
- where: { perp: $perpId, isMaker: true }
1714
- ) {
1715
- perp { id }
1716
- inContractPosId
1637
+ // Optimized batch data fetching methods
1638
+ async fetchPerpData(perpId) {
1639
+ return withErrorHandling(async () => {
1640
+ const perpQuery = (0, import_graphql.parse)(`
1641
+ query ($perpId: Bytes!) {
1642
+ perp(id: $perpId) {
1643
+ beacon { id }
1644
+ }
1645
+ perpSnapshots(
1646
+ orderBy: timestamp
1647
+ orderDirection: asc
1648
+ where: { perp: $perpId }
1649
+ ) {
1650
+ timestamp
1651
+ markPrice
1652
+ takerLongNotional
1653
+ takerShortNotional
1654
+ fundingRate
1655
+ }
1717
1656
  }
1718
- }
1719
- `);
1720
- const response = await this.context.goldskyClient.request(query, { perpId: this.id });
1721
- return response.openPositions.map((position) => new OpenPosition(this.context, position.perp.id, position.inContractPosId));
1722
- }
1723
- async allTakerPositions() {
1724
- const query = (0, import_graphql.parse)(import_graphql_request2.gql`
1725
- query ($perpId: Bytes!) {
1726
- openPositions(
1727
- where: { perp: $perpId, isMaker: false }
1728
- ) {
1729
- perp { id }
1730
- inContractPosId
1657
+ `);
1658
+ const beaconQuery = (0, import_graphql.parse)(`
1659
+ query ($beaconAddr: Bytes!) {
1660
+ beaconSnapshots(
1661
+ orderBy: timestamp
1662
+ orderDirection: asc
1663
+ where: { beacon: $beaconAddr }
1664
+ ) {
1665
+ timestamp
1666
+ indexPrice
1667
+ }
1731
1668
  }
1732
- }
1733
- `);
1734
- const response = await this.context.goldskyClient.request(query, { perpId: this.id });
1735
- return response.openPositions.map((position) => new OpenPosition(this.context, position.perp.id, position.inContractPosId));
1736
- }
1737
- async totalOpenMakerPnl() {
1738
- const positions = await this.allMakerPositions();
1739
- const liveDetails = await Promise.all(positions.map((position) => position.liveDetails()));
1740
- return liveDetails.reduce((acc, detail) => acc + detail.pnl - detail.fundingPayment, 0);
1669
+ `);
1670
+ let perpResponse;
1671
+ try {
1672
+ perpResponse = await this.goldskyClient.request(perpQuery, { perpId });
1673
+ } catch (error) {
1674
+ throw new GraphQLError(`Failed to fetch perp data for ${perpId}: ${error instanceof Error ? error.message : String(error)}`, error instanceof Error ? error : void 0);
1675
+ }
1676
+ if (!perpResponse.perp || !perpResponse.perp.beacon) {
1677
+ throw new GraphQLError(`Perp ${perpId} not found or has no beacon`);
1678
+ }
1679
+ let beaconResponse;
1680
+ let contractData;
1681
+ try {
1682
+ [beaconResponse, contractData] = await Promise.all([
1683
+ this.goldskyClient.request(beaconQuery, { beaconAddr: perpResponse.perp.beacon.id }),
1684
+ this.fetchPerpContractData(perpId)
1685
+ ]);
1686
+ } catch (error) {
1687
+ if (error instanceof GraphQLError || error instanceof RPCError) {
1688
+ throw error;
1689
+ }
1690
+ throw new GraphQLError(`Failed to fetch beacon or contract data: ${error instanceof Error ? error.message : String(error)}`, error instanceof Error ? error : void 0);
1691
+ }
1692
+ if (perpResponse.perpSnapshots.length === 0) {
1693
+ throw new GraphQLError(`No perpSnapshots found for perp ${perpId}. This perp may be newly created with no trading activity yet.`);
1694
+ }
1695
+ if (beaconResponse.beaconSnapshots.length === 0) {
1696
+ throw new GraphQLError(`No beaconSnapshots found for perp ${perpId} beacon ${perpResponse.perp.beacon.id}. The beacon may not have any price updates yet.`);
1697
+ }
1698
+ const markTimeSeries = perpResponse.perpSnapshots.map((snapshot) => ({
1699
+ timestamp: Number(snapshot.timestamp),
1700
+ value: Number(snapshot.markPrice)
1701
+ }));
1702
+ const indexTimeSeries = beaconResponse.beaconSnapshots.map((snapshot) => ({
1703
+ timestamp: Number(snapshot.timestamp),
1704
+ value: Number(snapshot.indexPrice)
1705
+ }));
1706
+ const openInterestTimeSeries = perpResponse.perpSnapshots.map((snapshot) => ({
1707
+ timestamp: Number(snapshot.timestamp),
1708
+ value: {
1709
+ takerLongNotional: Number(snapshot.takerLongNotional),
1710
+ takerShortNotional: Number(snapshot.takerShortNotional)
1711
+ }
1712
+ }));
1713
+ const fundingRateTimeSeries = perpResponse.perpSnapshots.map((snapshot) => ({
1714
+ timestamp: Number(snapshot.timestamp),
1715
+ value: Number(snapshot.fundingRate)
1716
+ }));
1717
+ const latestSnapshot = perpResponse.perpSnapshots[perpResponse.perpSnapshots.length - 1];
1718
+ const latestBeaconSnapshot = beaconResponse.beaconSnapshots[beaconResponse.beaconSnapshots.length - 1];
1719
+ const perpData = {
1720
+ id: perpId,
1721
+ tickSpacing: contractData.tickSpacing,
1722
+ mark: sqrtPriceX96ToPrice(contractData.sqrtPriceX96),
1723
+ index: Number(latestBeaconSnapshot.indexPrice),
1724
+ beacon: perpResponse.perp.beacon.id,
1725
+ lastIndexUpdate: Number(latestBeaconSnapshot.timestamp),
1726
+ openInterest: {
1727
+ takerLongNotional: Number(latestSnapshot.takerLongNotional),
1728
+ takerShortNotional: Number(latestSnapshot.takerShortNotional)
1729
+ },
1730
+ markTimeSeries,
1731
+ indexTimeSeries,
1732
+ fundingRate: Number(latestSnapshot.fundingRate),
1733
+ bounds: contractData.bounds,
1734
+ fees: contractData.fees,
1735
+ openInterestTimeSeries,
1736
+ fundingRateTimeSeries,
1737
+ totalOpenMakerPnl: 0,
1738
+ // These will be calculated by functions
1739
+ totalOpenTakerPnl: 0
1740
+ // These will be calculated by functions
1741
+ };
1742
+ return perpData;
1743
+ }, `fetchPerpData for perp ${perpId}`);
1741
1744
  }
1742
- async totalOpenTakerPnl() {
1743
- const positions = await this.allTakerPositions();
1744
- const liveDetails = await Promise.all(positions.map((position) => position.liveDetails()));
1745
- return liveDetails.reduce((acc, detail) => acc + detail.pnl - detail.fundingPayment, 0);
1745
+ async fetchPerpContractData(perpId) {
1746
+ return withErrorHandling(async () => {
1747
+ const [tickSpacing, sqrtPriceX96, boundsRaw, feesRaw] = await Promise.all([
1748
+ this.walletClient.readContract({
1749
+ address: this.deployments().perpManager,
1750
+ abi: PERP_MANAGER_ABI,
1751
+ functionName: "tickSpacing",
1752
+ args: [perpId]
1753
+ }),
1754
+ this.walletClient.readContract({
1755
+ address: this.deployments().perpManager,
1756
+ abi: PERP_MANAGER_ABI,
1757
+ functionName: "sqrtPriceX96",
1758
+ args: [perpId]
1759
+ }),
1760
+ this.walletClient.readContract({
1761
+ address: this.deployments().perpManager,
1762
+ abi: PERP_MANAGER_ABI,
1763
+ functionName: "tradingBounds",
1764
+ args: [perpId]
1765
+ }),
1766
+ this.walletClient.readContract({
1767
+ address: this.deployments().perpManager,
1768
+ abi: PERP_MANAGER_ABI,
1769
+ functionName: "fees",
1770
+ args: [perpId]
1771
+ })
1772
+ ]);
1773
+ const bounds = boundsRaw;
1774
+ const fees = feesRaw;
1775
+ return {
1776
+ tickSpacing: Number(tickSpacing),
1777
+ sqrtPriceX96,
1778
+ bounds: {
1779
+ minMargin: Number((0, import_viem3.formatUnits)(bounds[0], 6)),
1780
+ minTakerLeverage: marginRatioToLeverage(Number((0, import_viem3.formatUnits)(bounds[4], 6))),
1781
+ maxTakerLeverage: marginRatioToLeverage(Number((0, import_viem3.formatUnits)(bounds[5], 6)))
1782
+ },
1783
+ fees: {
1784
+ creatorFee: Number((0, import_viem3.formatUnits)(fees[0], 6)),
1785
+ insuranceFee: Number((0, import_viem3.formatUnits)(fees[1], 6)),
1786
+ lpFee: Number((0, import_viem3.formatUnits)(fees[2], 6)),
1787
+ liquidationFee: Number((0, import_viem3.formatUnits)(fees[3], 6))
1788
+ }
1789
+ };
1790
+ }, `fetchPerpContractData for perp ${perpId}`);
1746
1791
  }
1747
- async fees() {
1748
- const result = await this.context.walletClient.readContract({
1749
- address: this.context.deployments().perpManager,
1750
- abi: PERP_MANAGER_ABI,
1751
- functionName: "fees",
1752
- args: [this.id]
1753
- });
1754
- return {
1755
- creatorFee: scaleFrom6Decimals(result[0]),
1756
- insuranceFee: scaleFrom6Decimals(result[1]),
1757
- lpFee: scaleFrom6Decimals(result[2]),
1758
- liquidationFee: scaleFrom6Decimals(result[3])
1759
- };
1792
+ /**
1793
+ * Fetch comprehensive perp data with all related information in a single batched request
1794
+ */
1795
+ async getPerpData(perpId) {
1796
+ return this.fetchPerpData(perpId);
1760
1797
  }
1761
- async openInterestTimeSeries() {
1762
- const query = (0, import_graphql.parse)(import_graphql_request2.gql`
1763
- query ($perpId: Bytes!) {
1798
+ /**
1799
+ * Fetch data for multiple perps efficiently with true batching
1800
+ * This fetches all perps in just 2 Goldsky requests total (not 2N!)
1801
+ */
1802
+ async getMultiplePerpData(perpIds) {
1803
+ if (perpIds.length === 0) {
1804
+ return /* @__PURE__ */ new Map();
1805
+ }
1806
+ if (perpIds.length === 1) {
1807
+ const data = await this.fetchPerpData(perpIds[0]);
1808
+ return /* @__PURE__ */ new Map([[perpIds[0], data]]);
1809
+ }
1810
+ const batchPerpQuery = (0, import_graphql.parse)(`
1811
+ query ($perpIds: [Bytes!]!) {
1812
+ perps(where: { id_in: $perpIds }) {
1813
+ id
1814
+ beacon { id }
1815
+ }
1764
1816
  perpSnapshots(
1765
1817
  orderBy: timestamp
1766
1818
  orderDirection: asc
1767
- where: { perp: $perpId }
1819
+ where: { perp_in: $perpIds }
1768
1820
  ) {
1821
+ perp { id }
1769
1822
  timestamp
1823
+ markPrice
1770
1824
  takerLongNotional
1771
1825
  takerShortNotional
1826
+ fundingRate
1772
1827
  }
1773
1828
  }
1774
1829
  `);
1775
- const response = await this.context.goldskyClient.request(query, { perpId: this.id });
1776
- return response.perpSnapshots.map((snapshot) => ({
1777
- timestamp: Number(snapshot.timestamp),
1778
- value: {
1779
- takerLongNotional: Number(snapshot.takerLongNotional),
1780
- takerShortNotional: Number(snapshot.takerShortNotional)
1781
- }
1782
- }));
1783
- }
1784
- async fundingRateTimeSeries() {
1785
- const query = (0, import_graphql.parse)(import_graphql_request2.gql`
1786
- query ($perpId: Bytes!) {
1787
- perpSnapshots(
1830
+ const perpResponse = await this.goldskyClient.request(batchPerpQuery, { perpIds });
1831
+ const beaconIds = [...new Set(perpResponse.perps.map((p) => p.beacon.id))];
1832
+ const batchBeaconQuery = (0, import_graphql.parse)(`
1833
+ query ($beaconIds: [Bytes!]!) {
1834
+ beaconSnapshots(
1788
1835
  orderBy: timestamp
1789
1836
  orderDirection: asc
1790
- where: { perp: $perpId }
1837
+ where: { beacon_in: $beaconIds }
1791
1838
  ) {
1839
+ beacon { id }
1792
1840
  timestamp
1793
- fundingRate
1841
+ indexPrice
1794
1842
  }
1795
1843
  }
1796
1844
  `);
1797
- const response = await this.context.goldskyClient.request(query, { perpId: this.id });
1798
- return response.perpSnapshots.map((snapshot) => ({
1799
- timestamp: Number(snapshot.timestamp),
1800
- value: Number(snapshot.fundingRate)
1801
- }));
1802
- }
1803
- // WRITES
1804
- async approveAndOpenMakerPosition(params) {
1805
- await approveUsdc(this.context, scale6Decimals(params.margin));
1806
- return await this.openMakerPosition(params);
1807
- }
1808
- async approveAndOpenTakerPosition(params) {
1809
- await approveUsdc(this.context, scale6Decimals(params.margin));
1810
- return await this.openTakerPosition(params);
1811
- }
1812
- async openMakerPosition(params) {
1813
- const deployments = this.context.deployments();
1814
- const tickSpacing = await this.tickSpacing();
1815
- const scaledUsd = scale6Decimals(params.margin);
1816
- const tickLower = (0, import_v3_sdk.nearestUsableTick)(priceToTick(params.priceLower, true), tickSpacing);
1817
- const tickUpper = (0, import_v3_sdk.nearestUsableTick)(priceToTick(params.priceUpper, false), tickSpacing);
1818
- const contractParams = {
1819
- margin: scaledUsd,
1820
- liquidity: await estimateLiquidity(this.context, tickLower, tickUpper, scaledUsd),
1821
- tickLower,
1822
- tickUpper,
1823
- maxAmt0In: scale6Decimals(params.maxAmt0In),
1824
- maxAmt1In: scale6Decimals(params.maxAmt1In)
1825
- };
1826
- const { result, request } = await this.context.walletClient.simulateContract({
1827
- address: deployments.perpManager,
1828
- abi: PERP_MANAGER_ABI,
1829
- functionName: "openMakerPosition",
1830
- args: [this.id, contractParams],
1831
- account: this.context.walletClient.account
1845
+ const [beaconResponse, contractDataMap] = await Promise.all([
1846
+ this.goldskyClient.request(batchBeaconQuery, { beaconIds }),
1847
+ this.fetchMultiplePerpContractData(perpIds)
1848
+ ]);
1849
+ const snapshotsByPerp = /* @__PURE__ */ new Map();
1850
+ perpResponse.perpSnapshots.forEach((snapshot) => {
1851
+ const perpId = snapshot.perp.id;
1852
+ if (!snapshotsByPerp.has(perpId)) {
1853
+ snapshotsByPerp.set(perpId, []);
1854
+ }
1855
+ snapshotsByPerp.get(perpId).push(snapshot);
1832
1856
  });
1833
- await this.context.walletClient.writeContract(request);
1834
- return new OpenPosition(this.context, this.id, result);
1835
- }
1836
- async openTakerPosition(params) {
1837
- const contractParams = {
1838
- isLong: params.isLong,
1839
- margin: scale6Decimals(params.margin),
1840
- levX96: scaleToX96(params.leverage),
1841
- unspecifiedAmountLimit: scale6Decimals(params.unspecifiedAmountLimit)
1842
- };
1843
- const { result, request } = await this.context.walletClient.simulateContract({
1844
- address: this.context.deployments().perpManager,
1845
- abi: PERP_MANAGER_ABI,
1846
- functionName: "openTakerPosition",
1847
- args: [this.id, contractParams],
1848
- account: this.context.walletClient.account
1857
+ const snapshotsByBeacon = /* @__PURE__ */ new Map();
1858
+ beaconResponse.beaconSnapshots.forEach((snapshot) => {
1859
+ const beaconId = snapshot.beacon.id;
1860
+ if (!snapshotsByBeacon.has(beaconId)) {
1861
+ snapshotsByBeacon.set(beaconId, []);
1862
+ }
1863
+ snapshotsByBeacon.get(beaconId).push(snapshot);
1849
1864
  });
1850
- await this.context.walletClient.writeContract(request);
1851
- return new OpenPosition(this.context, this.id, result);
1852
- }
1853
- };
1854
-
1855
- // src/entities/perp-manager.ts
1856
- var import_graphql_request3 = require("graphql-request");
1857
- var import_graphql2 = require("graphql");
1858
- var PerpManager = class {
1859
- constructor(context) {
1860
- this.context = context;
1861
- }
1862
- // READS
1863
- async getPerps() {
1864
- const query = (0, import_graphql2.parse)(import_graphql_request3.gql`
1865
- {
1866
- perps {
1867
- id
1865
+ const perpLookup = new Map(
1866
+ perpResponse.perps.map((p) => [
1867
+ p.id,
1868
+ p
1869
+ ])
1870
+ );
1871
+ const resultMap = /* @__PURE__ */ new Map();
1872
+ for (const perpId of perpIds) {
1873
+ const perp = perpLookup.get(perpId);
1874
+ if (!perp) {
1875
+ throw new Error(`Perp ${perpId} not found`);
1876
+ }
1877
+ const beaconId = perp.beacon.id;
1878
+ const snapshots = snapshotsByPerp.get(perpId) || [];
1879
+ const beaconSnapshots = snapshotsByBeacon.get(beaconId) || [];
1880
+ const contractData = contractDataMap.get(perpId);
1881
+ if (!contractData) {
1882
+ throw new Error(`Contract data for perp ${perpId} not found`);
1883
+ }
1884
+ if (snapshots.length === 0) {
1885
+ throw new Error(`No snapshots found for perp ${perpId}`);
1886
+ }
1887
+ if (beaconSnapshots.length === 0) {
1888
+ throw new Error(`No beacon snapshots found for perp ${perpId}`);
1889
+ }
1890
+ const markTimeSeries = snapshots.map((snapshot) => ({
1891
+ timestamp: Number(snapshot.timestamp),
1892
+ value: Number(snapshot.markPrice)
1893
+ }));
1894
+ const indexTimeSeries = beaconSnapshots.map((snapshot) => ({
1895
+ timestamp: Number(snapshot.timestamp),
1896
+ value: Number(snapshot.indexPrice)
1897
+ }));
1898
+ const openInterestTimeSeries = snapshots.map((snapshot) => ({
1899
+ timestamp: Number(snapshot.timestamp),
1900
+ value: {
1901
+ takerLongNotional: Number(snapshot.takerLongNotional),
1902
+ takerShortNotional: Number(snapshot.takerShortNotional)
1868
1903
  }
1869
- }
1870
- `);
1871
- const response = await this.context.goldskyClient.request(query);
1872
- return response.perps.map(
1873
- (perpData) => new Perp(this.context, perpData.id)
1904
+ }));
1905
+ const fundingRateTimeSeries = snapshots.map((snapshot) => ({
1906
+ timestamp: Number(snapshot.timestamp),
1907
+ value: Number(snapshot.fundingRate)
1908
+ }));
1909
+ const latestSnapshot = snapshots[snapshots.length - 1];
1910
+ const latestBeaconSnapshot = beaconSnapshots[beaconSnapshots.length - 1];
1911
+ const perpData = {
1912
+ id: perpId,
1913
+ tickSpacing: contractData.tickSpacing,
1914
+ mark: sqrtPriceX96ToPrice(contractData.sqrtPriceX96),
1915
+ index: Number(latestBeaconSnapshot.indexPrice),
1916
+ beacon: beaconId,
1917
+ lastIndexUpdate: Number(latestBeaconSnapshot.timestamp),
1918
+ openInterest: {
1919
+ takerLongNotional: Number(latestSnapshot.takerLongNotional),
1920
+ takerShortNotional: Number(latestSnapshot.takerShortNotional)
1921
+ },
1922
+ markTimeSeries,
1923
+ indexTimeSeries,
1924
+ fundingRate: Number(latestSnapshot.fundingRate),
1925
+ bounds: contractData.bounds,
1926
+ fees: contractData.fees,
1927
+ openInterestTimeSeries,
1928
+ fundingRateTimeSeries,
1929
+ totalOpenMakerPnl: 0,
1930
+ totalOpenTakerPnl: 0
1931
+ };
1932
+ resultMap.set(perpId, perpData);
1933
+ }
1934
+ return resultMap;
1935
+ }
1936
+ async fetchMultiplePerpContractData(perpIds) {
1937
+ const results = await Promise.all(
1938
+ perpIds.map(async (perpId) => ({
1939
+ perpId,
1940
+ data: await this.fetchPerpContractData(perpId)
1941
+ }))
1874
1942
  );
1943
+ return new Map(results.map(({ perpId, data }) => [perpId, data]));
1875
1944
  }
1876
- // WRITES
1877
- async createPerp(params) {
1878
- const sqrtPriceX96 = priceToSqrtPriceX96(params.startingPrice);
1879
- const contractParams = {
1880
- startingSqrtPriceX96: sqrtPriceX96,
1881
- beacon: params.beacon
1945
+ async fetchUserData(userAddress) {
1946
+ const [usdcBalance, openPositionsData, closedPositionsData] = await Promise.all([
1947
+ this.walletClient.readContract({
1948
+ address: this.deployments().usdc,
1949
+ abi: import_viem4.erc20Abi,
1950
+ functionName: "balanceOf",
1951
+ args: [userAddress]
1952
+ }),
1953
+ this.fetchUserOpenPositions(userAddress),
1954
+ this.fetchUserClosedPositions(userAddress)
1955
+ ]);
1956
+ const realizedPnl = closedPositionsData.reduce((acc, position) => acc + position.pnlAtClose, 0);
1957
+ const unrealizedPnl = openPositionsData.reduce(
1958
+ (acc, position) => acc + position.liveDetails.pnl - position.liveDetails.fundingPayment,
1959
+ 0
1960
+ );
1961
+ return {
1962
+ walletAddress: userAddress,
1963
+ usdcBalance: Number((0, import_viem3.formatUnits)(usdcBalance, 6)),
1964
+ openPositions: openPositionsData,
1965
+ closedPositions: closedPositionsData,
1966
+ realizedPnl,
1967
+ unrealizedPnl
1882
1968
  };
1883
- const { result, request } = await this.context.walletClient.simulateContract({
1884
- address: this.context.deployments().perpManager,
1885
- abi: PERP_MANAGER_ABI,
1886
- functionName: "createPerp",
1887
- args: [contractParams],
1888
- account: this.context.walletClient.account
1889
- });
1890
- await this.context.walletClient.writeContract(request);
1891
- return new Perp(this.context, result);
1892
- }
1893
- };
1894
-
1895
- // src/entities/user.ts
1896
- var import_viem4 = require("viem");
1897
- var import_graphql3 = require("graphql");
1898
- var import_graphql_request4 = require("graphql-request");
1899
- var User = class {
1900
- constructor(context) {
1901
- this.context = context;
1902
- if (!context.walletClient.account) throw new Error("Wallet client account not found");
1903
- this.walletAddress = context.walletClient.account.address;
1904
- }
1905
- async usdcBalance() {
1906
- const result = await this.context.walletClient.readContract({
1907
- address: this.context.deployments().usdc,
1908
- abi: import_viem4.erc20Abi,
1909
- functionName: "balanceOf",
1910
- args: [this.walletAddress]
1911
- });
1912
- return scaleFrom6Decimals(Number(result));
1913
1969
  }
1914
- async openPositions() {
1915
- const query = (0, import_graphql3.parse)(import_graphql_request4.gql`
1970
+ async fetchUserOpenPositions(userAddress) {
1971
+ const query = (0, import_graphql.parse)(`
1916
1972
  query ($holder: Bytes!) {
1917
1973
  openPositions(
1918
1974
  where: { holder: $holder }
1919
1975
  ) {
1920
1976
  perp { id }
1921
1977
  inContractPosId
1978
+ isLong
1979
+ isMaker
1922
1980
  }
1923
1981
  }
1924
1982
  `);
1925
- const response = await this.context.goldskyClient.request(query, { holder: this.walletAddress });
1926
- return response.openPositions.map((position) => new OpenPosition(this.context, position.perp.id, position.inContractPosId));
1983
+ const response = await this.goldskyClient.request(query, { holder: userAddress });
1984
+ const positionsWithDetails = await Promise.all(
1985
+ response.openPositions.map(async (position) => {
1986
+ const positionId = typeof position.inContractPosId === "bigint" ? position.inContractPosId : BigInt(position.inContractPosId);
1987
+ const liveDetails = await this.fetchPositionLiveDetailsFromContract(
1988
+ position.perp.id,
1989
+ positionId
1990
+ );
1991
+ return {
1992
+ perpId: position.perp.id,
1993
+ positionId,
1994
+ isLong: position.isLong,
1995
+ isMaker: position.isMaker,
1996
+ liveDetails
1997
+ };
1998
+ })
1999
+ );
2000
+ return positionsWithDetails;
1927
2001
  }
1928
- async closedPositions() {
1929
- const query = (0, import_graphql3.parse)(import_graphql_request4.gql`
2002
+ async fetchUserClosedPositions(userAddress) {
2003
+ const query = (0, import_graphql.parse)(`
1930
2004
  query ($holder: Bytes!) {
1931
2005
  closedPositions(
1932
2006
  where: { holder: $holder }
@@ -1938,7 +2012,7 @@ var User = class {
1938
2012
  }
1939
2013
  }
1940
2014
  `);
1941
- const response = await this.context.goldskyClient.request(query, { holder: this.walletAddress });
2015
+ const response = await this.goldskyClient.request(query, { holder: userAddress });
1942
2016
  return response.closedPositions.map((position) => ({
1943
2017
  perpId: position.perp.id,
1944
2018
  wasMaker: position.wasMaker,
@@ -1946,13 +2020,60 @@ var User = class {
1946
2020
  pnlAtClose: Number(position.pnlAtClose)
1947
2021
  }));
1948
2022
  }
1949
- async realizedPnl() {
1950
- return (await this.closedPositions()).reduce((acc, position) => acc + position.pnlAtClose, 0);
2023
+ async fetchPositionLiveDetailsFromContract(perpId, positionId) {
2024
+ return withErrorHandling(async () => {
2025
+ const result = await this.walletClient.readContract({
2026
+ address: this.deployments().perpManager,
2027
+ abi: PERP_MANAGER_ABI,
2028
+ functionName: "livePositionDetails",
2029
+ args: [perpId, positionId]
2030
+ });
2031
+ return {
2032
+ pnl: Number((0, import_viem3.formatUnits)(result[0], 6)),
2033
+ fundingPayment: Number((0, import_viem3.formatUnits)(result[1], 6)),
2034
+ effectiveMargin: Number((0, import_viem3.formatUnits)(result[2], 6)),
2035
+ isLiquidatable: result[3]
2036
+ };
2037
+ }, `fetchPositionLiveDetailsFromContract for position ${positionId}`);
2038
+ }
2039
+ /**
2040
+ * Fetch comprehensive user data with all positions in a single batched request
2041
+ */
2042
+ async getUserData(userAddress) {
2043
+ return this.fetchUserData(userAddress);
1951
2044
  }
1952
- async unrealizedPnl() {
1953
- const openPositions = await this.openPositions();
1954
- const liveDetails = await Promise.all(openPositions.map((position) => position.liveDetails()));
1955
- return liveDetails.reduce((acc, detail) => acc + detail.pnl - detail.fundingPayment, 0);
2045
+ /**
2046
+ * Fetch open position data with live details
2047
+ */
2048
+ async getOpenPositionData(perpId, positionId) {
2049
+ const query = (0, import_graphql.parse)(`
2050
+ query ($perpId: Bytes!, $posId: BigInt!) {
2051
+ openPositions(
2052
+ where: { perp: $perpId, inContractPosId: $posId }
2053
+ first: 1
2054
+ ) {
2055
+ isLong
2056
+ isMaker
2057
+ }
2058
+ }
2059
+ `);
2060
+ const [positionResponse, liveDetails] = await Promise.all([
2061
+ this.goldskyClient.request(query, { perpId, posId: positionId.toString() }),
2062
+ this.fetchPositionLiveDetailsFromContract(perpId, positionId)
2063
+ ]);
2064
+ const position = positionResponse.openPositions[0];
2065
+ if (!position) {
2066
+ throw new Error(
2067
+ `Position not found in GraphQL: perpId=${perpId}, positionId=${positionId}. The position may not exist or may have been closed.`
2068
+ );
2069
+ }
2070
+ return {
2071
+ perpId,
2072
+ positionId,
2073
+ isLong: position.isLong,
2074
+ isMaker: position.isMaker,
2075
+ liveDetails
2076
+ };
1956
2077
  }
1957
2078
  };
1958
2079
 
@@ -2211,28 +2332,512 @@ var BEACON_ABI = [
2211
2332
  "type": "function"
2212
2333
  }
2213
2334
  ];
2335
+
2336
+ // src/functions/open-position.ts
2337
+ var import_viem5 = require("viem");
2338
+ var OpenPosition = class _OpenPosition {
2339
+ constructor(context, perpId, positionId, isLong, isMaker) {
2340
+ this.context = context;
2341
+ this.perpId = perpId;
2342
+ this.positionId = positionId;
2343
+ this.isLong = isLong;
2344
+ this.isMaker = isMaker;
2345
+ }
2346
+ async closePosition(params) {
2347
+ return withErrorHandling(async () => {
2348
+ const contractParams = {
2349
+ posId: this.positionId,
2350
+ minAmt0Out: scale6Decimals(params.minAmt0Out),
2351
+ minAmt1Out: scale6Decimals(params.minAmt1Out),
2352
+ maxAmt1In: scale6Decimals(params.maxAmt1In)
2353
+ };
2354
+ const { result, request } = await this.context.walletClient.extend(import_viem5.publicActions).simulateContract({
2355
+ address: this.context.deployments().perpManager,
2356
+ abi: PERP_MANAGER_ABI,
2357
+ functionName: "closePosition",
2358
+ args: [this.perpId, contractParams],
2359
+ account: this.context.walletClient.account
2360
+ });
2361
+ const txHash = await this.context.walletClient.writeContract(request);
2362
+ const publicClient = this.context.walletClient.extend(import_viem5.publicActions);
2363
+ const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
2364
+ if (receipt.status === "reverted") {
2365
+ throw new Error(`Transaction reverted. Hash: ${txHash}`);
2366
+ }
2367
+ let newPositionId = result && result !== 0n ? result : null;
2368
+ for (const log of receipt.logs) {
2369
+ try {
2370
+ const closedDecoded = (0, import_viem5.decodeEventLog)({
2371
+ abi: PERP_MANAGER_ABI,
2372
+ data: log.data,
2373
+ topics: log.topics,
2374
+ eventName: "PositionClosed"
2375
+ });
2376
+ if (closedDecoded.args.perpId === this.perpId && closedDecoded.args.posId === this.positionId) {
2377
+ newPositionId = null;
2378
+ break;
2379
+ }
2380
+ } catch (e) {
2381
+ continue;
2382
+ }
2383
+ }
2384
+ if (!newPositionId) {
2385
+ return null;
2386
+ }
2387
+ return new _OpenPosition(this.context, this.perpId, newPositionId, this.isLong, this.isMaker);
2388
+ }, `closePosition for ${this.isMaker ? "maker" : "taker"} position ${this.positionId}`);
2389
+ }
2390
+ async liveDetails() {
2391
+ return withErrorHandling(async () => {
2392
+ const result = await this.context.walletClient.readContract({
2393
+ address: this.context.deployments().perpManager,
2394
+ abi: PERP_MANAGER_ABI,
2395
+ functionName: "livePositionDetails",
2396
+ args: [this.perpId, this.positionId]
2397
+ });
2398
+ return {
2399
+ pnl: Number((0, import_viem5.formatUnits)(result[0], 6)),
2400
+ fundingPayment: Number((0, import_viem5.formatUnits)(result[1], 6)),
2401
+ effectiveMargin: Number((0, import_viem5.formatUnits)(result[2], 6)),
2402
+ isLiquidatable: result[3]
2403
+ };
2404
+ }, `liveDetails for position ${this.positionId}`);
2405
+ }
2406
+ };
2407
+
2408
+ // src/functions/perp.ts
2409
+ function getPerpMark(perpData) {
2410
+ return perpData.mark;
2411
+ }
2412
+ function getPerpIndex(perpData) {
2413
+ return perpData.index;
2414
+ }
2415
+ function getPerpBeacon(perpData) {
2416
+ return perpData.beacon;
2417
+ }
2418
+ function getPerpLastIndexUpdate(perpData) {
2419
+ return perpData.lastIndexUpdate;
2420
+ }
2421
+ function getPerpOpenInterest(perpData) {
2422
+ return perpData.openInterest;
2423
+ }
2424
+ function getPerpMarkTimeSeries(perpData) {
2425
+ return perpData.markTimeSeries;
2426
+ }
2427
+ function getPerpIndexTimeSeries(perpData) {
2428
+ return perpData.indexTimeSeries;
2429
+ }
2430
+ function getPerpFundingRate(perpData) {
2431
+ return perpData.fundingRate;
2432
+ }
2433
+ function getPerpBounds(perpData) {
2434
+ return perpData.bounds;
2435
+ }
2436
+ function getPerpFees(perpData) {
2437
+ return perpData.fees;
2438
+ }
2439
+ function getPerpOpenInterestTimeSeries(perpData) {
2440
+ return perpData.openInterestTimeSeries;
2441
+ }
2442
+ function getPerpFundingRateTimeSeries(perpData) {
2443
+ return perpData.fundingRateTimeSeries;
2444
+ }
2445
+ function getPerpTickSpacing(perpData) {
2446
+ return perpData.tickSpacing;
2447
+ }
2448
+ async function getAllMakerPositions(context, perpId) {
2449
+ const query = `
2450
+ query ($perpId: Bytes!) {
2451
+ openPositions(
2452
+ where: { perp: $perpId, isMaker: true }
2453
+ ) {
2454
+ perp { id }
2455
+ inContractPosId
2456
+ isLong
2457
+ isMaker
2458
+ }
2459
+ }
2460
+ `;
2461
+ const response = await context.goldskyClient.request(query, { perpId });
2462
+ return response.openPositions.map(
2463
+ (position) => new OpenPosition(
2464
+ context,
2465
+ position.perp.id,
2466
+ BigInt(position.inContractPosId),
2467
+ position.isLong,
2468
+ position.isMaker
2469
+ )
2470
+ );
2471
+ }
2472
+ async function getAllTakerPositions(context, perpId) {
2473
+ const query = `
2474
+ query ($perpId: Bytes!) {
2475
+ openPositions(
2476
+ where: { perp: $perpId, isMaker: false }
2477
+ ) {
2478
+ perp { id }
2479
+ inContractPosId
2480
+ isLong
2481
+ isMaker
2482
+ }
2483
+ }
2484
+ `;
2485
+ const response = await context.goldskyClient.request(query, { perpId });
2486
+ return response.openPositions.map(
2487
+ (position) => new OpenPosition(
2488
+ context,
2489
+ position.perp.id,
2490
+ BigInt(position.inContractPosId),
2491
+ position.isLong,
2492
+ position.isMaker
2493
+ )
2494
+ );
2495
+ }
2496
+ async function getTotalOpenMakerPnl(context, perpId) {
2497
+ const positions = await getAllMakerPositions(context, perpId);
2498
+ const liveDetails = await Promise.all(positions.map((position) => position.liveDetails()));
2499
+ return liveDetails.reduce((acc, detail) => acc + detail.pnl - detail.fundingPayment, 0);
2500
+ }
2501
+ async function getTotalOpenTakerPnl(context, perpId) {
2502
+ const positions = await getAllTakerPositions(context, perpId);
2503
+ const liveDetails = await Promise.all(positions.map((position) => position.liveDetails()));
2504
+ return liveDetails.reduce((acc, detail) => acc + detail.pnl - detail.fundingPayment, 0);
2505
+ }
2506
+
2507
+ // src/functions/perp-manager.ts
2508
+ var import_viem6 = require("viem");
2509
+ var import_graphql_request2 = require("graphql-request");
2510
+ var import_graphql2 = require("graphql");
2511
+ async function getPerps(context) {
2512
+ return withErrorHandling(async () => {
2513
+ const query = (0, import_graphql2.parse)(import_graphql_request2.gql`
2514
+ {
2515
+ perps {
2516
+ id
2517
+ }
2518
+ }
2519
+ `);
2520
+ const response = await context.goldskyClient.request(query);
2521
+ return response.perps.map((perpData) => perpData.id);
2522
+ }, "getPerps");
2523
+ }
2524
+ async function createPerp(context, params) {
2525
+ return withErrorHandling(async () => {
2526
+ const sqrtPriceX96 = priceToSqrtPriceX96(params.startingPrice);
2527
+ const contractParams = {
2528
+ startingSqrtPriceX96: sqrtPriceX96,
2529
+ beacon: params.beacon
2530
+ };
2531
+ const { request } = await context.walletClient.simulateContract({
2532
+ address: context.deployments().perpManager,
2533
+ abi: PERP_MANAGER_ABI,
2534
+ functionName: "createPerp",
2535
+ args: [contractParams],
2536
+ account: context.walletClient.account
2537
+ });
2538
+ const txHash = await context.walletClient.writeContract(request);
2539
+ const publicClient = context.walletClient.extend(import_viem6.publicActions);
2540
+ const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
2541
+ if (receipt.status === "reverted") {
2542
+ throw new Error(`Transaction reverted. Hash: ${txHash}`);
2543
+ }
2544
+ for (const log of receipt.logs) {
2545
+ try {
2546
+ const decoded = (0, import_viem6.decodeEventLog)({
2547
+ abi: PERP_MANAGER_ABI,
2548
+ data: log.data,
2549
+ topics: log.topics,
2550
+ eventName: "PerpCreated"
2551
+ });
2552
+ return decoded.args.perpId;
2553
+ } catch (e) {
2554
+ continue;
2555
+ }
2556
+ }
2557
+ throw new Error("PerpCreated event not found in transaction receipt");
2558
+ }, "createPerp");
2559
+ }
2560
+ async function openTakerPosition(context, perpId, params) {
2561
+ return withErrorHandling(async () => {
2562
+ const marginScaled = scale6Decimals(params.margin);
2563
+ await approveUsdc(context, marginScaled);
2564
+ const levX96 = scaleToX96(params.leverage);
2565
+ const contractParams = {
2566
+ isLong: params.isLong,
2567
+ margin: marginScaled,
2568
+ levX96,
2569
+ unspecifiedAmountLimit: scale6Decimals(params.unspecifiedAmountLimit)
2570
+ };
2571
+ const { request } = await context.walletClient.simulateContract({
2572
+ address: context.deployments().perpManager,
2573
+ abi: PERP_MANAGER_ABI,
2574
+ functionName: "openTakerPosition",
2575
+ args: [perpId, contractParams],
2576
+ account: context.walletClient.account
2577
+ });
2578
+ const txHash = await context.walletClient.writeContract(request);
2579
+ const publicClient = context.walletClient.extend(import_viem6.publicActions);
2580
+ const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
2581
+ if (receipt.status === "reverted") {
2582
+ throw new Error(`Transaction reverted. Hash: ${txHash}`);
2583
+ }
2584
+ let takerPosId = null;
2585
+ for (const log of receipt.logs) {
2586
+ try {
2587
+ const decoded = (0, import_viem6.decodeEventLog)({
2588
+ abi: PERP_MANAGER_ABI,
2589
+ data: log.data,
2590
+ topics: log.topics,
2591
+ eventName: "PositionOpened"
2592
+ });
2593
+ if (decoded.args.perpId === perpId && !decoded.args.isMaker) {
2594
+ takerPosId = decoded.args.posId;
2595
+ break;
2596
+ }
2597
+ } catch (e) {
2598
+ continue;
2599
+ }
2600
+ }
2601
+ if (!takerPosId) {
2602
+ throw new Error(`PositionOpened event not found in transaction receipt. Hash: ${txHash}`);
2603
+ }
2604
+ return new OpenPosition(context, perpId, takerPosId, params.isLong, false);
2605
+ }, "openTakerPosition");
2606
+ }
2607
+ async function openMakerPosition(context, perpId, params) {
2608
+ return withErrorHandling(async () => {
2609
+ const marginScaled = scale6Decimals(params.margin);
2610
+ await approveUsdc(context, marginScaled);
2611
+ const perpData = await context.getPerpData(perpId);
2612
+ const tickLower = priceToTick(params.priceLower, true);
2613
+ const tickUpper = priceToTick(params.priceUpper, false);
2614
+ const tickSpacing = perpData.tickSpacing;
2615
+ const alignedTickLower = Math.floor(tickLower / tickSpacing) * tickSpacing;
2616
+ const alignedTickUpper = Math.ceil(tickUpper / tickSpacing) * tickSpacing;
2617
+ const contractParams = {
2618
+ margin: marginScaled,
2619
+ liquidity: params.liquidity,
2620
+ tickLower: alignedTickLower,
2621
+ tickUpper: alignedTickUpper,
2622
+ maxAmt0In: scale6Decimals(params.maxAmt0In),
2623
+ maxAmt1In: scale6Decimals(params.maxAmt1In)
2624
+ };
2625
+ const { request } = await context.walletClient.simulateContract({
2626
+ address: context.deployments().perpManager,
2627
+ abi: PERP_MANAGER_ABI,
2628
+ functionName: "openMakerPosition",
2629
+ args: [perpId, contractParams],
2630
+ account: context.walletClient.account
2631
+ });
2632
+ const txHash = await context.walletClient.writeContract(request);
2633
+ const publicClient = context.walletClient.extend(import_viem6.publicActions);
2634
+ const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
2635
+ if (receipt.status === "reverted") {
2636
+ throw new Error(`Transaction reverted. Hash: ${txHash}`);
2637
+ }
2638
+ let makerPosId = null;
2639
+ for (const log of receipt.logs) {
2640
+ try {
2641
+ const decoded = (0, import_viem6.decodeEventLog)({
2642
+ abi: PERP_MANAGER_ABI,
2643
+ data: log.data,
2644
+ topics: log.topics,
2645
+ eventName: "PositionOpened"
2646
+ });
2647
+ if (decoded.args.perpId === perpId && decoded.args.isMaker) {
2648
+ makerPosId = decoded.args.posId;
2649
+ break;
2650
+ }
2651
+ } catch (e) {
2652
+ continue;
2653
+ }
2654
+ }
2655
+ if (!makerPosId) {
2656
+ throw new Error(`PositionOpened event not found in transaction receipt. Hash: ${txHash}`);
2657
+ }
2658
+ return new OpenPosition(context, perpId, makerPosId, void 0, true);
2659
+ }, "openMakerPosition");
2660
+ }
2661
+
2662
+ // src/functions/user.ts
2663
+ function getUserUsdcBalance(userData) {
2664
+ return userData.usdcBalance;
2665
+ }
2666
+ function getUserOpenPositions(userData) {
2667
+ return userData.openPositions;
2668
+ }
2669
+ function getUserClosedPositions(userData) {
2670
+ return userData.closedPositions;
2671
+ }
2672
+ function getUserRealizedPnl(userData) {
2673
+ return userData.realizedPnl;
2674
+ }
2675
+ function getUserUnrealizedPnl(userData) {
2676
+ return userData.unrealizedPnl;
2677
+ }
2678
+ function getUserWalletAddress(userData) {
2679
+ return userData.walletAddress;
2680
+ }
2681
+
2682
+ // src/functions/position.ts
2683
+ var import_viem7 = require("viem");
2684
+ var import_viem8 = require("viem");
2685
+ function getPositionPerpId(positionData) {
2686
+ return positionData.perpId;
2687
+ }
2688
+ function getPositionId(positionData) {
2689
+ return positionData.positionId;
2690
+ }
2691
+ function getPositionIsLong(positionData) {
2692
+ return positionData.isLong;
2693
+ }
2694
+ function getPositionIsMaker(positionData) {
2695
+ return positionData.isMaker;
2696
+ }
2697
+ function getPositionLiveDetails(positionData) {
2698
+ return positionData.liveDetails;
2699
+ }
2700
+ function getPositionPnl(positionData) {
2701
+ return positionData.liveDetails.pnl;
2702
+ }
2703
+ function getPositionFundingPayment(positionData) {
2704
+ return positionData.liveDetails.fundingPayment;
2705
+ }
2706
+ function getPositionEffectiveMargin(positionData) {
2707
+ return positionData.liveDetails.effectiveMargin;
2708
+ }
2709
+ function getPositionIsLiquidatable(positionData) {
2710
+ return positionData.liveDetails.isLiquidatable;
2711
+ }
2712
+ async function closePosition(context, perpId, positionId, params) {
2713
+ return withErrorHandling(async () => {
2714
+ const contractParams = {
2715
+ posId: positionId,
2716
+ minAmt0Out: scale6Decimals(params.minAmt0Out),
2717
+ minAmt1Out: scale6Decimals(params.minAmt1Out),
2718
+ maxAmt1In: scale6Decimals(params.maxAmt1In)
2719
+ };
2720
+ const { result, request } = await context.walletClient.extend(import_viem8.publicActions).simulateContract({
2721
+ address: context.deployments().perpManager,
2722
+ abi: PERP_MANAGER_ABI,
2723
+ functionName: "closePosition",
2724
+ args: [perpId, contractParams],
2725
+ account: context.walletClient.account
2726
+ });
2727
+ const txHash = await context.walletClient.writeContract(request);
2728
+ const publicClient = context.walletClient.extend(import_viem8.publicActions);
2729
+ const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
2730
+ if (receipt.status === "reverted") {
2731
+ throw new Error(`Transaction reverted. Hash: ${txHash}`);
2732
+ }
2733
+ let newPositionId = null;
2734
+ for (const log of receipt.logs) {
2735
+ try {
2736
+ const decoded = (0, import_viem7.decodeEventLog)({
2737
+ abi: PERP_MANAGER_ABI,
2738
+ data: log.data,
2739
+ topics: log.topics,
2740
+ eventName: "PositionOpened"
2741
+ });
2742
+ if (decoded.args.perpId === perpId) {
2743
+ newPositionId = decoded.args.posId;
2744
+ break;
2745
+ }
2746
+ } catch (e) {
2747
+ continue;
2748
+ }
2749
+ }
2750
+ if (!newPositionId) {
2751
+ return null;
2752
+ }
2753
+ return {
2754
+ perpId,
2755
+ positionId: newPositionId,
2756
+ liveDetails: await getPositionLiveDetailsFromContract(context, perpId, newPositionId)
2757
+ };
2758
+ }, `closePosition for position ${positionId}`);
2759
+ }
2760
+ async function getPositionLiveDetailsFromContract(context, perpId, positionId) {
2761
+ return withErrorHandling(async () => {
2762
+ const result = await context.walletClient.readContract({
2763
+ address: context.deployments().perpManager,
2764
+ abi: PERP_MANAGER_ABI,
2765
+ functionName: "livePositionDetails",
2766
+ args: [perpId, positionId]
2767
+ });
2768
+ return {
2769
+ pnl: Number((0, import_viem7.formatUnits)(result[0], 6)),
2770
+ fundingPayment: Number((0, import_viem7.formatUnits)(result[1], 6)),
2771
+ effectiveMargin: Number((0, import_viem7.formatUnits)(result[2], 6)),
2772
+ isLiquidatable: result[3]
2773
+ };
2774
+ }, `getPositionLiveDetailsFromContract for position ${positionId}`);
2775
+ }
2214
2776
  // Annotate the CommonJS export names for ESM import in node:
2215
2777
  0 && (module.exports = {
2216
2778
  BEACON_ABI,
2217
2779
  BIGINT_1E6,
2218
- DEPLOYMENTS,
2780
+ ContractError,
2781
+ GraphQLError,
2782
+ InsufficientFundsError,
2219
2783
  NUMBER_1E6,
2220
2784
  OpenPosition,
2221
2785
  PERP_MANAGER_ABI,
2222
- Perp,
2223
2786
  PerpCityContext,
2224
- PerpManager,
2787
+ PerpCityError,
2225
2788
  Q96,
2226
- User,
2789
+ RPCError,
2790
+ TransactionRejectedError,
2791
+ ValidationError,
2227
2792
  approveUsdc,
2793
+ closePosition,
2794
+ createPerp,
2228
2795
  estimateLiquidity,
2796
+ getAllMakerPositions,
2797
+ getAllTakerPositions,
2798
+ getPerpBeacon,
2799
+ getPerpBounds,
2800
+ getPerpFees,
2801
+ getPerpFundingRate,
2802
+ getPerpFundingRateTimeSeries,
2803
+ getPerpIndex,
2804
+ getPerpIndexTimeSeries,
2805
+ getPerpLastIndexUpdate,
2806
+ getPerpMark,
2807
+ getPerpMarkTimeSeries,
2808
+ getPerpOpenInterest,
2809
+ getPerpOpenInterestTimeSeries,
2810
+ getPerpTickSpacing,
2811
+ getPerps,
2812
+ getPositionEffectiveMargin,
2813
+ getPositionFundingPayment,
2814
+ getPositionId,
2815
+ getPositionIsLiquidatable,
2816
+ getPositionIsLong,
2817
+ getPositionIsMaker,
2818
+ getPositionLiveDetails,
2819
+ getPositionLiveDetailsFromContract,
2820
+ getPositionPerpId,
2821
+ getPositionPnl,
2822
+ getTotalOpenMakerPnl,
2823
+ getTotalOpenTakerPnl,
2824
+ getUserClosedPositions,
2825
+ getUserOpenPositions,
2826
+ getUserRealizedPnl,
2827
+ getUserUnrealizedPnl,
2828
+ getUserUsdcBalance,
2829
+ getUserWalletAddress,
2229
2830
  marginRatioToLeverage,
2831
+ openMakerPosition,
2832
+ openTakerPosition,
2833
+ parseContractError,
2230
2834
  priceToSqrtPriceX96,
2231
2835
  priceToTick,
2232
2836
  scale6Decimals,
2233
2837
  scaleFrom6Decimals,
2234
2838
  scaleFromX96,
2235
2839
  scaleToX96,
2236
- sqrtPriceX96ToPrice
2840
+ sqrtPriceX96ToPrice,
2841
+ withErrorHandling
2237
2842
  });
2238
2843
  //# sourceMappingURL=index.js.map