@theliem/xmarket-sdk 3.6.0 → 3.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1843,45 +1843,38 @@ ${logs.join("\n")}`);
1843
1843
  }
1844
1844
  /**
1845
1845
  * 1 SELL taker vs N BUY makers.
1846
- * Rust program only supports BUY-as-taker, so we decompose into N instructions
1847
- * (BUY_i as taker, SELL as single maker) combined into one atomic transaction.
1848
- * Engine must use limitPrice for BUY.makerAmount to pass per-pair crossing check.
1846
+ * Program now supports SELL-as-taker natively 1 instruction with all BUY makers
1847
+ * in remaining_accounts (same structure as BUY taker case).
1849
1848
  */
1850
1849
  async matchComplementarySellVsMultiBuy(sellTaker, buyMakers, collateralMint, feeRecipient, operatorWallet, lookupTable, opts) {
1850
+ if (buyMakers.length === 0) {
1851
+ throw new InvalidParamError("COMPLEMENTARY: no BUY maker orders provided");
1852
+ }
1853
+ const sell = sellTaker.order;
1854
+ const totalBuyPayment = buyMakers.reduce(
1855
+ (acc, b) => acc + BigInt(b.order.makerAmount.toString()),
1856
+ BigInt(0)
1857
+ );
1858
+ const sellExpected = BigInt(sell.takerAmount.toString());
1859
+ if (totalBuyPayment < sellExpected) {
1860
+ throw new InvalidParamError(
1861
+ `COMPLEMENTARY: total buyer payments ${totalBuyPayment} < seller expected ${sellExpected}`
1862
+ );
1863
+ }
1851
1864
  await Promise.all([
1852
1865
  this.registerOrderIfNeeded(sellTaker),
1853
1866
  ...buyMakers.map((m) => this.registerOrderIfNeeded(m))
1854
1867
  ]);
1855
- const sell = sellTaker.order;
1856
- const crossingBuys = buyMakers.filter((b) => {
1857
- const buy = b.order;
1858
- const lhs = BigInt(buy.makerAmount.toString()) * BigInt(sell.makerAmount.toString());
1859
- const rhs = BigInt(buy.takerAmount.toString()) * BigInt(sell.takerAmount.toString());
1860
- return lhs >= rhs;
1861
- });
1862
- if (crossingBuys.length === 0) {
1863
- throw new InvalidParamError("COMPLEMENTARY: no BUY maker orders cross with the SELL taker");
1864
- }
1865
- if (crossingBuys.length < buyMakers.length) {
1866
- console.warn(`[matchOrders] SELL+BUY: filtered ${buyMakers.length - crossingBuys.length} non-crossing BUY(s)`);
1867
- }
1868
- const allIxs = [];
1869
- for (const buyMaker of crossingBuys) {
1870
- const ixs = await this.buildMatchComplementaryIxs(
1871
- buyMaker,
1872
- // BUY as taker
1873
- [sellTaker],
1874
- // SELL as maker
1875
- collateralMint,
1876
- feeRecipient,
1877
- operatorWallet.publicKey,
1878
- opts,
1879
- true
1880
- // useTakerPrice: SELL gets filled at BUY's price (maker's price per doc)
1881
- );
1882
- allIxs.push(...ixs);
1883
- }
1884
- const sig = await this.sendMatchTx(allIxs, lookupTable, operatorWallet);
1868
+ const ixs = await this.buildMatchComplementaryIxs(
1869
+ sellTaker,
1870
+ buyMakers,
1871
+ collateralMint,
1872
+ feeRecipient,
1873
+ operatorWallet.publicKey,
1874
+ opts,
1875
+ false
1876
+ );
1877
+ const sig = await this.sendMatchTx(ixs, lookupTable, operatorWallet);
1885
1878
  return { signature: sig };
1886
1879
  }
1887
1880
  /**
@@ -2124,18 +2117,17 @@ ${logs.join("\n")}`);
2124
2117
  throw new InvalidParamError("COMPLEMENTARY requires one BUY and one or more SELLs on same tokenId");
2125
2118
  }
2126
2119
  const buy = buySignedOrder.order;
2127
- const finalSells = sellCandidates.filter((s) => {
2128
- const sell = s.order;
2129
- const lhs = BigInt(buy.makerAmount.toString()) * BigInt(sell.makerAmount.toString());
2130
- const rhs = BigInt(buy.takerAmount.toString()) * BigInt(sell.takerAmount.toString());
2131
- return lhs >= rhs;
2132
- });
2133
- if (finalSells.length === 0) {
2134
- throw new InvalidParamError("COMPLEMENTARY: no maker orders cross with the buy order");
2135
- }
2136
- if (finalSells.length < sellCandidates.length) {
2137
- console.warn(`[matchOrders] filtered ${sellCandidates.length - finalSells.length} non-crossing maker(s)`);
2120
+ const totalSellDemand = sellCandidates.reduce(
2121
+ (acc, s) => acc + BigInt(s.order.takerAmount.toString()),
2122
+ BigInt(0)
2123
+ );
2124
+ const buyBudget = BigInt(buy.makerAmount.toString());
2125
+ if (buyBudget < totalSellDemand) {
2126
+ throw new InvalidParamError(
2127
+ `COMPLEMENTARY: total sell demand ${totalSellDemand} > buy budget ${buyBudget}. Build taker order with limitPrice, not averageMatchedPrice.`
2128
+ );
2138
2129
  }
2130
+ const finalSells = sellCandidates;
2139
2131
  return this.matchComplementary(buySignedOrder, finalSells, collateralMint, feeRecipient, operatorWallet, alt, opts);
2140
2132
  }
2141
2133
  const allBuy = t.side === SIDE_BUY && makers.every((m) => m.order.side === SIDE_BUY);