@theliem/xmarket-sdk 3.10.0 → 3.12.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.d.mts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as anchor from '@coral-xyz/anchor';
2
2
  import * as _solana_web3_js from '@solana/web3.js';
3
- import { PublicKey, Transaction, Keypair, TransactionInstruction, AddressLookupTableAccount } from '@solana/web3.js';
3
+ import { PublicKey, Transaction, Keypair, TransactionInstruction, AddressLookupTableAccount, VersionedTransaction } from '@solana/web3.js';
4
4
  import BN from 'bn.js';
5
5
 
6
6
  interface ProgramIds {
@@ -617,6 +617,8 @@ declare class ClobClient {
617
617
  * remaining_accounts per NO maker (5):
618
618
  * [order_record, buyer_no_token, buyer_no_collateral, buyer_no_position, no_order_status]
619
619
  */
620
+ /** Build the match_mint_orders instruction (no signing, no sending). */
621
+ private _buildMintIx;
620
622
  private matchMintOrders;
621
623
  /**
622
624
  * MERGE: 1 YES seller (taker) + N NO sellers (makers).
@@ -627,6 +629,8 @@ declare class ClobClient {
627
629
  * [order_record, seller_no_token, seller_no_collateral, seller_no_position, no_order_status]
628
630
  * After all makers, optional 5 fee accounts.
629
631
  */
632
+ /** Build the match_merge_orders instruction (no signing, no sending). */
633
+ private _buildMergeIx;
630
634
  private matchMergeOrders;
631
635
  /**
632
636
  * Auto-detect match type and execute 2-phase:
@@ -644,6 +648,7 @@ declare class ClobClient {
644
648
  */
645
649
  matchOrders(taker: SignedOrder, makers: SignedOrder[], opts?: {
646
650
  marketOracleVault?: PublicKey;
651
+ operatorWallet?: anchor.Wallet;
647
652
  }): Promise<TxResult>;
648
653
  /**
649
654
  * High-level match: caller passes price + quantity + keypair — SDK builds,
@@ -686,7 +691,32 @@ declare class ClobClient {
686
691
  taker?: PublicKey;
687
692
  }>, decimals?: number, opts?: {
688
693
  marketOracleVault?: PublicKey;
694
+ operatorWallet?: anchor.Wallet;
689
695
  }): Promise<TxResult>;
696
+ /**
697
+ * Build an unsigned VersionedTransaction for a set of match instructions.
698
+ * Callers sign and send externally — mirrors createQuestionAdmin pattern.
699
+ */
700
+ private _buildUnsignedVtx;
701
+ /**
702
+ * Build unsigned VersionedTransaction(s) for matching orders.
703
+ *
704
+ * Mirrors createQuestionAdmin pattern — SDK registers orders internally but
705
+ * returns the match tx unsigned. BE signs with both keypairs and sends:
706
+ *
707
+ * const [vtx] = await sdk.clob.buildMatchOrdersTx(taker, makers, operatorPk, payerPk);
708
+ * vtx.sign([feePayerKeypair, operatorKeypair]);
709
+ * await connection.sendRawTransaction(vtx.serialize());
710
+ *
711
+ * All match types pack into a single VersionedTransaction — same as createQuestionAdmin pattern.
712
+ * NO-taker MINT/MERGE decomposes into N instructions but all packed in 1 tx.
713
+ *
714
+ * @param operator - Whitelisted CLOB operator pubkey (must sign)
715
+ * @param payer - Fee payer pubkey (must sign, pays tx fee + rent)
716
+ */
717
+ buildMatchOrdersTx(taker: SignedOrder, makers: SignedOrder[], operator: PublicKey, payer: PublicKey, opts?: {
718
+ marketOracleVault?: PublicKey;
719
+ }): Promise<VersionedTransaction>;
690
720
  fetchConfig(): Promise<ClobConfig | null>;
691
721
  fetchOrderStatus(maker: PublicKey, nonce: anchor.BN): Promise<OrderStatus | null>;
692
722
  fetchOrderRecord(maker: PublicKey, nonce: anchor.BN): Promise<{
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as anchor from '@coral-xyz/anchor';
2
2
  import * as _solana_web3_js from '@solana/web3.js';
3
- import { PublicKey, Transaction, Keypair, TransactionInstruction, AddressLookupTableAccount } from '@solana/web3.js';
3
+ import { PublicKey, Transaction, Keypair, TransactionInstruction, AddressLookupTableAccount, VersionedTransaction } from '@solana/web3.js';
4
4
  import BN from 'bn.js';
5
5
 
6
6
  interface ProgramIds {
@@ -617,6 +617,8 @@ declare class ClobClient {
617
617
  * remaining_accounts per NO maker (5):
618
618
  * [order_record, buyer_no_token, buyer_no_collateral, buyer_no_position, no_order_status]
619
619
  */
620
+ /** Build the match_mint_orders instruction (no signing, no sending). */
621
+ private _buildMintIx;
620
622
  private matchMintOrders;
621
623
  /**
622
624
  * MERGE: 1 YES seller (taker) + N NO sellers (makers).
@@ -627,6 +629,8 @@ declare class ClobClient {
627
629
  * [order_record, seller_no_token, seller_no_collateral, seller_no_position, no_order_status]
628
630
  * After all makers, optional 5 fee accounts.
629
631
  */
632
+ /** Build the match_merge_orders instruction (no signing, no sending). */
633
+ private _buildMergeIx;
630
634
  private matchMergeOrders;
631
635
  /**
632
636
  * Auto-detect match type and execute 2-phase:
@@ -644,6 +648,7 @@ declare class ClobClient {
644
648
  */
645
649
  matchOrders(taker: SignedOrder, makers: SignedOrder[], opts?: {
646
650
  marketOracleVault?: PublicKey;
651
+ operatorWallet?: anchor.Wallet;
647
652
  }): Promise<TxResult>;
648
653
  /**
649
654
  * High-level match: caller passes price + quantity + keypair — SDK builds,
@@ -686,7 +691,32 @@ declare class ClobClient {
686
691
  taker?: PublicKey;
687
692
  }>, decimals?: number, opts?: {
688
693
  marketOracleVault?: PublicKey;
694
+ operatorWallet?: anchor.Wallet;
689
695
  }): Promise<TxResult>;
696
+ /**
697
+ * Build an unsigned VersionedTransaction for a set of match instructions.
698
+ * Callers sign and send externally — mirrors createQuestionAdmin pattern.
699
+ */
700
+ private _buildUnsignedVtx;
701
+ /**
702
+ * Build unsigned VersionedTransaction(s) for matching orders.
703
+ *
704
+ * Mirrors createQuestionAdmin pattern — SDK registers orders internally but
705
+ * returns the match tx unsigned. BE signs with both keypairs and sends:
706
+ *
707
+ * const [vtx] = await sdk.clob.buildMatchOrdersTx(taker, makers, operatorPk, payerPk);
708
+ * vtx.sign([feePayerKeypair, operatorKeypair]);
709
+ * await connection.sendRawTransaction(vtx.serialize());
710
+ *
711
+ * All match types pack into a single VersionedTransaction — same as createQuestionAdmin pattern.
712
+ * NO-taker MINT/MERGE decomposes into N instructions but all packed in 1 tx.
713
+ *
714
+ * @param operator - Whitelisted CLOB operator pubkey (must sign)
715
+ * @param payer - Fee payer pubkey (must sign, pays tx fee + rent)
716
+ */
717
+ buildMatchOrdersTx(taker: SignedOrder, makers: SignedOrder[], operator: PublicKey, payer: PublicKey, opts?: {
718
+ marketOracleVault?: PublicKey;
719
+ }): Promise<VersionedTransaction>;
690
720
  fetchConfig(): Promise<ClobConfig | null>;
691
721
  fetchOrderStatus(maker: PublicKey, nonce: anchor.BN): Promise<OrderStatus | null>;
692
722
  fetchOrderRecord(maker: PublicKey, nonce: anchor.BN): Promise<{
package/dist/index.js CHANGED
@@ -1915,11 +1915,8 @@ ${logs.join("\n")}`);
1915
1915
  * remaining_accounts per NO maker (5):
1916
1916
  * [order_record, buyer_no_token, buyer_no_collateral, buyer_no_position, no_order_status]
1917
1917
  */
1918
- async matchMintOrders(yesSigned, noMakers, collateralMint, _feeRecipient, operatorWallet, lookupTable) {
1919
- await Promise.all([
1920
- this.registerOrderIfNeeded(yesSigned),
1921
- ...noMakers.map((m) => this.registerOrderIfNeeded(m))
1922
- ]);
1918
+ /** Build the match_mint_orders instruction (no signing, no sending). */
1919
+ async _buildMintIx(yesSigned, noMakers, collateralMint, operator, payer) {
1923
1920
  const condition = yesSigned.order.condition;
1924
1921
  const taker = yesSigned.order.maker;
1925
1922
  const takerNonce = yesSigned.order.nonce;
@@ -1967,9 +1964,9 @@ ${logs.join("\n")}`);
1967
1964
  { pubkey: hookConfig, isSigner: false, isWritable: false },
1968
1965
  { pubkey: hookProgram, isSigner: false, isWritable: false }
1969
1966
  );
1970
- const matchIx = await this.program.methods.matchMintOrders(takerNonce, fillAmount, true).accounts({
1971
- operator: operatorWallet.publicKey,
1972
- payer: this.walletPubkey,
1967
+ return this.program.methods.matchMintOrders(takerNonce, fillAmount, true).accounts({
1968
+ operator,
1969
+ payer,
1973
1970
  clobConfig,
1974
1971
  condition,
1975
1972
  taker,
@@ -1996,6 +1993,19 @@ ${logs.join("\n")}`);
1996
1993
  associatedTokenProgram: splToken.ASSOCIATED_TOKEN_PROGRAM_ID,
1997
1994
  systemProgram: web3_js.SystemProgram.programId
1998
1995
  }).remainingAccounts(remainingAccounts).instruction();
1996
+ }
1997
+ async matchMintOrders(yesSigned, noMakers, collateralMint, _feeRecipient, operatorWallet, lookupTable) {
1998
+ await Promise.all([
1999
+ this.registerOrderIfNeeded(yesSigned),
2000
+ ...noMakers.map((m) => this.registerOrderIfNeeded(m))
2001
+ ]);
2002
+ const condition = yesSigned.order.condition;
2003
+ const clobConfig = this.configPda();
2004
+ const [yesMint] = PDA.yesMint(condition, this.programIds);
2005
+ const [noMint] = PDA.noMint(condition, this.programIds);
2006
+ const clobYesAta = splToken.getAssociatedTokenAddressSync(yesMint, clobConfig, true, splToken.TOKEN_2022_PROGRAM_ID);
2007
+ const clobNoAta = splToken.getAssociatedTokenAddressSync(noMint, clobConfig, true, splToken.TOKEN_2022_PROGRAM_ID);
2008
+ const matchIx = await this._buildMintIx(yesSigned, noMakers, collateralMint, operatorWallet.publicKey, this.walletPubkey);
1999
2009
  await this._ensureClobOutcomeAtas(yesMint, noMint, clobConfig, clobYesAta, clobNoAta);
2000
2010
  const sig = await this.sendMatchTx([matchIx], lookupTable, operatorWallet);
2001
2011
  return { signature: sig };
@@ -2009,11 +2019,8 @@ ${logs.join("\n")}`);
2009
2019
  * [order_record, seller_no_token, seller_no_collateral, seller_no_position, no_order_status]
2010
2020
  * After all makers, optional 5 fee accounts.
2011
2021
  */
2012
- async matchMergeOrders(yesSigned, noMakers, collateralMint, feeRecipient, operatorWallet, lookupTable, opts) {
2013
- await Promise.all([
2014
- this.registerOrderIfNeeded(yesSigned),
2015
- ...noMakers.map((m) => this.registerOrderIfNeeded(m))
2016
- ]);
2022
+ /** Build the match_merge_orders instruction (no signing, no sending). */
2023
+ async _buildMergeIx(yesSigned, noMakers, collateralMint, operator, payer, opts) {
2017
2024
  const condition = yesSigned.order.condition;
2018
2025
  const sellerYes = yesSigned.order.maker;
2019
2026
  const takerNonce = yesSigned.order.nonce;
@@ -2066,7 +2073,7 @@ ${logs.join("\n")}`);
2066
2073
  const feeOverridePda = PDA.marketFeeOverride(condition, this.programIds)[0];
2067
2074
  const feeOverrideExists = await this.provider.connection.getAccountInfo(feeOverridePda);
2068
2075
  if (feeOverrideExists) {
2069
- const oracleVault = opts?.marketOracleVault ?? this.walletPubkey;
2076
+ const oracleVault = opts?.marketOracleVault ?? payer;
2070
2077
  remainingAccounts.push(
2071
2078
  { pubkey: this.programIds.feeManagement, isSigner: false, isWritable: false },
2072
2079
  { pubkey: PDA.feeConfig(this.feeConfigOwner, this.programIds)[0], isSigner: false, isWritable: false },
@@ -2077,9 +2084,9 @@ ${logs.join("\n")}`);
2077
2084
  }
2078
2085
  }
2079
2086
  }
2080
- const matchIx = await this.program.methods.matchMergeOrders(takerNonce, fillAmount, true).accounts({
2081
- operator: operatorWallet.publicKey,
2082
- payer: this.walletPubkey,
2087
+ return this.program.methods.matchMergeOrders(takerNonce, fillAmount, true).accounts({
2088
+ operator,
2089
+ payer,
2083
2090
  clobConfig,
2084
2091
  condition,
2085
2092
  taker: sellerYes,
@@ -2105,6 +2112,19 @@ ${logs.join("\n")}`);
2105
2112
  associatedTokenProgram: splToken.ASSOCIATED_TOKEN_PROGRAM_ID,
2106
2113
  systemProgram: web3_js.SystemProgram.programId
2107
2114
  }).remainingAccounts(remainingAccounts).instruction();
2115
+ }
2116
+ async matchMergeOrders(yesSigned, noMakers, collateralMint, _feeRecipient, operatorWallet, lookupTable, opts) {
2117
+ await Promise.all([
2118
+ this.registerOrderIfNeeded(yesSigned),
2119
+ ...noMakers.map((m) => this.registerOrderIfNeeded(m))
2120
+ ]);
2121
+ const condition = yesSigned.order.condition;
2122
+ const clobConfig = this.configPda();
2123
+ const [yesMint] = PDA.yesMint(condition, this.programIds);
2124
+ const [noMint] = PDA.noMint(condition, this.programIds);
2125
+ const clobYesAta = splToken.getAssociatedTokenAddressSync(yesMint, clobConfig, true, splToken.TOKEN_2022_PROGRAM_ID);
2126
+ const clobNoAta = splToken.getAssociatedTokenAddressSync(noMint, clobConfig, true, splToken.TOKEN_2022_PROGRAM_ID);
2127
+ const matchIx = await this._buildMergeIx(yesSigned, noMakers, collateralMint, operatorWallet.publicKey, this.walletPubkey, opts);
2108
2128
  await this._ensureClobOutcomeAtas(yesMint, noMint, clobConfig, clobYesAta, clobNoAta);
2109
2129
  const sig = await this.sendMatchTx([matchIx], lookupTable, operatorWallet);
2110
2130
  return { signature: sig };
@@ -2129,7 +2149,7 @@ ${logs.join("\n")}`);
2129
2149
  const cfg = await this.fetchConfig();
2130
2150
  if (!cfg) throw new InvalidParamError("CLOB config not found on-chain");
2131
2151
  const feeRecipient = cfg.feeRecipient;
2132
- const operatorWallet = this.provider.wallet;
2152
+ const operatorWallet = opts?.operatorWallet ?? this.provider.wallet;
2133
2153
  const alt = await this.ensureAlt(
2134
2154
  taker.order.condition,
2135
2155
  collateralMint,
@@ -2217,6 +2237,119 @@ ${logs.join("\n")}`);
2217
2237
  const makersSigned = sortedMakers.map(buildSigned);
2218
2238
  return this.matchOrders(takerSigned, makersSigned, opts);
2219
2239
  }
2240
+ /**
2241
+ * Build an unsigned VersionedTransaction for a set of match instructions.
2242
+ * Callers sign and send externally — mirrors createQuestionAdmin pattern.
2243
+ */
2244
+ async _buildUnsignedVtx(instructions, lookupTable, payer) {
2245
+ const { connection } = this.provider;
2246
+ const { blockhash } = await connection.getLatestBlockhash();
2247
+ const cuLimit = web3_js.ComputeBudgetProgram.setComputeUnitLimit({ units: 14e5 });
2248
+ const heapFrame = web3_js.ComputeBudgetProgram.requestHeapFrame({ bytes: 262144 });
2249
+ const message = new web3_js.TransactionMessage({
2250
+ payerKey: payer,
2251
+ recentBlockhash: blockhash,
2252
+ instructions: [cuLimit, heapFrame, ...instructions]
2253
+ }).compileToV0Message(lookupTable ? [lookupTable] : []);
2254
+ return new web3_js.VersionedTransaction(message);
2255
+ }
2256
+ /**
2257
+ * Build unsigned VersionedTransaction(s) for matching orders.
2258
+ *
2259
+ * Mirrors createQuestionAdmin pattern — SDK registers orders internally but
2260
+ * returns the match tx unsigned. BE signs with both keypairs and sends:
2261
+ *
2262
+ * const [vtx] = await sdk.clob.buildMatchOrdersTx(taker, makers, operatorPk, payerPk);
2263
+ * vtx.sign([feePayerKeypair, operatorKeypair]);
2264
+ * await connection.sendRawTransaction(vtx.serialize());
2265
+ *
2266
+ * All match types pack into a single VersionedTransaction — same as createQuestionAdmin pattern.
2267
+ * NO-taker MINT/MERGE decomposes into N instructions but all packed in 1 tx.
2268
+ *
2269
+ * @param operator - Whitelisted CLOB operator pubkey (must sign)
2270
+ * @param payer - Fee payer pubkey (must sign, pays tx fee + rent)
2271
+ */
2272
+ async buildMatchOrdersTx(taker, makers, operator, payer, opts) {
2273
+ if (makers.length === 0) throw new InvalidParamError("At least 1 maker required");
2274
+ const collateralMint = this.networkConfig.defaultCollateral.mint;
2275
+ const cfg = await this.fetchConfig();
2276
+ if (!cfg) throw new InvalidParamError("CLOB config not found on-chain");
2277
+ const feeRecipient = cfg.feeRecipient;
2278
+ const alt = await this.ensureAlt(taker.order.condition, collateralMint, taker, makers);
2279
+ const t = taker.order;
2280
+ const m0 = makers[0].order;
2281
+ const SIDE_BUY = 0;
2282
+ const SIDE_SELL = 1;
2283
+ if (t.tokenId === m0.tokenId) {
2284
+ let buySignedOrder, sellCandidates;
2285
+ if (t.side === SIDE_BUY && makers.every((m) => m.order.side === SIDE_SELL)) {
2286
+ buySignedOrder = taker;
2287
+ sellCandidates = makers;
2288
+ } else if (t.side === SIDE_SELL && makers.every((m) => m.order.side === SIDE_BUY)) {
2289
+ await Promise.all([
2290
+ this.registerOrderIfNeeded(taker),
2291
+ ...makers.map((m) => this.registerOrderIfNeeded(m))
2292
+ ]);
2293
+ const ixs3 = await this.buildMatchComplementaryIxs(
2294
+ taker,
2295
+ makers,
2296
+ collateralMint,
2297
+ feeRecipient,
2298
+ operator,
2299
+ opts,
2300
+ false
2301
+ );
2302
+ return this._buildUnsignedVtx(ixs3, alt, payer);
2303
+ } else {
2304
+ throw new InvalidParamError("COMPLEMENTARY requires one BUY and one or more SELLs on same tokenId");
2305
+ }
2306
+ await Promise.all([
2307
+ this.registerOrderIfNeeded(buySignedOrder),
2308
+ ...sellCandidates.map((m) => this.registerOrderIfNeeded(m))
2309
+ ]);
2310
+ const ixs2 = await this.buildMatchComplementaryIxs(
2311
+ buySignedOrder,
2312
+ sellCandidates,
2313
+ collateralMint,
2314
+ feeRecipient,
2315
+ operator,
2316
+ opts
2317
+ );
2318
+ return this._buildUnsignedVtx(ixs2, alt, payer);
2319
+ }
2320
+ const allBuy = t.side === SIDE_BUY && makers.every((m) => m.order.side === SIDE_BUY);
2321
+ const allSell = t.side === SIDE_SELL && makers.every((m) => m.order.side === SIDE_SELL);
2322
+ if (!allBuy && !allSell) throw new InvalidParamError("MINT/MERGE: all orders must be same side");
2323
+ const takerIsYes = t.tokenId === 1 && makers.every((m) => m.order.tokenId === 0);
2324
+ const takerIsNo = t.tokenId === 0 && makers.every((m) => m.order.tokenId === 1);
2325
+ if (!takerIsYes && !takerIsNo) throw new InvalidParamError("MINT/MERGE: orders must be complementary YES+NO pair");
2326
+ const condition = t.condition;
2327
+ const clobConfig = this.configPda();
2328
+ const [yesMint] = PDA.yesMint(condition, this.programIds);
2329
+ const [noMint] = PDA.noMint(condition, this.programIds);
2330
+ const clobYesAta = splToken.getAssociatedTokenAddressSync(yesMint, clobConfig, true, splToken.TOKEN_2022_PROGRAM_ID);
2331
+ const clobNoAta = splToken.getAssociatedTokenAddressSync(noMint, clobConfig, true, splToken.TOKEN_2022_PROGRAM_ID);
2332
+ if (takerIsYes) {
2333
+ await Promise.all([
2334
+ this.registerOrderIfNeeded(taker),
2335
+ ...makers.map((m) => this.registerOrderIfNeeded(m))
2336
+ ]);
2337
+ await this._ensureClobOutcomeAtas(yesMint, noMint, clobConfig, clobYesAta, clobNoAta);
2338
+ const ix = allBuy ? await this._buildMintIx(taker, makers, collateralMint, operator, payer) : await this._buildMergeIx(taker, makers, collateralMint, operator, payer, opts);
2339
+ return this._buildUnsignedVtx([ix], alt, payer);
2340
+ }
2341
+ await Promise.all([
2342
+ this.registerOrderIfNeeded(taker),
2343
+ ...makers.map((m) => this.registerOrderIfNeeded(m))
2344
+ ]);
2345
+ await this._ensureClobOutcomeAtas(yesMint, noMint, clobConfig, clobYesAta, clobNoAta);
2346
+ const ixs = [];
2347
+ for (const yesMaker of makers) {
2348
+ const ix = allBuy ? await this._buildMintIx(yesMaker, [taker], collateralMint, operator, payer) : await this._buildMergeIx(yesMaker, [taker], collateralMint, operator, payer, opts);
2349
+ ixs.push(ix);
2350
+ }
2351
+ return this._buildUnsignedVtx(ixs, alt, payer);
2352
+ }
2220
2353
  // ─── Queries ─────────────────────────────────────────────────────────────────
2221
2354
  async fetchConfig() {
2222
2355
  try {