@renegade-fi/renegade-sdk 0.1.5 → 0.1.7

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.
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Basic example of using the Renegade External Match Client
3
+ *
4
+ * This example demonstrates how to create a client, request a quote, assemble a match, and submit the transaction on-chain.
5
+ */
6
+
7
+ import { ExternalMatchClient, OrderSide } from "../index";
8
+ import type { ExternalOrder } from "../index";
9
+
10
+ // Viem imports for on-chain transactions
11
+ import { http, createWalletClient } from "viem";
12
+ import { privateKeyToAccount } from "viem/accounts";
13
+ import { baseSepolia } from "viem/chains";
14
+
15
+ // Get API credentials from environment variables
16
+ const API_KEY = process.env.EXTERNAL_MATCH_KEY || "";
17
+ const API_SECRET = process.env.EXTERNAL_MATCH_SECRET || "";
18
+ const PRIVATE_KEY = process.env.PKEY || "";
19
+ const RPC_URL = process.env.RPC_URL || "https://sepolia.base.org";
20
+
21
+ // Validate API credentials
22
+ if (!API_KEY || !API_SECRET) {
23
+ console.error("Error: Missing API credentials");
24
+ console.error("Please set EXTERNAL_MATCH_KEY and EXTERNAL_MATCH_SECRET environment variables");
25
+ process.exit(1);
26
+ }
27
+
28
+ // Validate wallet private key
29
+ if (!PRIVATE_KEY) {
30
+ console.error("Error: Missing private key");
31
+ console.error("Please set PKEY environment variable");
32
+ process.exit(1);
33
+ }
34
+
35
+ // Set up wallet client for blockchain transactions
36
+ const privateKey = PRIVATE_KEY.startsWith("0x") ? PRIVATE_KEY : `0x${PRIVATE_KEY}`;
37
+ const walletClient = createWalletClient({
38
+ account: privateKeyToAccount(privateKey as `0x${string}`),
39
+ chain: baseSepolia,
40
+ transport: http(RPC_URL),
41
+ });
42
+
43
+ // Create the external match client
44
+ console.log("API KEY", API_KEY);
45
+ const client = ExternalMatchClient.newBaseSepoliaClient(API_KEY, API_SECRET);
46
+
47
+ // Example order for USDC/WETH pair
48
+ const order: ExternalOrder = {
49
+ quote_mint: "0xD9961Bb4Cb27192f8dAd20a662be081f546b0E74", // USDC on testnet
50
+ base_mint: "0xb51a558c8E55DE1EE5391BDFe2aFA49968FC3B25", // cbBTC on testnet
51
+ side: OrderSide.BUY,
52
+ quote_amount: BigInt(20_000_000), // 20 USDC
53
+ };
54
+
55
+ /**
56
+ * Submit a transaction to the chain
57
+ * @param settlementTx The settlement transaction
58
+ * @returns The transaction hash
59
+ */
60
+ async function submitTransaction(settlementTx: any): Promise<`0x${string}`> {
61
+ console.log("Submitting transaction...");
62
+
63
+ const tx = await walletClient.sendTransaction({
64
+ to: settlementTx.to as `0x${string}`,
65
+ data: settlementTx.data as `0x${string}`,
66
+ value: settlementTx.value ? BigInt(settlementTx.value) : BigInt(0),
67
+ });
68
+
69
+ return tx;
70
+ }
71
+
72
+ // Full example with on-chain submission
73
+ async function fullExample() {
74
+ try {
75
+ // Step 1: Request a quote
76
+ console.log("Requesting quote...");
77
+ const quote = await client.requestQuote(order);
78
+
79
+ if (!quote) {
80
+ console.log("No quote available");
81
+ return;
82
+ }
83
+
84
+ console.log("Quote received!");
85
+
86
+ // Step 2: Assemble the quote into a match bundle
87
+ console.log("Assembling match...");
88
+ const bundle = await client.assembleQuote(quote);
89
+
90
+ if (!bundle) {
91
+ console.log("No match available");
92
+ return;
93
+ }
94
+
95
+ console.log("Match assembled!");
96
+
97
+ // Step 3: Submit the transaction on-chain
98
+ const txHash = await submitTransaction(bundle.match_bundle.settlement_tx);
99
+ console.log(
100
+ "Transaction submitted:",
101
+ `${walletClient.chain.blockExplorers?.default.url}/tx/${txHash}`,
102
+ );
103
+ } catch (error) {
104
+ console.error("Error:", error);
105
+ }
106
+ }
107
+
108
+ // Run the examples
109
+ async function main() {
110
+ console.log("Running full example with on-chain submission...");
111
+ await fullExample();
112
+ }
113
+
114
+ // Only run if this file is being executed directly
115
+ if (require.main === module) {
116
+ main().catch(console.error);
117
+ }
@@ -13,6 +13,7 @@ import type { ExternalOrder } from "../index";
13
13
  import { http, createWalletClient } from "viem";
14
14
  import { privateKeyToAccount } from "viem/accounts";
15
15
  import { arbitrumSepolia } from "viem/chains";
16
+ import type { MalleableExternalMatchResponse } from "../src/types";
16
17
 
17
18
  // Get API credentials from environment variables
18
19
  const API_KEY = process.env.EXTERNAL_MATCH_KEY || "";
@@ -53,6 +54,71 @@ const order: ExternalOrder = {
53
54
  quote_amount: BigInt(20_000_000), // 20 USDC
54
55
  };
55
56
 
57
+ /**
58
+ * Set a random base amount on the bundle and print the results
59
+ * @param bundle The malleable match bundle
60
+ */
61
+ function setRandomBaseAmount(bundle: MalleableExternalMatchResponse) {
62
+ // Print bundle info
63
+ console.log("Bundle info:");
64
+ const [minBase, maxBase] = bundle.baseBounds();
65
+ console.log(`Base bounds: ${minBase} - ${maxBase}`);
66
+
67
+ // Pick a random base amount and see the send and receive amounts at that base amount
68
+ const dummyBaseAmount = randomInRange(minBase, maxBase);
69
+ const dummySendAmount = bundle.sendAmountAtBase(dummyBaseAmount);
70
+ const dummyReceiveAmount = bundle.receiveAmountAtBase(dummyBaseAmount);
71
+ console.log(`Hypothetical base amount: ${dummyBaseAmount}`);
72
+ console.log(`Hypothetical send amount: ${dummySendAmount}`);
73
+ console.log(`Hypothetical receive amount: ${dummyReceiveAmount}`);
74
+
75
+ // Pick an actual base amount to swap with
76
+ const swappedBaseAmount = randomInRange(minBase, maxBase);
77
+
78
+ // Setting the base amount will return the receive amount at the new base
79
+ // You can also call sendAmount and receiveAmount to get the amounts at the
80
+ // currently set base amount
81
+ bundle.setBaseAmount(swappedBaseAmount);
82
+ const send = bundle.sendAmount();
83
+ const recv = bundle.receiveAmount();
84
+ console.log(`Swapped base amount: ${swappedBaseAmount}`);
85
+ console.log(`Send amount: ${send}`);
86
+ console.log(`Receive amount: ${recv}`);
87
+ }
88
+
89
+ /**
90
+ * Set a random quote amount on the bundle and print the results
91
+ * @param bundle The malleable match bundle
92
+ */
93
+ // biome-ignore lint/correctness/noUnusedVariables: User can choose to use this function in the example
94
+ function setRandomQuoteAmount(bundle: MalleableExternalMatchResponse) {
95
+ // Print bundle info
96
+ console.log("Bundle info:");
97
+ const [minQuote, maxQuote] = bundle.quoteBounds();
98
+ console.log(`Quote bounds: ${minQuote} - ${maxQuote}`);
99
+
100
+ // Pick a random base amount and see the send and receive amounts at that base amount
101
+ const dummyQuoteAmount = randomInRange(minQuote, maxQuote);
102
+ const dummySendAmount = bundle.sendAmountAtQuote(dummyQuoteAmount);
103
+ const dummyReceiveAmount = bundle.receiveAmountAtQuote(dummyQuoteAmount);
104
+ console.log(`Hypothetical quote amount: ${dummyQuoteAmount}`);
105
+ console.log(`Hypothetical send amount: ${dummySendAmount}`);
106
+ console.log(`Hypothetical receive amount: ${dummyReceiveAmount}`);
107
+
108
+ // Pick an actual base amount to swap with
109
+ const swappedQuoteAmount = randomInRange(minQuote, maxQuote);
110
+
111
+ // Setting the quote amount will return the receive amount at the new quote
112
+ // You can also call sendAmount and receiveAmount to get the amounts at the
113
+ // currently set quote amount
114
+ bundle.setQuoteAmount(swappedQuoteAmount);
115
+ const send = bundle.sendAmount();
116
+ const recv = bundle.receiveAmount();
117
+ console.log(`Swapped quote amount: ${swappedQuoteAmount}`);
118
+ console.log(`Send amount: ${send}`);
119
+ console.log(`Receive amount: ${recv}`);
120
+ }
121
+
56
122
  /**
57
123
  * Submit a transaction to the chain
58
124
  * @param settlementTx The settlement transaction
@@ -92,31 +158,10 @@ async function fullExample() {
92
158
  return;
93
159
  }
94
160
 
95
- // Print bundle info
96
- console.log("Bundle info:");
97
- const [minBase, maxBase] = bundle.baseBounds();
98
- console.log(`Base bounds: ${minBase} - ${maxBase}`);
99
-
100
- // Pick a random base amount and see the send and receive amounts at that base amount
101
- const dummyBaseAmount = randomInRange(minBase, maxBase);
102
- const dummySendAmount = bundle.sendAmountAtBase(dummyBaseAmount);
103
- const dummyReceiveAmount = bundle.receiveAmountAtBase(dummyBaseAmount);
104
- console.log(`Hypothetical base amount: ${dummyBaseAmount}`);
105
- console.log(`Hypothetical send amount: ${dummySendAmount}`);
106
- console.log(`Hypothetical receive amount: ${dummyReceiveAmount}`);
107
-
108
- // Pick an actual base amount to swap with
109
- const swappedBaseAmount = randomInRange(minBase, maxBase);
110
-
111
- // Setting the base amount will return the receive amount at the new base
112
- // You can also call sendAmount and receiveAmount to get the amounts at the
113
- // currently set base amount
114
- const _recv = bundle.setBaseAmount(swappedBaseAmount);
115
- const send = bundle.sendAmount();
116
- const recv = bundle.receiveAmount();
117
- console.log(`Swapped base amount: ${swappedBaseAmount}`);
118
- console.log(`Send amount: ${send}`);
119
- console.log(`Receive amount: ${recv}`);
161
+ // Set a base amount on the bundle
162
+ // Alternatively, you can set a quote amount on the bundle - see
163
+ // `setRandomQuoteAmount`
164
+ setRandomBaseAmount(bundle);
120
165
 
121
166
  // Step 3: Submit the transaction on-chain
122
167
  const txHash = await submitTransaction(bundle.match_bundle.settlement_tx);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@renegade-fi/renegade-sdk",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "description": "A TypeScript client for interacting with the Renegade Darkpool API",
5
5
  "module": "index.ts",
6
6
  "type": "module",
package/src/client.ts CHANGED
@@ -22,6 +22,8 @@ import { VERSION } from "./version";
22
22
  // Constants for API URLs
23
23
  const ARBITRUM_SEPOLIA_BASE_URL = "https://arbitrum-sepolia.auth-server.renegade.fi";
24
24
  const ARBITRUM_ONE_BASE_URL = "https://arbitrum-one.auth-server.renegade.fi";
25
+ const BASE_SEPOLIA_BASE_URL = "https://base-sepolia.auth-server.renegade.fi";
26
+ const BASE_MAINNET_BASE_URL = "https://base-mainnet.auth-server.renegade.fi";
25
27
 
26
28
  // Header constants
27
29
  const RENEGADE_API_KEY_HEADER = "x-renegade-api-key";
@@ -290,6 +292,17 @@ export class ExternalMatchClient {
290
292
  return new ExternalMatchClient(apiKey, apiSecret, ARBITRUM_SEPOLIA_BASE_URL);
291
293
  }
292
294
 
295
+ /**
296
+ * Create a new client configured for the Base Sepolia testnet.
297
+ *
298
+ * @param apiKey The API key for authentication
299
+ * @param apiSecret The API secret for request signing
300
+ * @returns A new ExternalMatchClient configured for Sepolia
301
+ */
302
+ static newBaseSepoliaClient(apiKey: string, apiSecret: string): ExternalMatchClient {
303
+ return new ExternalMatchClient(apiKey, apiSecret, BASE_SEPOLIA_BASE_URL);
304
+ }
305
+
293
306
  /**
294
307
  * Create a new client configured for the Arbitrum One mainnet.
295
308
  *
@@ -310,6 +323,17 @@ export class ExternalMatchClient {
310
323
  return new ExternalMatchClient(apiKey, apiSecret, ARBITRUM_ONE_BASE_URL);
311
324
  }
312
325
 
326
+ /**
327
+ * Create a new client configured for the Base mainnet.
328
+ *
329
+ * @param apiKey The API key for authentication
330
+ * @param apiSecret The API secret for request signing
331
+ * @returns A new ExternalMatchClient configured for mainnet
332
+ */
333
+ static newBaseMainnetClient(apiKey: string, apiSecret: string): ExternalMatchClient {
334
+ return new ExternalMatchClient(apiKey, apiSecret, BASE_MAINNET_BASE_URL);
335
+ }
336
+
313
337
  /**
314
338
  * Request a quote for the given order.
315
339
  *
@@ -12,7 +12,7 @@ export class FixedPoint {
12
12
  }
13
13
 
14
14
  /**
15
- * Multiply a fixed point number by a u128 and return the floor
15
+ * Multiply a fixed point number by a bigint and return the floor
16
16
  */
17
17
  floorMulInt(amount: bigint): bigint {
18
18
  const product = this.value * amount;
@@ -20,4 +20,19 @@ export class FixedPoint {
20
20
  const floored = product / FIXED_POINT_PRECISION_SHIFT;
21
21
  return floored;
22
22
  }
23
+
24
+ /**
25
+ * Divide a bigint by a fixed point number and return the ceiling
26
+ */
27
+ static ceilDivInt(amount: bigint, fp: FixedPoint): bigint {
28
+ const numerator = amount * FIXED_POINT_PRECISION_SHIFT;
29
+ const quotient = numerator / fp.value;
30
+ const remainder = numerator % fp.value;
31
+
32
+ if (remainder === BigInt(0)) {
33
+ return quotient;
34
+ }
35
+
36
+ return quotient + BigInt(1);
37
+ }
23
38
  }
@@ -8,10 +8,20 @@ import {
8
8
  type SettlementTransaction,
9
9
  } from "./index";
10
10
 
11
- /** The offset of the base amount in the calldata */
12
- const BASE_AMOUNT_OFFSET = 4;
13
- /** The length of the base amount in the calldata */
14
- const BASE_AMOUNT_LENGTH = 32;
11
+ /** The length of an amount in the calldata, which is 32 bytes for a `uint256` */
12
+ const AMOUNT_CALLDATA_LENGTH = 32;
13
+ /**
14
+ * The offset of the quote amount in the calldata,
15
+ * which is `4` because it's the first calldata argument
16
+ * after the 4-byte function selector
17
+ */
18
+ const QUOTE_AMOUNT_OFFSET = 4;
19
+ /**
20
+ * The offset of the base amount in the calldata,
21
+ * which is `AMOUNT_CALLDATA_LENGTH` bytes after
22
+ * the quote amount as it is the next calldata argument
23
+ */
24
+ const BASE_AMOUNT_OFFSET = QUOTE_AMOUNT_OFFSET + AMOUNT_CALLDATA_LENGTH;
15
25
  /** The address used to represent the native asset */
16
26
  const NATIVE_ASSET_ADDR = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE";
17
27
 
@@ -33,6 +43,17 @@ export class MalleableExternalMatchResponse {
33
43
  * consistent
34
44
  */
35
45
  base_amount?: bigint;
46
+ /**
47
+ * The quote amount chosen for the match
48
+ *
49
+ * If `undefined`, the quote amount hasn't been selected and defaults to the
50
+ * quote amount implied by the maximum base amount and the price in the match result.
51
+ *
52
+ * This field is not meant for client use directly, rather it is set by
53
+ * operating on the type and allows the response type to stay internally
54
+ * consistent
55
+ */
56
+ quote_amount?: bigint;
36
57
  /**
37
58
  * Whether the match was sponsored
38
59
  */
@@ -47,11 +68,13 @@ export class MalleableExternalMatchResponse {
47
68
  gas_sponsored: boolean,
48
69
  gas_sponsorship_info?: GasSponsorshipInfo,
49
70
  base_amount?: bigint,
71
+ quote_amount?: bigint,
50
72
  ) {
51
73
  this.match_bundle = match_bundle;
52
74
  this.gas_sponsored = gas_sponsored;
53
75
  this.gas_sponsorship_info = gas_sponsorship_info;
54
76
  this.base_amount = base_amount;
77
+ this.quote_amount = quote_amount;
55
78
  }
56
79
 
57
80
  /**
@@ -62,9 +85,15 @@ export class MalleableExternalMatchResponse {
62
85
  public setBaseAmount(baseAmount: bigint) {
63
86
  this.checkBaseAmount(baseAmount);
64
87
 
88
+ const impliedQuoteAmount = this.quoteAmount(baseAmount);
89
+
65
90
  // Set the calldata
66
91
  this.setBaseAmountCalldata(baseAmount);
92
+ this.setQuoteAmountCalldata(impliedQuoteAmount);
93
+
94
+ // Set the quote and base amounts on the response
67
95
  this.base_amount = baseAmount;
96
+ this.quote_amount = impliedQuoteAmount;
68
97
 
69
98
  return this.receiveAmount();
70
99
  }
@@ -72,18 +101,19 @@ export class MalleableExternalMatchResponse {
72
101
  /**
73
102
  * Set the calldata to use a given base amount
74
103
  */
75
- public setBaseAmountCalldata(baseAmount: bigint) {
104
+ private setBaseAmountCalldata(baseAmount: bigint) {
76
105
  const calldataBytes = hexToBytes(this.match_bundle.settlement_tx.data as `0x${string}`);
77
106
 
78
107
  // Padded to 32 bytes
79
- const baseAmountBytes = numberToBytes(baseAmount, { size: BASE_AMOUNT_LENGTH });
108
+ const baseAmountBytes = numberToBytes(baseAmount, { size: AMOUNT_CALLDATA_LENGTH });
80
109
 
81
110
  const prefix = calldataBytes.slice(0, BASE_AMOUNT_OFFSET);
82
111
  const suffix = calldataBytes.slice(
83
- BASE_AMOUNT_OFFSET + BASE_AMOUNT_LENGTH,
112
+ BASE_AMOUNT_OFFSET + AMOUNT_CALLDATA_LENGTH,
84
113
  calldataBytes.length,
85
114
  );
86
115
 
116
+ // Set the calldata and the tx value
87
117
  const newCalldataBytes = concatBytes([prefix, baseAmountBytes, suffix]);
88
118
  const newCalladata = bytesToHex(newCalldataBytes);
89
119
  const value = this.isNativeEthSell() ? baseAmount : 0n;
@@ -101,6 +131,56 @@ export class MalleableExternalMatchResponse {
101
131
  this.match_bundle = newMatchBundle;
102
132
  }
103
133
 
134
+ /**
135
+ * Set the `quote_amount` of the `match_result`
136
+ *
137
+ * @returns The amount received at the given `quote_amount`
138
+ */
139
+ public setQuoteAmount(quoteAmount: bigint) {
140
+ const impliedBaseAmount = this.baseAmount(quoteAmount);
141
+ this.checkQuoteAmount(quoteAmount, impliedBaseAmount);
142
+
143
+ // Set the calldata
144
+ this.setQuoteAmountCalldata(quoteAmount);
145
+ this.setBaseAmountCalldata(impliedBaseAmount);
146
+
147
+ // Set the quote and base amounts on the response
148
+ this.quote_amount = quoteAmount;
149
+ this.base_amount = impliedBaseAmount;
150
+
151
+ return this.receiveAmount();
152
+ }
153
+
154
+ /**
155
+ * Set the calldata to use a given quote amount
156
+ */
157
+ private setQuoteAmountCalldata(quoteAmount: bigint) {
158
+ const calldataBytes = hexToBytes(this.match_bundle.settlement_tx.data as `0x${string}`);
159
+
160
+ // Padded to 32 bytes
161
+ const quoteAmountBytes = numberToBytes(quoteAmount, { size: AMOUNT_CALLDATA_LENGTH });
162
+
163
+ const prefix = calldataBytes.slice(0, QUOTE_AMOUNT_OFFSET);
164
+ const suffix = calldataBytes.slice(
165
+ QUOTE_AMOUNT_OFFSET + AMOUNT_CALLDATA_LENGTH,
166
+ calldataBytes.length,
167
+ );
168
+
169
+ // Set the calldata and the tx value
170
+ const newCalldataBytes = concatBytes([prefix, quoteAmountBytes, suffix]);
171
+ const newCalladata = bytesToHex(newCalldataBytes);
172
+
173
+ const newMatchBundle = {
174
+ ...this.match_bundle,
175
+ settlement_tx: {
176
+ ...this.match_bundle.settlement_tx,
177
+ data: newCalladata,
178
+ },
179
+ };
180
+
181
+ this.match_bundle = newMatchBundle;
182
+ }
183
+
104
184
  /**
105
185
  * Get the bounds on the base amount
106
186
  *
@@ -113,6 +193,41 @@ export class MalleableExternalMatchResponse {
113
193
  ];
114
194
  }
115
195
 
196
+ /**
197
+ * Get the bounds on the quote amount
198
+ *
199
+ * Returns an array [min, max] inclusive
200
+ */
201
+ public quoteBounds(): [bigint, bigint] {
202
+ const [minBase, maxBase] = this.baseBounds();
203
+ const price = this.getPriceFp();
204
+
205
+ const minQuote = price.floorMulInt(minBase);
206
+ const maxQuote = price.floorMulInt(maxBase);
207
+
208
+ return [minQuote, maxQuote];
209
+ }
210
+
211
+ /**
212
+ * Get the bounds on the quote amount for a given base amount.
213
+ *
214
+ * For an explanation of these bounds, see:
215
+ * https://github.com/renegade-fi/renegade-contracts/blob/main/contracts-common/src/types/match.rs#L144-L174
216
+ */
217
+ public quoteBoundsForBase(baseAmount: bigint): [bigint, bigint] {
218
+ const [minQuote, maxQuote] = this.quoteBounds();
219
+
220
+ const price = this.getPriceFp();
221
+ const refQuote = price.floorMulInt(baseAmount);
222
+
223
+ const direction = this.match_bundle.match_result.direction;
224
+
225
+ const resolvedMinQuote = direction === OrderSide.BUY ? refQuote : minQuote;
226
+ const resolvedMaxQuote = direction === OrderSide.BUY ? maxQuote : refQuote;
227
+
228
+ return [resolvedMinQuote, resolvedMaxQuote];
229
+ }
230
+
116
231
  /**
117
232
  * Get the receive amount at the currently set base amount
118
233
  */
@@ -127,6 +242,14 @@ export class MalleableExternalMatchResponse {
127
242
  return this.computeReceiveAmount(baseAmount);
128
243
  }
129
244
 
245
+ /**
246
+ * Get the receive amount at the given quote amount
247
+ */
248
+ public receiveAmountAtQuote(quoteAmount: bigint) {
249
+ const baseAmount = this.baseAmount(quoteAmount);
250
+ return this.computeReceiveAmount(baseAmount);
251
+ }
252
+
130
253
  /**
131
254
  * Get the send amount at the currently set base amount
132
255
  */
@@ -141,6 +264,14 @@ export class MalleableExternalMatchResponse {
141
264
  return this.computeSendAmount(baseAmount);
142
265
  }
143
266
 
267
+ /**
268
+ * Get the send amount at the given quote amount
269
+ */
270
+ public sendAmountAtQuote(quoteAmount: bigint) {
271
+ const baseAmount = this.baseAmount(quoteAmount);
272
+ return this.computeSendAmount(baseAmount);
273
+ }
274
+
144
275
  /**
145
276
  * Return whether the trade is a native ETH sell
146
277
  */
@@ -156,14 +287,31 @@ export class MalleableExternalMatchResponse {
156
287
  * Check a base amount is in the valid range
157
288
  */
158
289
  private checkBaseAmount(baseAmount: bigint) {
159
- const min = this.match_bundle.match_result.min_base_amount;
160
- const max = this.match_bundle.match_result.max_base_amount;
290
+ const [min, max] = this.baseBounds();
161
291
 
162
292
  if (baseAmount < min || baseAmount > max) {
163
293
  throw new Error(`Base amount ${baseAmount} is not in the valid range ${min} - ${max}`);
164
294
  }
165
295
  }
166
296
 
297
+ /**
298
+ * Check a quote amount is in the valid range for a given base amount.
299
+ *
300
+ * This is true if the quote amount is within the bounds implied by the min
301
+ * and max base amounts given the price in the match results, and the
302
+ * quote amount does not imply a price improvement over the price in
303
+ * the match result.
304
+ */
305
+ private checkQuoteAmount(quoteAmount: bigint, baseAmount: bigint) {
306
+ const [min, max] = this.quoteBoundsForBase(baseAmount);
307
+
308
+ if (quoteAmount < min || quoteAmount > max) {
309
+ throw new Error(
310
+ `Quote amount ${quoteAmount} is not in the valid range ${min} - ${max}`,
311
+ );
312
+ }
313
+ }
314
+
167
315
  /**
168
316
  * Get the current receive amount at the given base amount
169
317
  *
@@ -200,11 +348,19 @@ export class MalleableExternalMatchResponse {
200
348
  return baseAmount;
201
349
  }
202
350
 
351
+ /**
352
+ * Get the base amount at the given quote amount
353
+ */
354
+ private baseAmount(quoteAmount: bigint) {
355
+ const price = this.getPriceFp();
356
+ return FixedPoint.ceilDivInt(quoteAmount, price);
357
+ }
358
+
203
359
  /**
204
360
  * Get the quote amount at the given base amount
205
361
  */
206
362
  private quoteAmount(baseAmount: bigint) {
207
- const price = new FixedPoint(BigInt(this.match_bundle.match_result.price_fp));
363
+ const price = this.getPriceFp();
208
364
  return price.floorMulInt(baseAmount);
209
365
  }
210
366
 
@@ -217,6 +373,10 @@ export class MalleableExternalMatchResponse {
217
373
  }
218
374
  return this.base_amount;
219
375
  }
376
+
377
+ private getPriceFp() {
378
+ return new FixedPoint(BigInt(this.match_bundle.match_result.price_fp));
379
+ }
220
380
  }
221
381
 
222
382
  /**
package/src/version.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * SDK version information
3
3
  * This file is automatically updated during the build process
4
- * Last updated: 2025-05-10T01:06:48Z
4
+ * Last updated: 2025-05-30T00:51:32Z
5
5
  */
6
6
 
7
- export const VERSION = '0.1.5';
7
+ export const VERSION = '0.1.7';