@ostium/builder-sdk 0.2.0 → 0.3.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/cli.js CHANGED
@@ -59,6 +59,32 @@ var ERC20_ABI = [
59
59
  }
60
60
  ];
61
61
 
62
+ // src/internal/builder-fee.ts
63
+ var MAX_BUILDER_FEE_BPS = 50;
64
+ var MIN_BUILDER_FEE_BPS_STEP = 0.01;
65
+ var MAX_BUILDER_FEE_CONTRACT = 5e5;
66
+ var BPS_TO_CONTRACT = 1e4;
67
+ function bpsToContractBuilderFee(feeBps) {
68
+ if (feeBps === 0) return 0n;
69
+ return BigInt(Math.round(feeBps * BPS_TO_CONTRACT));
70
+ }
71
+ function validateBuilderFeeBps(feeBps) {
72
+ if (!Number.isFinite(feeBps)) {
73
+ return "builder.feeBps must be a finite number";
74
+ }
75
+ if (feeBps < 0 || feeBps > MAX_BUILDER_FEE_BPS) {
76
+ return `builder.feeBps must be between 0 and ${MAX_BUILDER_FEE_BPS} (0%\u20130.5%)`;
77
+ }
78
+ const centiBps = Math.round(feeBps * 100);
79
+ if (Math.abs(feeBps * 100 - centiBps) > 1e-6) {
80
+ return `builder.feeBps must be a multiple of ${MIN_BUILDER_FEE_BPS_STEP} (0.01 bps)`;
81
+ }
82
+ if (bpsToContractBuilderFee(feeBps) > MAX_BUILDER_FEE_CONTRACT) {
83
+ return "builder.feeBps exceeds on-chain maximum (0.5%)";
84
+ }
85
+ return null;
86
+ }
87
+
62
88
  // src/internal/decimal.ts
63
89
  function parseUsdc(amount) {
64
90
  const amountStr = typeof amount === "number" ? amount.toString() : amount;
@@ -215,7 +241,7 @@ function buildBuilderFee(builder) {
215
241
  }
216
242
  return {
217
243
  builder: builder.b,
218
- builderFee: BigInt(builder.f)
244
+ builderFee: bpsToContractBuilderFee(builder.f)
219
245
  };
220
246
  }
221
247
 
@@ -2917,6 +2943,17 @@ query GetTraderOpenTrades($trader: String!, $skip: Int!, $first: Int!) {
2917
2943
  ${PAIR_FULL}
2918
2944
  }
2919
2945
  }`;
2946
+ var GetAllOpenTradesQuery = `
2947
+ query GetAllOpenTrades($skip: Int!, $first: Int!) {
2948
+ trades(
2949
+ where: { isOpen: true }
2950
+ skip: $skip first: $first
2951
+ orderBy: timestamp orderDirection: desc
2952
+ ) {
2953
+ ${TRADE_CORE}
2954
+ ${PAIR_FULL}
2955
+ }
2956
+ }`;
2920
2957
  var ORDER_FIELDS = `
2921
2958
  id tradeID limitID trader
2922
2959
  pair { id from to group { id name } }
@@ -2996,9 +3033,9 @@ query GetTraderActiveLimits($trader: String!, $skip: Int!, $first: Int!) {
2996
3033
  }`;
2997
3034
 
2998
3035
  // src/data/internal/pagination.ts
2999
- async function paginateAll(fetcher, batchSize = 1e3, max = Infinity) {
3036
+ async function paginateAll(fetcher, batchSize = 1e3, max = Infinity, initialSkip = 0) {
3000
3037
  const results = [];
3001
- let skip = 0;
3038
+ let skip = initialSkip;
3002
3039
  while (results.length < max) {
3003
3040
  const remaining = max - results.length;
3004
3041
  const fetchSize = Math.min(batchSize, remaining);
@@ -3927,15 +3964,28 @@ var OstiumSubgraphClient = class _OstiumSubgraphClient {
3927
3964
  * PnL fields are zeroed.
3928
3965
  */
3929
3966
  async getOpenPositions(params) {
3930
- const { user, blockNumber } = params;
3967
+ const { user, blockNumber, limit = Infinity, skip: initialSkip = 0 } = params;
3968
+ const isGlobal = user === "ALL";
3931
3969
  const [trades, prices] = await Promise.all([
3932
- paginateAll(async (skip, first) => {
3933
- const data = await this.query(
3934
- GetTraderOpenTradesQuery,
3935
- { trader: user.toLowerCase(), skip, first }
3936
- );
3937
- return data.trades;
3938
- }),
3970
+ paginateAll(
3971
+ async (skip, first) => {
3972
+ if (isGlobal) {
3973
+ const data2 = await this.query(
3974
+ GetAllOpenTradesQuery,
3975
+ { skip, first }
3976
+ );
3977
+ return data2.trades;
3978
+ }
3979
+ const data = await this.query(
3980
+ GetTraderOpenTradesQuery,
3981
+ { trader: user.toLowerCase(), skip, first }
3982
+ );
3983
+ return data.trades;
3984
+ },
3985
+ 1e3,
3986
+ limit,
3987
+ initialSkip
3988
+ ),
3939
3989
  this.fetchLivePricesSafe()
3940
3990
  ]);
3941
3991
  const pairPositions = trades.map((trade) => {
@@ -4303,11 +4353,11 @@ function validateConfig(config) {
4303
4353
  "INVALID_CONFIG" /* INVALID_CONFIG */
4304
4354
  );
4305
4355
  }
4306
- if (config.builder !== void 0 && (config.builder.feeBps < 0 || config.builder.feeBps > 50)) {
4307
- throw new OstiumError(
4308
- "builder.feeBps must be between 0 and 50 (max 0.5%)",
4309
- "INVALID_CONFIG" /* INVALID_CONFIG */
4310
- );
4356
+ if (config.builder !== void 0) {
4357
+ const feeError = validateBuilderFeeBps(config.builder.feeBps);
4358
+ if (feeError) {
4359
+ throw new OstiumError(feeError, "INVALID_CONFIG" /* INVALID_CONFIG */);
4360
+ }
4311
4361
  }
4312
4362
  let mode;
4313
4363
  try {
@@ -5103,11 +5153,18 @@ var OstiumClient = class _OstiumClient {
5103
5153
  /**
5104
5154
  * Open positions + margin summary for a user. Defaults to the connected
5105
5155
  * trader. Live prices and the current block number are fetched automatically.
5156
+ *
5157
+ * - `user`: pass an address to scope to a single trader, or `'ALL'` to fetch
5158
+ * positions across every trader (no trader filter).
5159
+ * - `limit`: cap the number of positions returned (default: all).
5160
+ * - `skip`: offset into the result set for pagination (default: `0`).
5106
5161
  */
5107
5162
  async getOpenPositions(params) {
5108
5163
  return this.subgraph.getOpenPositions({
5109
5164
  user: params?.user ?? this.getTraderAddress(),
5110
- blockNumber: params?.blockNumber ?? await this.publicClient.getBlockNumber()
5165
+ blockNumber: params?.blockNumber ?? await this.publicClient.getBlockNumber(),
5166
+ limit: params?.limit,
5167
+ skip: params?.skip
5111
5168
  });
5112
5169
  }
5113
5170
  /**
package/dist/index.cjs CHANGED
@@ -60,6 +60,32 @@ var ERC20_ABI = [
60
60
  }
61
61
  ];
62
62
 
63
+ // src/internal/builder-fee.ts
64
+ var MAX_BUILDER_FEE_BPS = 50;
65
+ var MIN_BUILDER_FEE_BPS_STEP = 0.01;
66
+ var MAX_BUILDER_FEE_CONTRACT = 5e5;
67
+ var BPS_TO_CONTRACT = 1e4;
68
+ function bpsToContractBuilderFee(feeBps) {
69
+ if (feeBps === 0) return 0n;
70
+ return BigInt(Math.round(feeBps * BPS_TO_CONTRACT));
71
+ }
72
+ function validateBuilderFeeBps(feeBps) {
73
+ if (!Number.isFinite(feeBps)) {
74
+ return "builder.feeBps must be a finite number";
75
+ }
76
+ if (feeBps < 0 || feeBps > MAX_BUILDER_FEE_BPS) {
77
+ return `builder.feeBps must be between 0 and ${MAX_BUILDER_FEE_BPS} (0%\u20130.5%)`;
78
+ }
79
+ const centiBps = Math.round(feeBps * 100);
80
+ if (Math.abs(feeBps * 100 - centiBps) > 1e-6) {
81
+ return `builder.feeBps must be a multiple of ${MIN_BUILDER_FEE_BPS_STEP} (0.01 bps)`;
82
+ }
83
+ if (bpsToContractBuilderFee(feeBps) > MAX_BUILDER_FEE_CONTRACT) {
84
+ return "builder.feeBps exceeds on-chain maximum (0.5%)";
85
+ }
86
+ return null;
87
+ }
88
+
63
89
  // src/internal/decimal.ts
64
90
  function parseUsdc(amount) {
65
91
  const amountStr = typeof amount === "number" ? amount.toString() : amount;
@@ -218,7 +244,7 @@ function buildBuilderFee(builder) {
218
244
  }
219
245
  return {
220
246
  builder: builder.b,
221
- builderFee: BigInt(builder.f)
247
+ builderFee: bpsToContractBuilderFee(builder.f)
222
248
  };
223
249
  }
224
250
 
@@ -2944,6 +2970,17 @@ query GetTraderOpenTrades($trader: String!, $skip: Int!, $first: Int!) {
2944
2970
  ${PAIR_FULL}
2945
2971
  }
2946
2972
  }`;
2973
+ var GetAllOpenTradesQuery = `
2974
+ query GetAllOpenTrades($skip: Int!, $first: Int!) {
2975
+ trades(
2976
+ where: { isOpen: true }
2977
+ skip: $skip first: $first
2978
+ orderBy: timestamp orderDirection: desc
2979
+ ) {
2980
+ ${TRADE_CORE}
2981
+ ${PAIR_FULL}
2982
+ }
2983
+ }`;
2947
2984
  var ORDER_FIELDS = `
2948
2985
  id tradeID limitID trader
2949
2986
  pair { id from to group { id name } }
@@ -3023,9 +3060,9 @@ query GetTraderActiveLimits($trader: String!, $skip: Int!, $first: Int!) {
3023
3060
  }`;
3024
3061
 
3025
3062
  // src/data/internal/pagination.ts
3026
- async function paginateAll(fetcher, batchSize = 1e3, max = Infinity) {
3063
+ async function paginateAll(fetcher, batchSize = 1e3, max = Infinity, initialSkip = 0) {
3027
3064
  const results = [];
3028
- let skip = 0;
3065
+ let skip = initialSkip;
3029
3066
  while (results.length < max) {
3030
3067
  const remaining = max - results.length;
3031
3068
  const fetchSize = Math.min(batchSize, remaining);
@@ -3954,15 +3991,28 @@ var OstiumSubgraphClient = class _OstiumSubgraphClient {
3954
3991
  * PnL fields are zeroed.
3955
3992
  */
3956
3993
  async getOpenPositions(params) {
3957
- const { user, blockNumber } = params;
3994
+ const { user, blockNumber, limit = Infinity, skip: initialSkip = 0 } = params;
3995
+ const isGlobal = user === "ALL";
3958
3996
  const [trades, prices] = await Promise.all([
3959
- paginateAll(async (skip, first) => {
3960
- const data = await this.query(
3961
- GetTraderOpenTradesQuery,
3962
- { trader: user.toLowerCase(), skip, first }
3963
- );
3964
- return data.trades;
3965
- }),
3997
+ paginateAll(
3998
+ async (skip, first) => {
3999
+ if (isGlobal) {
4000
+ const data2 = await this.query(
4001
+ GetAllOpenTradesQuery,
4002
+ { skip, first }
4003
+ );
4004
+ return data2.trades;
4005
+ }
4006
+ const data = await this.query(
4007
+ GetTraderOpenTradesQuery,
4008
+ { trader: user.toLowerCase(), skip, first }
4009
+ );
4010
+ return data.trades;
4011
+ },
4012
+ 1e3,
4013
+ limit,
4014
+ initialSkip
4015
+ ),
3966
4016
  this.fetchLivePricesSafe()
3967
4017
  ]);
3968
4018
  const pairPositions = trades.map((trade) => {
@@ -4330,11 +4380,11 @@ function validateConfig(config) {
4330
4380
  "INVALID_CONFIG" /* INVALID_CONFIG */
4331
4381
  );
4332
4382
  }
4333
- if (config.builder !== void 0 && (config.builder.feeBps < 0 || config.builder.feeBps > 50)) {
4334
- throw new OstiumError(
4335
- "builder.feeBps must be between 0 and 50 (max 0.5%)",
4336
- "INVALID_CONFIG" /* INVALID_CONFIG */
4337
- );
4383
+ if (config.builder !== void 0) {
4384
+ const feeError = validateBuilderFeeBps(config.builder.feeBps);
4385
+ if (feeError) {
4386
+ throw new OstiumError(feeError, "INVALID_CONFIG" /* INVALID_CONFIG */);
4387
+ }
4338
4388
  }
4339
4389
  let mode;
4340
4390
  try {
@@ -5130,11 +5180,18 @@ var OstiumClient = class _OstiumClient {
5130
5180
  /**
5131
5181
  * Open positions + margin summary for a user. Defaults to the connected
5132
5182
  * trader. Live prices and the current block number are fetched automatically.
5183
+ *
5184
+ * - `user`: pass an address to scope to a single trader, or `'ALL'` to fetch
5185
+ * positions across every trader (no trader filter).
5186
+ * - `limit`: cap the number of positions returned (default: all).
5187
+ * - `skip`: offset into the result set for pagination (default: `0`).
5133
5188
  */
5134
5189
  async getOpenPositions(params) {
5135
5190
  return this.subgraph.getOpenPositions({
5136
5191
  user: params?.user ?? this.getTraderAddress(),
5137
- blockNumber: params?.blockNumber ?? await this.publicClient.getBlockNumber()
5192
+ blockNumber: params?.blockNumber ?? await this.publicClient.getBlockNumber(),
5193
+ limit: params?.limit,
5194
+ skip: params?.skip
5138
5195
  });
5139
5196
  }
5140
5197
  /**