@theliem/xmarket-sdk 3.23.0 → 3.26.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
@@ -161,6 +161,22 @@ var PDA = class {
161
161
  programIds.clobExchange
162
162
  );
163
163
  }
164
+ static collectFeeOrderRecord(user, nonce, programIds) {
165
+ const nonceBuf = Buffer.alloc(8);
166
+ nonceBuf.writeBigUInt64LE(BigInt(nonce.toString()));
167
+ return PublicKey.findProgramAddressSync(
168
+ [Buffer.from("collect_order"), user.toBuffer(), nonceBuf],
169
+ programIds.clobExchange
170
+ );
171
+ }
172
+ static redeemFeeOrderRecord(user, nonce, programIds) {
173
+ const nonceBuf = Buffer.alloc(8);
174
+ nonceBuf.writeBigUInt64LE(BigInt(nonce.toString()));
175
+ return PublicKey.findProgramAddressSync(
176
+ [Buffer.from("redeem_fee_order"), user.toBuffer(), nonceBuf],
177
+ programIds.clobExchange
178
+ );
179
+ }
164
180
  // ─── Fee Management ─────────────────────────────────────────────────────────
165
181
  static feeConfig(owner, programIds) {
166
182
  if (!programIds.feeManagement) throw new Error("feeManagement program ID not configured");
@@ -1470,6 +1486,50 @@ function buildBatchedCollectFeeEd25519Instruction(orders) {
1470
1486
  data
1471
1487
  });
1472
1488
  }
1489
+ function serializeRedeemFeeOrderToBytes(order) {
1490
+ const buf = new Uint8Array(128);
1491
+ buf.set(order.user.toBytes(), 0);
1492
+ buf.set(order.condition.toBytes(), 32);
1493
+ buf.set(order.tokenMint.toBytes(), 64);
1494
+ buf.set(order.amount.toArrayLike(Buffer, "le", 8), 96);
1495
+ buf.set(order.takerAmount.toArrayLike(Buffer, "le", 8), 104);
1496
+ buf.set(order.nonce.toArrayLike(Buffer, "le", 8), 112);
1497
+ buf.set(order.expiry.toArrayLike(Buffer, "le", 8), 120);
1498
+ return buf;
1499
+ }
1500
+ function buildBatchedRedeemFeeEd25519Instruction(orders) {
1501
+ const N = orders.length;
1502
+ if (N === 0) throw new Error("At least 1 order required");
1503
+ const MSG_SIZE = 128;
1504
+ const SIG_SIZE = 64;
1505
+ const PK_SIZE = 32;
1506
+ const HEADER = 2 + N * 14;
1507
+ const sigBase = HEADER;
1508
+ const pkBase = sigBase + N * SIG_SIZE;
1509
+ const msgBase = pkBase + N * PK_SIZE;
1510
+ const totalSize = msgBase + N * MSG_SIZE;
1511
+ const data = Buffer.alloc(totalSize);
1512
+ data[0] = N;
1513
+ data[1] = 0;
1514
+ for (let i = 0; i < N; i++) {
1515
+ const e = 2 + i * 14;
1516
+ data.writeUInt16LE(sigBase + i * SIG_SIZE, e);
1517
+ data.writeUInt16LE(65535, e + 2);
1518
+ data.writeUInt16LE(pkBase + i * PK_SIZE, e + 4);
1519
+ data.writeUInt16LE(65535, e + 6);
1520
+ data.writeUInt16LE(msgBase + i * MSG_SIZE, e + 8);
1521
+ data.writeUInt16LE(MSG_SIZE, e + 10);
1522
+ data.writeUInt16LE(65535, e + 12);
1523
+ data.set(orders[i].signature, sigBase + i * SIG_SIZE);
1524
+ data.set(orders[i].order.user.toBytes(), pkBase + i * PK_SIZE);
1525
+ data.set(serializeRedeemFeeOrderToBytes(orders[i].order), msgBase + i * MSG_SIZE);
1526
+ }
1527
+ return new TransactionInstruction({
1528
+ keys: [],
1529
+ programId: Ed25519Program.programId,
1530
+ data
1531
+ });
1532
+ }
1473
1533
  function buildOrder(params) {
1474
1534
  return {
1475
1535
  maker: params.maker,
@@ -1618,6 +1678,39 @@ var ClobClient = class {
1618
1678
  this._marketOracleVaultCache.set(key, vault);
1619
1679
  return vault;
1620
1680
  }
1681
+ /**
1682
+ * Returns a createATA ix for the oracle vault when:
1683
+ * - takerFee > 0
1684
+ * - marketFeeOverride exists for the condition
1685
+ * - oracle vault ATA is not yet initialized
1686
+ * Idempotent — safe to call every tx; returns null if vault already exists.
1687
+ */
1688
+ async buildInitOracleVaultIfNeeded(condition, collateralMint, takerFee, payer) {
1689
+ if (takerFee.isZero()) return null;
1690
+ if (!this.feeConfigOwner || !this.programIds.feeManagement) return null;
1691
+ if (!this.ctfClient || !this.qmConfigPda || !this.programIds.marketOracle) return null;
1692
+ const companyAddr = await this.companyAddress();
1693
+ const refVault = await this.referralVault();
1694
+ if (!companyAddr || !refVault) return null;
1695
+ const feeOverridePda = PDA.marketFeeOverride(condition, this.programIds)[0];
1696
+ const cond = await this.ctfClient.fetchCondition(condition);
1697
+ if (!cond) return null;
1698
+ const [questionPda] = PDA.question(this.qmConfigPda, cond.questionId, this.programIds);
1699
+ const [marketOraclePda] = PDA.marketOraclePda(questionPda, this.programIds);
1700
+ const vault = getAssociatedTokenAddressSync(collateralMint, marketOraclePda, true);
1701
+ const [feeOverrideInfo, vaultInfo] = await Promise.all([
1702
+ this.provider.connection.getAccountInfo(feeOverridePda),
1703
+ this.provider.connection.getAccountInfo(vault)
1704
+ ]);
1705
+ if (!feeOverrideInfo) return null;
1706
+ if (vaultInfo) return null;
1707
+ return createAssociatedTokenAccountIdempotentInstruction(
1708
+ payer,
1709
+ vault,
1710
+ marketOraclePda,
1711
+ collateralMint
1712
+ );
1713
+ }
1621
1714
  get walletPubkey() {
1622
1715
  return this.provider.wallet.publicKey;
1623
1716
  }
@@ -1756,8 +1849,8 @@ var ClobClient = class {
1756
1849
  async _sendLegacyTxSig(instructions) {
1757
1850
  const { connection } = this.provider;
1758
1851
  const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash();
1759
- const { Transaction: Transaction11 } = await import('@solana/web3.js');
1760
- const tx = new Transaction11();
1852
+ const { Transaction: Transaction12 } = await import('@solana/web3.js');
1853
+ const tx = new Transaction12();
1761
1854
  tx.recentBlockhash = blockhash;
1762
1855
  tx.feePayer = this.walletPubkey;
1763
1856
  tx.add(...instructions);
@@ -1783,10 +1876,10 @@ ${logs.join("\n")}`);
1783
1876
  connection.getAccountInfo(clobYesAta),
1784
1877
  connection.getAccountInfo(clobNoAta)
1785
1878
  ]);
1786
- const { createAssociatedTokenAccountIdempotentInstruction: createAssociatedTokenAccountIdempotentInstruction4 } = await import('@solana/spl-token');
1879
+ const { createAssociatedTokenAccountIdempotentInstruction: createAssociatedTokenAccountIdempotentInstruction5 } = await import('@solana/spl-token');
1787
1880
  const ixs = [];
1788
1881
  if (!yesInfo) {
1789
- ixs.push(createAssociatedTokenAccountIdempotentInstruction4(
1882
+ ixs.push(createAssociatedTokenAccountIdempotentInstruction5(
1790
1883
  this.walletPubkey,
1791
1884
  clobYesAta,
1792
1885
  clobConfig,
@@ -1795,7 +1888,7 @@ ${logs.join("\n")}`);
1795
1888
  ));
1796
1889
  }
1797
1890
  if (!noInfo) {
1798
- ixs.push(createAssociatedTokenAccountIdempotentInstruction4(
1891
+ ixs.push(createAssociatedTokenAccountIdempotentInstruction5(
1799
1892
  this.walletPubkey,
1800
1893
  clobNoAta,
1801
1894
  clobConfig,
@@ -1878,6 +1971,49 @@ ${logs.join("\n")}`);
1878
1971
  await this.registerOrder(signed);
1879
1972
  }
1880
1973
  }
1974
+ // ─── Register CollectFeeOrder ────────────────────────────────────────────────
1975
+ /**
1976
+ * Build a legacy Transaction to register a CollectFeeOrder on-chain.
1977
+ * Must be signed and sent before calling buildBatchCollectRedeemEarlyTx.
1978
+ *
1979
+ * Flow: [Ed25519 ix (1 user sig) + register_collect_fee_order ix]
1980
+ * Caller signs with payer keypair and sends.
1981
+ */
1982
+ async buildRegisterCollectFeeOrderTx(signedOrder, payer) {
1983
+ const { order } = signedOrder;
1984
+ const [collectFeeOrderRecord] = PDA.collectFeeOrderRecord(order.user, order.nonce, this.programIds);
1985
+ const ed25519Ix = buildBatchedCollectFeeEd25519Instruction([signedOrder]);
1986
+ const registerIx = await this.program.methods.registerCollectFeeOrder(order.nonce).accounts({
1987
+ payer,
1988
+ clobConfig: this.configPda(),
1989
+ ixSysvar: IX_SYSVAR,
1990
+ orderSigner: order.user,
1991
+ collectFeeOrderRecord,
1992
+ systemProgram: SystemProgram.programId
1993
+ }).instruction();
1994
+ const { blockhash } = await this.provider.connection.getLatestBlockhash();
1995
+ const tx = new Transaction();
1996
+ tx.recentBlockhash = blockhash;
1997
+ tx.feePayer = payer;
1998
+ tx.add(ed25519Ix, registerIx);
1999
+ return tx;
2000
+ }
2001
+ /**
2002
+ * Register a CollectFeeOrder on-chain and send immediately (operator-signed flow).
2003
+ * Idempotent — skips if PDA already exists.
2004
+ */
2005
+ async registerCollectFeeOrderIfNeeded(signedOrder) {
2006
+ const [pda] = PDA.collectFeeOrderRecord(
2007
+ signedOrder.order.user,
2008
+ signedOrder.order.nonce,
2009
+ this.programIds
2010
+ );
2011
+ const existing = await this.program.account.collectFeeOrderRecord?.fetchNullable(pda);
2012
+ if (!existing) {
2013
+ const tx = await this.buildRegisterCollectFeeOrderTx(signedOrder, this.walletPubkey);
2014
+ await this._sendLegacyTx(tx.instructions);
2015
+ }
2016
+ }
1881
2017
  /** Cancel an order — closes its OrderRecord PDA and returns rent to maker. */
1882
2018
  async cancelOrder(nonce) {
1883
2019
  const [orderRecord] = PDA.orderRecord(this.walletPubkey, nonce, this.programIds);
@@ -2460,6 +2596,13 @@ ${logs.join("\n")}`);
2460
2596
  if (yIx) hookInitIxs.push(yIx);
2461
2597
  if (nIx) hookInitIxs.push(nIx);
2462
2598
  }
2599
+ const oracleVaultInitIx = await this.buildInitOracleVaultIfNeeded(
2600
+ t.condition,
2601
+ collateralMint,
2602
+ t.fee,
2603
+ payer
2604
+ );
2605
+ const preIxs = oracleVaultInitIx ? [...hookInitIxs, oracleVaultInitIx] : hookInitIxs;
2463
2606
  if (t.tokenId === m0.tokenId) {
2464
2607
  let buySignedOrder, sellCandidates;
2465
2608
  if (t.side === SIDE_BUY && makers.every((m) => m.order.side === SIDE_SELL)) {
@@ -2479,7 +2622,7 @@ ${logs.join("\n")}`);
2479
2622
  opts,
2480
2623
  false
2481
2624
  );
2482
- return this._buildUnsignedVtx([...hookInitIxs, ...ixs3], alt, payer);
2625
+ return this._buildUnsignedVtx([...preIxs, ...ixs3], alt, payer);
2483
2626
  } else {
2484
2627
  throw new InvalidParamError("COMPLEMENTARY requires one BUY and one or more SELLs on same tokenId");
2485
2628
  }
@@ -2495,7 +2638,7 @@ ${logs.join("\n")}`);
2495
2638
  operator,
2496
2639
  opts
2497
2640
  );
2498
- return this._buildUnsignedVtx([...hookInitIxs, ...ixs2], alt, payer);
2641
+ return this._buildUnsignedVtx([...preIxs, ...ixs2], alt, payer);
2499
2642
  }
2500
2643
  const allBuy = t.side === SIDE_BUY && makers.every((m) => m.order.side === SIDE_BUY);
2501
2644
  const allSell = t.side === SIDE_SELL && makers.every((m) => m.order.side === SIDE_SELL);
@@ -2516,7 +2659,7 @@ ${logs.join("\n")}`);
2516
2659
  ]);
2517
2660
  await this._ensureClobOutcomeAtas(yesMint, noMint, clobConfig, clobYesAta, clobNoAta);
2518
2661
  const ix = allBuy ? await this._buildMintIx(taker, makers, collateralMint, operator, payer) : await this._buildMergeIx(taker, makers, collateralMint, operator, payer, opts);
2519
- return this._buildUnsignedVtx([...hookInitIxs, ix], alt, payer);
2662
+ return this._buildUnsignedVtx([...preIxs, ix], alt, payer);
2520
2663
  }
2521
2664
  await Promise.all([
2522
2665
  this.registerOrderIfNeeded(taker),
@@ -2528,17 +2671,19 @@ ${logs.join("\n")}`);
2528
2671
  const ix = allBuy ? await this._buildMintIx(yesMaker, [taker], collateralMint, operator, payer) : await this._buildMergeIx(yesMaker, [taker], collateralMint, operator, payer, opts);
2529
2672
  ixs.push(ix);
2530
2673
  }
2531
- return this._buildUnsignedVtx([...hookInitIxs, ...ixs], alt, payer);
2674
+ return this._buildUnsignedVtx([...preIxs, ...ixs], alt, payer);
2532
2675
  }
2533
2676
  // ─── batchCollectRedeemEarly ─────────────────────────────────────────────────
2534
2677
  /**
2535
2678
  * Build VersionedTransaction for batchCollectRedeemEarly.
2536
2679
  *
2537
- * Flow: Ed25519 ix (user sigs) + batchCollectRedeemEarly ix.
2538
- * Each SignedCollectFeeOrder authorizes CLOB to collect `amount` winning tokens
2539
- * from that user, redeem via CTF, then distribute as fees.
2680
+ * Prerequisite: each user's CollectFeeOrder must be registered on-chain via
2681
+ * buildRegisterCollectFeeOrderTx (one tx per user).
2540
2682
  *
2541
- * @param signedOrders - Array of { order, signature } from winning users
2683
+ * Flow: batchCollectRedeemEarly ix reads CollectFeeOrderRecord PDAs no Ed25519 inline.
2684
+ * No tx-size limit from signatures, supports 10+ orders in one tx.
2685
+ *
2686
+ * @param signedOrders - Array of { order, signature } (used to derive record PDAs)
2542
2687
  * @param condition - Market condition PDA
2543
2688
  * @param outcomeIndex - 0 = NO wins, 1 = YES wins
2544
2689
  * @param operator - Whitelisted operator pubkey (must sign)
@@ -2564,9 +2709,11 @@ ${logs.join("\n")}`);
2564
2709
  const [clobNoPosition] = PDA.position(condition, 0, clobConfig, this.programIds);
2565
2710
  const userAccounts = [];
2566
2711
  for (const { order } of signedOrders) {
2712
+ const [collectFeeOrderRecord] = PDA.collectFeeOrderRecord(order.user, order.nonce, this.programIds);
2567
2713
  const userTokenAta = getAssociatedTokenAddressSync(outcomeMint, order.user, false, TOKEN_2022_PROGRAM_ID);
2568
2714
  const [userPosition] = PDA.position(condition, outcomeIndex, order.user, this.programIds);
2569
2715
  userAccounts.push(
2716
+ { pubkey: collectFeeOrderRecord, isSigner: false, isWritable: true },
2570
2717
  { pubkey: order.user, isSigner: false, isWritable: false },
2571
2718
  { pubkey: userTokenAta, isSigner: false, isWritable: true },
2572
2719
  { pubkey: userPosition, isSigner: false, isWritable: true }
@@ -2603,11 +2750,7 @@ ${logs.join("\n")}`);
2603
2750
  const ix = await this.hookClient.buildInitHookIxIfNeeded(outcomeMint, payer);
2604
2751
  if (ix) hookInitIxs.push(ix);
2605
2752
  }
2606
- const ed25519Ix = buildBatchedCollectFeeEd25519Instruction(signedOrders);
2607
- const ed25519IxIndex = 2 + hookInitIxs.length;
2608
2753
  const collectIx = await this.program.methods.batchCollectRedeemEarly(
2609
- ed25519IxIndex,
2610
- // ix_index: adjusted for any prepended hook init ixs
2611
2754
  signedOrders.length,
2612
2755
  outcomeIndex
2613
2756
  ).accounts({
@@ -2624,44 +2767,273 @@ ${logs.join("\n")}`);
2624
2767
  clobNoAta,
2625
2768
  clobYesPosition,
2626
2769
  clobNoPosition,
2627
- ixSysvar: IX_SYSVAR,
2628
2770
  conditionalTokensProgram: this.programIds.conditionalTokens,
2629
2771
  tokenProgram: TOKEN_PROGRAM_ID,
2630
2772
  token2022Program: TOKEN_2022_PROGRAM_ID,
2631
2773
  systemProgram: SystemProgram.programId
2632
2774
  }).remainingAccounts([...userAccounts, ...hookAccounts, ...feeAccounts]).instruction();
2633
- const alt = opts?.lookupTable ?? this._altCache.get(condition.toBase58()) ?? await this.buildAltForCondition(condition, payer, collateralMint);
2634
- return this._buildUnsignedVtx([...hookInitIxs, ed25519Ix, collectIx], alt, payer);
2775
+ const alt = opts?.lookupTable ?? await this.buildAltForCollectBatch(condition, payer, collateralMint, signedOrders, outcomeIndex);
2776
+ return this._buildUnsignedVtx([...hookInitIxs, collectIx], alt, payer);
2635
2777
  }
2778
+ // ─── Register RedeemFeeOrder ─────────────────────────────────────────────────
2636
2779
  /**
2637
- * Build ALT with static accounts for a condition no order-specific PDAs needed.
2638
- * Use before buildBatchCollectRedeemEarlyTx when no prior buildMatchOrdersTx ran in this session.
2780
+ * Build a Transaction to register a RedeemFeeOrder on-chain (Ed25519 verify + PDA).
2781
+ * Must be sent before calling buildBatchRedeemWithFeeTx / buildBatchMergeWithFeeTx.
2782
+ *
2783
+ * ix[0]: batched Ed25519 { pubkey=order.user, sig, msg=128 bytes }
2784
+ * ix[1]: register_redeem_fee_order(nonce)
2639
2785
  */
2640
- async buildAltForCondition(condition, _payer, collateralMint) {
2641
- const cacheKey = condition.toBase58();
2786
+ async buildRegisterRedeemFeeOrderTx(signedOrder, payer) {
2787
+ const { order } = signedOrder;
2788
+ const [redeemFeeOrderRecord] = PDA.redeemFeeOrderRecord(order.user, order.nonce, this.programIds);
2789
+ const ed25519Ix = buildBatchedRedeemFeeEd25519Instruction([signedOrder]);
2790
+ const registerIx = await this.program.methods.registerRedeemFeeOrder(order.nonce).accounts({
2791
+ payer,
2792
+ clobConfig: this.configPda(),
2793
+ ixSysvar: IX_SYSVAR,
2794
+ orderSigner: order.user,
2795
+ redeemFeeOrderRecord,
2796
+ systemProgram: anchor5.web3.SystemProgram.programId
2797
+ }).instruction();
2798
+ const tx = new anchor5.web3.Transaction();
2799
+ tx.add(ed25519Ix, registerIx);
2800
+ return tx;
2801
+ }
2802
+ // ─── batchRedeemWithFee ───────────────────────────────────────────────────────
2803
+ /**
2804
+ * Build a VersionedTransaction for batchRedeemWithFee.
2805
+ * Each pair has a YES order + NO order for the same user (same signer or different).
2806
+ * After resolution: YES holder taker_amount > 0, NO holder taker_amount = 0 (or vice versa).
2807
+ *
2808
+ * Prerequisite: each order's RedeemFeeOrderRecord must be registered via buildRegisterRedeemFeeOrderTx.
2809
+ */
2810
+ async buildBatchRedeemWithFeeTx(orderPairs, condition, operator, payer, opts) {
2811
+ if (orderPairs.length === 0) throw new InvalidParamError("At least 1 order pair required");
2812
+ const collateralMint = this.networkConfig.defaultCollateral.mint;
2813
+ const cfg = await this.fetchConfig();
2814
+ if (!cfg) throw new InvalidParamError("CLOB config not found on-chain");
2815
+ const clobConfig = this.configPda();
2816
+ const [yesMint] = PDA.yesMint(condition, this.programIds);
2817
+ const [noMint] = PDA.noMint(condition, this.programIds);
2818
+ const [collateralVault] = PDA.collateralVault(collateralMint, this.programIds);
2819
+ const [vaultTokenAccount] = PDA.vaultToken(collateralMint, this.programIds);
2820
+ const [yesExtraMeta] = PDA.extraAccountMetaList(yesMint, this.programIds);
2821
+ const [noExtraMeta] = PDA.extraAccountMetaList(noMint, this.programIds);
2822
+ const [hookConfig] = PDA.hookConfig(this.programIds);
2823
+ const [clobYesPosition] = PDA.position(condition, 1, clobConfig, this.programIds);
2824
+ const [clobNoPosition] = PDA.position(condition, 0, clobConfig, this.programIds);
2825
+ const clobYesAta = getAssociatedTokenAddressSync(yesMint, clobConfig, true, TOKEN_2022_PROGRAM_ID);
2826
+ const clobNoAta = getAssociatedTokenAddressSync(noMint, clobConfig, true, TOKEN_2022_PROGRAM_ID);
2827
+ const userAccounts = [];
2828
+ for (const { yes, no } of orderPairs) {
2829
+ const [yesRecord] = PDA.redeemFeeOrderRecord(yes.order.user, yes.order.nonce, this.programIds);
2830
+ const [noRecord] = PDA.redeemFeeOrderRecord(no.order.user, no.order.nonce, this.programIds);
2831
+ const userYesAta = getAssociatedTokenAddressSync(yesMint, yes.order.user, false, TOKEN_2022_PROGRAM_ID);
2832
+ const userNoAta = getAssociatedTokenAddressSync(noMint, no.order.user, false, TOKEN_2022_PROGRAM_ID);
2833
+ const [userYesPos] = PDA.position(condition, 1, yes.order.user, this.programIds);
2834
+ const [userNoPos] = PDA.position(condition, 0, no.order.user, this.programIds);
2835
+ const yesCollateral = getAssociatedTokenAddressSync(collateralMint, yes.order.user);
2836
+ const noCollateral = getAssociatedTokenAddressSync(collateralMint, no.order.user);
2837
+ userAccounts.push(
2838
+ { pubkey: yesRecord, isSigner: false, isWritable: true },
2839
+ { pubkey: noRecord, isSigner: false, isWritable: true },
2840
+ { pubkey: yes.order.user, isSigner: false, isWritable: false },
2841
+ { pubkey: no.order.user, isSigner: false, isWritable: false },
2842
+ { pubkey: userYesAta, isSigner: false, isWritable: true },
2843
+ { pubkey: userNoAta, isSigner: false, isWritable: true },
2844
+ { pubkey: userYesPos, isSigner: false, isWritable: true },
2845
+ { pubkey: userNoPos, isSigner: false, isWritable: true },
2846
+ { pubkey: yesCollateral, isSigner: false, isWritable: true },
2847
+ { pubkey: noCollateral, isSigner: false, isWritable: true }
2848
+ );
2849
+ }
2850
+ const hookAccounts = [
2851
+ { pubkey: yesExtraMeta, isSigner: false, isWritable: false },
2852
+ { pubkey: noExtraMeta, isSigner: false, isWritable: false },
2853
+ { pubkey: hookConfig, isSigner: false, isWritable: false },
2854
+ { pubkey: this.programIds.hook, isSigner: false, isWritable: false }
2855
+ ];
2856
+ let feeAccounts = [];
2857
+ if (this.programIds.feeManagement && this.feeConfigOwner) {
2858
+ const companyAddr = await this.companyAddress();
2859
+ const refVault = await this.referralVault();
2860
+ if (companyAddr && refVault) {
2861
+ const feeOverridePda = PDA.marketFeeOverride(condition, this.programIds)[0];
2862
+ const feeOverrideExists = await this.provider.connection.getAccountInfo(feeOverridePda);
2863
+ if (feeOverrideExists) {
2864
+ const oracleVault = opts?.marketOracleVault ?? await this.getMarketOracleVault(condition, collateralMint) ?? payer;
2865
+ feeAccounts = [
2866
+ { pubkey: this.programIds.feeManagement, isSigner: false, isWritable: false },
2867
+ { pubkey: PDA.feeConfig(this.feeConfigOwner, this.programIds)[0], isSigner: false, isWritable: false },
2868
+ { pubkey: feeOverridePda, isSigner: false, isWritable: false },
2869
+ { pubkey: getAssociatedTokenAddressSync(collateralMint, companyAddr), isSigner: false, isWritable: true },
2870
+ { pubkey: oracleVault, isSigner: false, isWritable: true },
2871
+ { pubkey: refVault, isSigner: false, isWritable: true }
2872
+ ];
2873
+ }
2874
+ }
2875
+ }
2876
+ await this._ensureClobOutcomeAtas(yesMint, noMint, clobConfig, clobYesAta, clobNoAta);
2877
+ const hookInitIxs = [];
2878
+ if (this.hookClient) {
2879
+ for (const mint of [yesMint, noMint]) {
2880
+ const ix = await this.hookClient.buildInitHookIxIfNeeded(mint, payer);
2881
+ if (ix) hookInitIxs.push(ix);
2882
+ }
2883
+ }
2884
+ const redeemIx = await this.program.methods.batchRedeemWithFee(orderPairs.length).accounts({
2885
+ operator,
2886
+ payer,
2887
+ clobConfig,
2888
+ condition,
2889
+ collateralVault,
2890
+ vaultTokenAccount,
2891
+ feeRecipient: cfg.feeRecipient,
2892
+ yesMint,
2893
+ noMint,
2894
+ clobYesAta,
2895
+ clobNoAta,
2896
+ clobYesPosition,
2897
+ clobNoPosition,
2898
+ conditionalTokensProgram: this.programIds.conditionalTokens,
2899
+ tokenProgram: TOKEN_PROGRAM_ID,
2900
+ token2022Program: TOKEN_2022_PROGRAM_ID,
2901
+ systemProgram: anchor5.web3.SystemProgram.programId
2902
+ }).remainingAccounts([...userAccounts, ...hookAccounts, ...feeAccounts]).instruction();
2903
+ const alt = opts?.lookupTable ?? await this.buildAltForCondition(condition, payer, collateralMint);
2904
+ return this._buildUnsignedVtx([...hookInitIxs, redeemIx], alt, payer);
2905
+ }
2906
+ // ─── batchMergeWithFee ────────────────────────────────────────────────────────
2907
+ /**
2908
+ * Build a VersionedTransaction for batchMergeWithFee (pre-resolution merge with fee).
2909
+ * Each pair: YES order + NO order with equal amounts for the same user.
2910
+ * Only yes_signer receives net USDS (mirrors EVM _matchMergeOrder).
2911
+ *
2912
+ * Prerequisite: each order's RedeemFeeOrderRecord must be registered via buildRegisterRedeemFeeOrderTx.
2913
+ */
2914
+ async buildBatchMergeWithFeeTx(orderPairs, condition, operator, payer, opts) {
2915
+ if (orderPairs.length === 0) throw new InvalidParamError("At least 1 order pair required");
2916
+ const collateralMint = this.networkConfig.defaultCollateral.mint;
2917
+ const cfg = await this.fetchConfig();
2918
+ if (!cfg) throw new InvalidParamError("CLOB config not found on-chain");
2919
+ const clobConfig = this.configPda();
2920
+ const [yesMint] = PDA.yesMint(condition, this.programIds);
2921
+ const [noMint] = PDA.noMint(condition, this.programIds);
2922
+ const [collateralVault] = PDA.collateralVault(collateralMint, this.programIds);
2923
+ const [vaultTokenAccount] = PDA.vaultToken(collateralMint, this.programIds);
2924
+ const [yesExtraMeta] = PDA.extraAccountMetaList(yesMint, this.programIds);
2925
+ const [noExtraMeta] = PDA.extraAccountMetaList(noMint, this.programIds);
2926
+ const [hookConfig] = PDA.hookConfig(this.programIds);
2927
+ const [clobYesPosition] = PDA.position(condition, 1, clobConfig, this.programIds);
2928
+ const [clobNoPosition] = PDA.position(condition, 0, clobConfig, this.programIds);
2929
+ const clobYesAta = getAssociatedTokenAddressSync(yesMint, clobConfig, true, TOKEN_2022_PROGRAM_ID);
2930
+ const clobNoAta = getAssociatedTokenAddressSync(noMint, clobConfig, true, TOKEN_2022_PROGRAM_ID);
2931
+ const userAccounts = [];
2932
+ for (const { yes, no } of orderPairs) {
2933
+ const [yesRecord] = PDA.redeemFeeOrderRecord(yes.order.user, yes.order.nonce, this.programIds);
2934
+ const [noRecord] = PDA.redeemFeeOrderRecord(no.order.user, no.order.nonce, this.programIds);
2935
+ const userYesAta = getAssociatedTokenAddressSync(yesMint, yes.order.user, false, TOKEN_2022_PROGRAM_ID);
2936
+ const userNoAta = getAssociatedTokenAddressSync(noMint, no.order.user, false, TOKEN_2022_PROGRAM_ID);
2937
+ const [userYesPos] = PDA.position(condition, 1, yes.order.user, this.programIds);
2938
+ const [userNoPos] = PDA.position(condition, 0, no.order.user, this.programIds);
2939
+ const yesCollateral = getAssociatedTokenAddressSync(collateralMint, yes.order.user);
2940
+ userAccounts.push(
2941
+ { pubkey: yesRecord, isSigner: false, isWritable: true },
2942
+ { pubkey: noRecord, isSigner: false, isWritable: true },
2943
+ { pubkey: yes.order.user, isSigner: false, isWritable: false },
2944
+ { pubkey: no.order.user, isSigner: false, isWritable: false },
2945
+ { pubkey: userYesAta, isSigner: false, isWritable: true },
2946
+ { pubkey: userNoAta, isSigner: false, isWritable: true },
2947
+ { pubkey: userYesPos, isSigner: false, isWritable: true },
2948
+ { pubkey: userNoPos, isSigner: false, isWritable: true },
2949
+ { pubkey: yesCollateral, isSigner: false, isWritable: true }
2950
+ );
2951
+ }
2952
+ const hookAccounts = [
2953
+ { pubkey: yesExtraMeta, isSigner: false, isWritable: false },
2954
+ { pubkey: noExtraMeta, isSigner: false, isWritable: false },
2955
+ { pubkey: hookConfig, isSigner: false, isWritable: false },
2956
+ { pubkey: this.programIds.hook, isSigner: false, isWritable: false }
2957
+ ];
2958
+ let feeAccounts = [];
2959
+ if (this.programIds.feeManagement && this.feeConfigOwner) {
2960
+ const companyAddr = await this.companyAddress();
2961
+ const refVault = await this.referralVault();
2962
+ if (companyAddr && refVault) {
2963
+ const feeOverridePda = PDA.marketFeeOverride(condition, this.programIds)[0];
2964
+ const feeOverrideExists = await this.provider.connection.getAccountInfo(feeOverridePda);
2965
+ if (feeOverrideExists) {
2966
+ const oracleVault = opts?.marketOracleVault ?? await this.getMarketOracleVault(condition, collateralMint) ?? payer;
2967
+ feeAccounts = [
2968
+ { pubkey: this.programIds.feeManagement, isSigner: false, isWritable: false },
2969
+ { pubkey: PDA.feeConfig(this.feeConfigOwner, this.programIds)[0], isSigner: false, isWritable: false },
2970
+ { pubkey: feeOverridePda, isSigner: false, isWritable: false },
2971
+ { pubkey: getAssociatedTokenAddressSync(collateralMint, companyAddr), isSigner: false, isWritable: true },
2972
+ { pubkey: oracleVault, isSigner: false, isWritable: true },
2973
+ { pubkey: refVault, isSigner: false, isWritable: true }
2974
+ ];
2975
+ }
2976
+ }
2977
+ }
2978
+ await this._ensureClobOutcomeAtas(yesMint, noMint, clobConfig, clobYesAta, clobNoAta);
2979
+ const hookInitIxs = [];
2980
+ if (this.hookClient) {
2981
+ for (const mint of [yesMint, noMint]) {
2982
+ const ix = await this.hookClient.buildInitHookIxIfNeeded(mint, payer);
2983
+ if (ix) hookInitIxs.push(ix);
2984
+ }
2985
+ }
2986
+ const mergeIx = await this.program.methods.batchMergeWithFee(orderPairs.length).accounts({
2987
+ operator,
2988
+ payer,
2989
+ clobConfig,
2990
+ condition,
2991
+ collateralVault,
2992
+ vaultTokenAccount,
2993
+ feeRecipient: cfg.feeRecipient,
2994
+ yesMint,
2995
+ noMint,
2996
+ clobYesAta,
2997
+ clobNoAta,
2998
+ clobYesPosition,
2999
+ clobNoPosition,
3000
+ conditionalTokensProgram: this.programIds.conditionalTokens,
3001
+ tokenProgram: TOKEN_PROGRAM_ID,
3002
+ token2022Program: TOKEN_2022_PROGRAM_ID,
3003
+ systemProgram: anchor5.web3.SystemProgram.programId
3004
+ }).remainingAccounts([...userAccounts, ...hookAccounts, ...feeAccounts]).instruction();
3005
+ const alt = opts?.lookupTable ?? await this.buildAltForCondition(condition, payer, collateralMint);
3006
+ return this._buildUnsignedVtx([...hookInitIxs, mergeIx], alt, payer);
3007
+ }
3008
+ /**
3009
+ * Build ALT for batchCollectRedeemEarly — includes per-user accounts so all
3010
+ * remaining_accounts fit as 1-byte ALT indices instead of 32-byte inline addresses.
3011
+ */
3012
+ async buildAltForCollectBatch(condition, payer, collateralMint, signedOrders, outcomeIndex) {
3013
+ const userKeys = signedOrders.map((o) => o.order.user.toBase58()).sort((a, b) => a.localeCompare(b)).join(",");
3014
+ const cacheKey = `${condition.toBase58()}:collect:${userKeys}`;
2642
3015
  if (this._altCache.has(cacheKey)) return this._altCache.get(cacheKey);
2643
- const mint = collateralMint ?? this.networkConfig.defaultCollateral.mint;
2644
- const payer = this.walletPubkey;
2645
3016
  const { connection } = this.provider;
2646
3017
  const clobConfigPda = this.configPda();
2647
3018
  const [yesMint] = PDA.yesMint(condition, this.programIds);
2648
3019
  const [noMint] = PDA.noMint(condition, this.programIds);
2649
- const [extraAccountMeta] = PDA.extraAccountMetaList(yesMint, this.programIds);
3020
+ const outcomeMint = outcomeIndex === 1 ? yesMint : noMint;
3021
+ const [extraAccountMeta] = PDA.extraAccountMetaList(outcomeMint, this.programIds);
2650
3022
  const [hookConfig] = PDA.hookConfig(this.programIds);
2651
- const [collateralVault] = PDA.collateralVault(mint, this.programIds);
2652
- const [vaultTokenAccount] = PDA.vaultToken(mint, this.programIds);
3023
+ const [collateralVault] = PDA.collateralVault(collateralMint, this.programIds);
3024
+ const [vaultTokenAccount] = PDA.vaultToken(collateralMint, this.programIds);
2653
3025
  const clobYesAta = getAssociatedTokenAddressSync(yesMint, clobConfigPda, true, TOKEN_2022_PROGRAM_ID);
2654
3026
  const clobNoAta = getAssociatedTokenAddressSync(noMint, clobConfigPda, true, TOKEN_2022_PROGRAM_ID);
3027
+ const [clobYesPos] = PDA.position(condition, 1, clobConfigPda, this.programIds);
3028
+ const [clobNoPos] = PDA.position(condition, 0, clobConfigPda, this.programIds);
2655
3029
  const feeRecipientAddr = (await this.fetchConfig())?.feeRecipient;
2656
3030
  const addresses = [
2657
- Ed25519Program.programId,
2658
3031
  this.programIds.clobExchange,
2659
3032
  this.programIds.conditionalTokens,
2660
3033
  this.programIds.hook,
2661
3034
  TOKEN_PROGRAM_ID,
2662
3035
  TOKEN_2022_PROGRAM_ID,
2663
3036
  SystemProgram.programId,
2664
- SYSVAR_INSTRUCTIONS_PUBKEY,
2665
3037
  clobConfigPda,
2666
3038
  hookConfig,
2667
3039
  condition,
@@ -2671,7 +3043,9 @@ ${logs.join("\n")}`);
2671
3043
  collateralVault,
2672
3044
  vaultTokenAccount,
2673
3045
  clobYesAta,
2674
- clobNoAta
3046
+ clobNoAta,
3047
+ clobYesPos,
3048
+ clobNoPos
2675
3049
  ];
2676
3050
  if (feeRecipientAddr) addresses.push(feeRecipientAddr);
2677
3051
  if (this.feeConfigOwner && this.programIds.feeManagement) {
@@ -2680,11 +3054,17 @@ ${logs.join("\n")}`);
2680
3054
  addresses.push(this.programIds.feeManagement);
2681
3055
  addresses.push(PDA.feeConfig(this.feeConfigOwner, this.programIds)[0]);
2682
3056
  addresses.push(PDA.marketFeeOverride(condition, this.programIds)[0]);
2683
- if (companyAddr) addresses.push(getAssociatedTokenAddressSync(mint, companyAddr));
3057
+ if (companyAddr) addresses.push(getAssociatedTokenAddressSync(collateralMint, companyAddr));
2684
3058
  if (refVault) addresses.push(refVault);
2685
- const oracleVault = await this.getMarketOracleVault(condition, mint) ?? payer;
3059
+ const oracleVault = await this.getMarketOracleVault(condition, collateralMint) ?? payer;
2686
3060
  addresses.push(oracleVault);
2687
3061
  }
3062
+ for (const { order } of signedOrders) {
3063
+ const [collectFeeOrderRecord] = PDA.collectFeeOrderRecord(order.user, order.nonce, this.programIds);
3064
+ const userTokenAta = getAssociatedTokenAddressSync(outcomeMint, order.user, false, TOKEN_2022_PROGRAM_ID);
3065
+ const [userPosition] = PDA.position(condition, outcomeIndex, order.user, this.programIds);
3066
+ addresses.push(collectFeeOrderRecord, order.user, userTokenAta, userPosition);
3067
+ }
2688
3068
  const slot = await connection.getSlot("finalized");
2689
3069
  const [createIx, altAddress] = AddressLookupTableProgram.createLookupTable(
2690
3070
  { authority: payer, payer, recentSlot: slot }
@@ -2708,11 +3088,86 @@ ${logs.join("\n")}`);
2708
3088
  }
2709
3089
  throw new Error(`ALT ${altAddress.toBase58()} not active after 30s`);
2710
3090
  }
2711
- // ─── Queries ─────────────────────────────────────────────────────────────────
2712
- async fetchConfig() {
2713
- try {
2714
- const acc = await this.program.account.clobConfig.fetch(this.configPda());
2715
- return {
3091
+ /**
3092
+ * Build ALT with static accounts for a condition — no order-specific PDAs needed.
3093
+ * Use before buildBatchCollectRedeemEarlyTx when no prior buildMatchOrdersTx ran in this session.
3094
+ */
3095
+ async buildAltForCondition(condition, _payer, collateralMint) {
3096
+ const cacheKey = condition.toBase58();
3097
+ if (this._altCache.has(cacheKey)) return this._altCache.get(cacheKey);
3098
+ const mint = collateralMint ?? this.networkConfig.defaultCollateral.mint;
3099
+ const payer = this.walletPubkey;
3100
+ const { connection } = this.provider;
3101
+ const clobConfigPda = this.configPda();
3102
+ const [yesMint] = PDA.yesMint(condition, this.programIds);
3103
+ const [noMint] = PDA.noMint(condition, this.programIds);
3104
+ const [extraAccountMeta] = PDA.extraAccountMetaList(yesMint, this.programIds);
3105
+ const [hookConfig] = PDA.hookConfig(this.programIds);
3106
+ const [collateralVault] = PDA.collateralVault(mint, this.programIds);
3107
+ const [vaultTokenAccount] = PDA.vaultToken(mint, this.programIds);
3108
+ const clobYesAta = getAssociatedTokenAddressSync(yesMint, clobConfigPda, true, TOKEN_2022_PROGRAM_ID);
3109
+ const clobNoAta = getAssociatedTokenAddressSync(noMint, clobConfigPda, true, TOKEN_2022_PROGRAM_ID);
3110
+ const feeRecipientAddr = (await this.fetchConfig())?.feeRecipient;
3111
+ const addresses = [
3112
+ Ed25519Program.programId,
3113
+ this.programIds.clobExchange,
3114
+ this.programIds.conditionalTokens,
3115
+ this.programIds.hook,
3116
+ TOKEN_PROGRAM_ID,
3117
+ TOKEN_2022_PROGRAM_ID,
3118
+ SystemProgram.programId,
3119
+ SYSVAR_INSTRUCTIONS_PUBKEY,
3120
+ clobConfigPda,
3121
+ hookConfig,
3122
+ condition,
3123
+ yesMint,
3124
+ noMint,
3125
+ extraAccountMeta,
3126
+ collateralVault,
3127
+ vaultTokenAccount,
3128
+ clobYesAta,
3129
+ clobNoAta
3130
+ ];
3131
+ if (feeRecipientAddr) addresses.push(feeRecipientAddr);
3132
+ if (this.feeConfigOwner && this.programIds.feeManagement) {
3133
+ const companyAddr = await this.companyAddress();
3134
+ const refVault = await this.referralVault();
3135
+ addresses.push(this.programIds.feeManagement);
3136
+ addresses.push(PDA.feeConfig(this.feeConfigOwner, this.programIds)[0]);
3137
+ addresses.push(PDA.marketFeeOverride(condition, this.programIds)[0]);
3138
+ if (companyAddr) addresses.push(getAssociatedTokenAddressSync(mint, companyAddr));
3139
+ if (refVault) addresses.push(refVault);
3140
+ const oracleVault = await this.getMarketOracleVault(condition, mint) ?? payer;
3141
+ addresses.push(oracleVault);
3142
+ }
3143
+ const slot = await connection.getSlot("finalized");
3144
+ const [createIx, altAddress] = AddressLookupTableProgram.createLookupTable(
3145
+ { authority: payer, payer, recentSlot: slot }
3146
+ );
3147
+ const BATCH = 30;
3148
+ const extendIxs = [];
3149
+ for (let i = 0; i < addresses.length; i += BATCH) {
3150
+ extendIxs.push(AddressLookupTableProgram.extendLookupTable(
3151
+ { payer, authority: payer, lookupTable: altAddress, addresses: addresses.slice(i, i + BATCH) }
3152
+ ));
3153
+ }
3154
+ await this._sendLegacyTx([createIx, extendIxs[0]]);
3155
+ for (let i = 1; i < extendIxs.length; i++) await this._sendLegacyTx([extendIxs[i]]);
3156
+ for (let attempt = 0; attempt < 30; attempt++) {
3157
+ await new Promise((r) => setTimeout(r, 1e3));
3158
+ const res = await connection.getAddressLookupTable(altAddress);
3159
+ if (res.value && res.value.state.addresses.length === addresses.length) {
3160
+ this._altCache.set(cacheKey, res.value);
3161
+ return res.value;
3162
+ }
3163
+ }
3164
+ throw new Error(`ALT ${altAddress.toBase58()} not active after 30s`);
3165
+ }
3166
+ // ─── Queries ─────────────────────────────────────────────────────────────────
3167
+ async fetchConfig() {
3168
+ try {
3169
+ const acc = await this.program.account.clobConfig.fetch(this.configPda());
3170
+ return {
2716
3171
  owner: acc.owner,
2717
3172
  operators: acc.operators,
2718
3173
  operatorsLen: acc.operatorsLen,
@@ -9394,7 +9849,8 @@ var clob_exchange_default = {
9394
9849
  name: "batch_collect_redeem_early",
9395
9850
  docs: [
9396
9851
  "Batch collect fee tokens from winning users after question resolution,",
9397
- "redeem them via CTF, and distribute USDS via fee_management."
9852
+ "redeem them via CTF, and distribute USDS via fee_management.",
9853
+ "Requires each user's CollectFeeOrderRecord to be registered via register_collect_fee_order."
9398
9854
  ],
9399
9855
  discriminator: [
9400
9856
  87,
@@ -9504,7 +9960,7 @@ var clob_exchange_default = {
9504
9960
  {
9505
9961
  name: "clob_yes_ata",
9506
9962
  docs: [
9507
- "CLOB's YES ATA (Token-2022) \u2014 must be pre-initialized (created during prior matchOrders)."
9963
+ "CLOB's YES ATA (Token-2022) \u2014 must be pre-initialized."
9508
9964
  ],
9509
9965
  writable: true
9510
9966
  },
@@ -9523,9 +9979,6 @@ var clob_exchange_default = {
9523
9979
  name: "clob_no_position",
9524
9980
  writable: true
9525
9981
  },
9526
- {
9527
- name: "ix_sysvar"
9528
- },
9529
9982
  {
9530
9983
  name: "conditional_tokens_program",
9531
9984
  address: "A6N1F8MRsdgcojAx8p6FaECvw8mo8w6qJcWsbKQBANK4"
@@ -9544,10 +9997,6 @@ var clob_exchange_default = {
9544
9997
  }
9545
9998
  ],
9546
9999
  args: [
9547
- {
9548
- name: "ix_index",
9549
- type: "u8"
9550
- },
9551
10000
  {
9552
10001
  name: "order_count",
9553
10002
  type: "u8"
@@ -9559,61 +10008,144 @@ var clob_exchange_default = {
9559
10008
  ]
9560
10009
  },
9561
10010
  {
9562
- name: "cancel_order",
10011
+ name: "batch_merge_with_fee",
9563
10012
  docs: [
9564
- "Cancel an order \u2014 close OrderRecord PDA, return rent to maker."
10013
+ "Batch merge YES+NO tokens before resolution. Returns net USDS to yes_signer, keeps fee.",
10014
+ "Mirrors EVM _matchMergeOrder flow."
9565
10015
  ],
9566
10016
  discriminator: [
9567
- 95,
9568
- 129,
9569
- 237,
9570
- 240,
9571
- 8,
9572
- 49,
9573
- 223,
9574
- 132
10017
+ 56,
10018
+ 127,
10019
+ 113,
10020
+ 232,
10021
+ 208,
10022
+ 177,
10023
+ 157,
10024
+ 230
9575
10025
  ],
9576
10026
  accounts: [
9577
10027
  {
9578
- name: "maker",
9579
- docs: [
9580
- "Must be the order maker/signer"
9581
- ],
10028
+ name: "operator",
9582
10029
  signer: true
9583
10030
  },
9584
10031
  {
9585
- name: "order_record",
10032
+ name: "payer",
10033
+ writable: true,
10034
+ signer: true
10035
+ },
10036
+ {
10037
+ name: "clob_config",
9586
10038
  writable: true,
9587
10039
  pda: {
9588
10040
  seeds: [
9589
10041
  {
9590
10042
  kind: "const",
9591
10043
  value: [
10044
+ 99,
10045
+ 108,
9592
10046
  111,
9593
- 114,
9594
- 100,
9595
- 101,
9596
- 114,
10047
+ 98,
9597
10048
  95,
9598
- 114,
9599
- 101,
9600
10049
  99,
9601
10050
  111,
10051
+ 110,
10052
+ 102,
10053
+ 105,
10054
+ 103
10055
+ ]
10056
+ }
10057
+ ]
10058
+ }
10059
+ },
10060
+ {
10061
+ name: "condition",
10062
+ writable: true
10063
+ },
10064
+ {
10065
+ name: "collateral_vault",
10066
+ writable: true,
10067
+ pda: {
10068
+ seeds: [
10069
+ {
10070
+ kind: "const",
10071
+ value: [
10072
+ 99,
10073
+ 111,
10074
+ 108,
10075
+ 108,
10076
+ 97,
10077
+ 116,
10078
+ 101,
9602
10079
  114,
9603
- 100
10080
+ 97,
10081
+ 108,
10082
+ 95,
10083
+ 118,
10084
+ 97,
10085
+ 117,
10086
+ 108,
10087
+ 116
9604
10088
  ]
9605
10089
  },
9606
10090
  {
9607
10091
  kind: "account",
9608
- path: "maker"
9609
- },
9610
- {
9611
- kind: "arg",
9612
- path: "nonce"
10092
+ path: "condition.collateral_mint",
10093
+ account: "Condition"
9613
10094
  }
9614
- ]
10095
+ ],
10096
+ program: {
10097
+ kind: "account",
10098
+ path: "conditional_tokens_program"
10099
+ }
9615
10100
  }
9616
10101
  },
10102
+ {
10103
+ name: "vault_token_account",
10104
+ writable: true
10105
+ },
10106
+ {
10107
+ name: "fee_recipient",
10108
+ docs: [
10109
+ "CLOB USDS ATA \u2014 receives USDS from merge, distributes to users + fee."
10110
+ ],
10111
+ writable: true
10112
+ },
10113
+ {
10114
+ name: "yes_mint",
10115
+ writable: true
10116
+ },
10117
+ {
10118
+ name: "no_mint",
10119
+ writable: true
10120
+ },
10121
+ {
10122
+ name: "clob_yes_ata",
10123
+ writable: true
10124
+ },
10125
+ {
10126
+ name: "clob_no_ata",
10127
+ writable: true
10128
+ },
10129
+ {
10130
+ name: "clob_yes_position",
10131
+ writable: true
10132
+ },
10133
+ {
10134
+ name: "clob_no_position",
10135
+ writable: true
10136
+ },
10137
+ {
10138
+ name: "conditional_tokens_program",
10139
+ address: "A6N1F8MRsdgcojAx8p6FaECvw8mo8w6qJcWsbKQBANK4"
10140
+ },
10141
+ {
10142
+ name: "token_program",
10143
+ address: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
10144
+ },
10145
+ {
10146
+ name: "token_2022_program",
10147
+ address: "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb"
10148
+ },
9617
10149
  {
9618
10150
  name: "system_program",
9619
10151
  address: "11111111111111111111111111111111"
@@ -9621,38 +10153,257 @@ var clob_exchange_default = {
9621
10153
  ],
9622
10154
  args: [
9623
10155
  {
9624
- name: "nonce",
9625
- type: "u64"
10156
+ name: "order_count",
10157
+ type: "u8"
9626
10158
  }
9627
10159
  ]
9628
10160
  },
9629
10161
  {
9630
- name: "force_reset_clob",
10162
+ name: "batch_redeem_with_fee",
10163
+ docs: [
10164
+ "Batch redeem YES+NO tokens after resolution. Returns net USDS to users, keeps fee.",
10165
+ "Mirrors EVM _matchRedeemOrder flow."
10166
+ ],
9631
10167
  discriminator: [
9632
- 96,
9633
- 95,
9634
- 187,
9635
- 95,
9636
- 65,
9637
- 135,
9638
- 120,
9639
- 204
10168
+ 240,
10169
+ 238,
10170
+ 168,
10171
+ 110,
10172
+ 84,
10173
+ 41,
10174
+ 165,
10175
+ 2
9640
10176
  ],
9641
10177
  accounts: [
9642
10178
  {
9643
- name: "upgrade_authority",
9644
- docs: [
9645
- "Must be the upgrade authority (deployer). Checked in handler via",
9646
- "programdata account so we don't hardcode the pubkey."
9647
- ],
9648
- writable: true,
10179
+ name: "operator",
9649
10180
  signer: true
9650
10181
  },
9651
10182
  {
9652
- name: "program_data",
9653
- docs: [
9654
- "The clob_exchange programdata account (BPF loader stores the upgrade authority here)."
9655
- ]
10183
+ name: "payer",
10184
+ writable: true,
10185
+ signer: true
10186
+ },
10187
+ {
10188
+ name: "clob_config",
10189
+ writable: true,
10190
+ pda: {
10191
+ seeds: [
10192
+ {
10193
+ kind: "const",
10194
+ value: [
10195
+ 99,
10196
+ 108,
10197
+ 111,
10198
+ 98,
10199
+ 95,
10200
+ 99,
10201
+ 111,
10202
+ 110,
10203
+ 102,
10204
+ 105,
10205
+ 103
10206
+ ]
10207
+ }
10208
+ ]
10209
+ }
10210
+ },
10211
+ {
10212
+ name: "condition",
10213
+ writable: true
10214
+ },
10215
+ {
10216
+ name: "collateral_vault",
10217
+ writable: true,
10218
+ pda: {
10219
+ seeds: [
10220
+ {
10221
+ kind: "const",
10222
+ value: [
10223
+ 99,
10224
+ 111,
10225
+ 108,
10226
+ 108,
10227
+ 97,
10228
+ 116,
10229
+ 101,
10230
+ 114,
10231
+ 97,
10232
+ 108,
10233
+ 95,
10234
+ 118,
10235
+ 97,
10236
+ 117,
10237
+ 108,
10238
+ 116
10239
+ ]
10240
+ },
10241
+ {
10242
+ kind: "account",
10243
+ path: "condition.collateral_mint",
10244
+ account: "Condition"
10245
+ }
10246
+ ],
10247
+ program: {
10248
+ kind: "account",
10249
+ path: "conditional_tokens_program"
10250
+ }
10251
+ }
10252
+ },
10253
+ {
10254
+ name: "vault_token_account",
10255
+ writable: true
10256
+ },
10257
+ {
10258
+ name: "fee_recipient",
10259
+ docs: [
10260
+ "CLOB USDS ATA \u2014 receives USDS from redeem, distributes to users + fee."
10261
+ ],
10262
+ writable: true
10263
+ },
10264
+ {
10265
+ name: "yes_mint",
10266
+ writable: true
10267
+ },
10268
+ {
10269
+ name: "no_mint",
10270
+ writable: true
10271
+ },
10272
+ {
10273
+ name: "clob_yes_ata",
10274
+ writable: true
10275
+ },
10276
+ {
10277
+ name: "clob_no_ata",
10278
+ writable: true
10279
+ },
10280
+ {
10281
+ name: "clob_yes_position",
10282
+ writable: true
10283
+ },
10284
+ {
10285
+ name: "clob_no_position",
10286
+ writable: true
10287
+ },
10288
+ {
10289
+ name: "conditional_tokens_program",
10290
+ address: "A6N1F8MRsdgcojAx8p6FaECvw8mo8w6qJcWsbKQBANK4"
10291
+ },
10292
+ {
10293
+ name: "token_program",
10294
+ address: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
10295
+ },
10296
+ {
10297
+ name: "token_2022_program",
10298
+ address: "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb"
10299
+ },
10300
+ {
10301
+ name: "system_program",
10302
+ address: "11111111111111111111111111111111"
10303
+ }
10304
+ ],
10305
+ args: [
10306
+ {
10307
+ name: "order_count",
10308
+ type: "u8"
10309
+ }
10310
+ ]
10311
+ },
10312
+ {
10313
+ name: "cancel_order",
10314
+ docs: [
10315
+ "Cancel an order \u2014 close OrderRecord PDA, return rent to maker."
10316
+ ],
10317
+ discriminator: [
10318
+ 95,
10319
+ 129,
10320
+ 237,
10321
+ 240,
10322
+ 8,
10323
+ 49,
10324
+ 223,
10325
+ 132
10326
+ ],
10327
+ accounts: [
10328
+ {
10329
+ name: "maker",
10330
+ docs: [
10331
+ "Must be the order maker/signer"
10332
+ ],
10333
+ signer: true
10334
+ },
10335
+ {
10336
+ name: "order_record",
10337
+ writable: true,
10338
+ pda: {
10339
+ seeds: [
10340
+ {
10341
+ kind: "const",
10342
+ value: [
10343
+ 111,
10344
+ 114,
10345
+ 100,
10346
+ 101,
10347
+ 114,
10348
+ 95,
10349
+ 114,
10350
+ 101,
10351
+ 99,
10352
+ 111,
10353
+ 114,
10354
+ 100
10355
+ ]
10356
+ },
10357
+ {
10358
+ kind: "account",
10359
+ path: "maker"
10360
+ },
10361
+ {
10362
+ kind: "arg",
10363
+ path: "nonce"
10364
+ }
10365
+ ]
10366
+ }
10367
+ },
10368
+ {
10369
+ name: "system_program",
10370
+ address: "11111111111111111111111111111111"
10371
+ }
10372
+ ],
10373
+ args: [
10374
+ {
10375
+ name: "nonce",
10376
+ type: "u64"
10377
+ }
10378
+ ]
10379
+ },
10380
+ {
10381
+ name: "force_reset_clob",
10382
+ discriminator: [
10383
+ 96,
10384
+ 95,
10385
+ 187,
10386
+ 95,
10387
+ 65,
10388
+ 135,
10389
+ 120,
10390
+ 204
10391
+ ],
10392
+ accounts: [
10393
+ {
10394
+ name: "upgrade_authority",
10395
+ docs: [
10396
+ "Must be the upgrade authority (deployer). Checked in handler via",
10397
+ "programdata account so we don't hardcode the pubkey."
10398
+ ],
10399
+ writable: true,
10400
+ signer: true
10401
+ },
10402
+ {
10403
+ name: "program_data",
10404
+ docs: [
10405
+ "The clob_exchange programdata account (BPF loader stores the upgrade authority here)."
10406
+ ]
9656
10407
  },
9657
10408
  {
9658
10409
  name: "clob_config",
@@ -10494,27 +11245,25 @@ var clob_exchange_default = {
10494
11245
  ]
10495
11246
  },
10496
11247
  {
10497
- name: "register_order",
11248
+ name: "register_collect_fee_order",
10498
11249
  docs: [
10499
- "Register a signed order on-chain (Ed25519 verify at registration time).",
10500
- "ix[0] must be Ed25519 precompile with 1 entry for order.signer."
11250
+ "Register a signed CollectFeeOrder on-chain (Ed25519 verify at registration time).",
11251
+ "ix[0] must be Ed25519 precompile with 1 entry for order.user.",
11252
+ "Call once per user before batch_collect_redeem_early."
10501
11253
  ],
10502
11254
  discriminator: [
10503
- 92,
10504
- 37,
10505
- 29,
10506
- 46,
10507
- 77,
10508
- 250,
10509
- 219,
10510
- 6
11255
+ 63,
11256
+ 26,
11257
+ 202,
11258
+ 98,
11259
+ 195,
11260
+ 2,
11261
+ 211,
11262
+ 36
10511
11263
  ],
10512
11264
  accounts: [
10513
11265
  {
10514
11266
  name: "payer",
10515
- docs: [
10516
- "Operator pays rent for the OrderRecord PDA."
10517
- ],
10518
11267
  writable: true,
10519
11268
  signer: true
10520
11269
  },
@@ -10549,27 +11298,128 @@ var clob_exchange_default = {
10549
11298
  name: "order_signer"
10550
11299
  },
10551
11300
  {
10552
- name: "order_record",
11301
+ name: "collect_fee_order_record",
10553
11302
  writable: true,
10554
11303
  pda: {
10555
11304
  seeds: [
10556
11305
  {
10557
11306
  kind: "const",
10558
11307
  value: [
11308
+ 99,
10559
11309
  111,
10560
- 114,
10561
- 100,
10562
- 101,
10563
- 114,
10564
- 95,
10565
- 114,
11310
+ 108,
11311
+ 108,
10566
11312
  101,
10567
11313
  99,
11314
+ 116,
11315
+ 95,
10568
11316
  111,
10569
11317
  114,
10570
- 100
10571
- ]
10572
- },
11318
+ 100,
11319
+ 101,
11320
+ 114
11321
+ ]
11322
+ },
11323
+ {
11324
+ kind: "account",
11325
+ path: "order_signer"
11326
+ },
11327
+ {
11328
+ kind: "arg",
11329
+ path: "nonce"
11330
+ }
11331
+ ]
11332
+ }
11333
+ },
11334
+ {
11335
+ name: "system_program",
11336
+ address: "11111111111111111111111111111111"
11337
+ }
11338
+ ],
11339
+ args: [
11340
+ {
11341
+ name: "nonce",
11342
+ type: "u64"
11343
+ }
11344
+ ]
11345
+ },
11346
+ {
11347
+ name: "register_order",
11348
+ docs: [
11349
+ "Register a signed order on-chain (Ed25519 verify at registration time).",
11350
+ "ix[0] must be Ed25519 precompile with 1 entry for order.signer."
11351
+ ],
11352
+ discriminator: [
11353
+ 92,
11354
+ 37,
11355
+ 29,
11356
+ 46,
11357
+ 77,
11358
+ 250,
11359
+ 219,
11360
+ 6
11361
+ ],
11362
+ accounts: [
11363
+ {
11364
+ name: "payer",
11365
+ docs: [
11366
+ "Operator pays rent for the OrderRecord PDA."
11367
+ ],
11368
+ writable: true,
11369
+ signer: true
11370
+ },
11371
+ {
11372
+ name: "clob_config",
11373
+ pda: {
11374
+ seeds: [
11375
+ {
11376
+ kind: "const",
11377
+ value: [
11378
+ 99,
11379
+ 108,
11380
+ 111,
11381
+ 98,
11382
+ 95,
11383
+ 99,
11384
+ 111,
11385
+ 110,
11386
+ 102,
11387
+ 105,
11388
+ 103
11389
+ ]
11390
+ }
11391
+ ]
11392
+ }
11393
+ },
11394
+ {
11395
+ name: "ix_sysvar",
11396
+ address: "Sysvar1nstructions1111111111111111111111111"
11397
+ },
11398
+ {
11399
+ name: "order_signer"
11400
+ },
11401
+ {
11402
+ name: "order_record",
11403
+ writable: true,
11404
+ pda: {
11405
+ seeds: [
11406
+ {
11407
+ kind: "const",
11408
+ value: [
11409
+ 111,
11410
+ 114,
11411
+ 100,
11412
+ 101,
11413
+ 114,
11414
+ 95,
11415
+ 114,
11416
+ 101,
11417
+ 99,
11418
+ 111,
11419
+ 114,
11420
+ 100
11421
+ ]
11422
+ },
10573
11423
  {
10574
11424
  kind: "account",
10575
11425
  path: "order_signer"
@@ -10619,6 +11469,107 @@ var clob_exchange_default = {
10619
11469
  }
10620
11470
  ]
10621
11471
  },
11472
+ {
11473
+ name: "register_redeem_fee_order",
11474
+ docs: [
11475
+ "Register a signed RedeemFeeOrder on-chain (Ed25519 verify + PDA creation).",
11476
+ "Prerequisite for batch_redeem_with_fee and batch_merge_with_fee."
11477
+ ],
11478
+ discriminator: [
11479
+ 129,
11480
+ 167,
11481
+ 199,
11482
+ 14,
11483
+ 217,
11484
+ 12,
11485
+ 76,
11486
+ 162
11487
+ ],
11488
+ accounts: [
11489
+ {
11490
+ name: "payer",
11491
+ writable: true,
11492
+ signer: true
11493
+ },
11494
+ {
11495
+ name: "clob_config",
11496
+ pda: {
11497
+ seeds: [
11498
+ {
11499
+ kind: "const",
11500
+ value: [
11501
+ 99,
11502
+ 108,
11503
+ 111,
11504
+ 98,
11505
+ 95,
11506
+ 99,
11507
+ 111,
11508
+ 110,
11509
+ 102,
11510
+ 105,
11511
+ 103
11512
+ ]
11513
+ }
11514
+ ]
11515
+ }
11516
+ },
11517
+ {
11518
+ name: "ix_sysvar",
11519
+ address: "Sysvar1nstructions1111111111111111111111111"
11520
+ },
11521
+ {
11522
+ name: "order_signer"
11523
+ },
11524
+ {
11525
+ name: "redeem_fee_order_record",
11526
+ writable: true,
11527
+ pda: {
11528
+ seeds: [
11529
+ {
11530
+ kind: "const",
11531
+ value: [
11532
+ 114,
11533
+ 101,
11534
+ 100,
11535
+ 101,
11536
+ 101,
11537
+ 109,
11538
+ 95,
11539
+ 102,
11540
+ 101,
11541
+ 101,
11542
+ 95,
11543
+ 111,
11544
+ 114,
11545
+ 100,
11546
+ 101,
11547
+ 114
11548
+ ]
11549
+ },
11550
+ {
11551
+ kind: "account",
11552
+ path: "order_signer"
11553
+ },
11554
+ {
11555
+ kind: "arg",
11556
+ path: "nonce"
11557
+ }
11558
+ ]
11559
+ }
11560
+ },
11561
+ {
11562
+ name: "system_program",
11563
+ address: "11111111111111111111111111111111"
11564
+ }
11565
+ ],
11566
+ args: [
11567
+ {
11568
+ name: "nonce",
11569
+ type: "u64"
11570
+ }
11571
+ ]
11572
+ },
10622
11573
  {
10623
11574
  name: "reinit_clob",
10624
11575
  discriminator: [
@@ -10783,6 +11734,19 @@ var clob_exchange_default = {
10783
11734
  160
10784
11735
  ]
10785
11736
  },
11737
+ {
11738
+ name: "CollectFeeOrderRecord",
11739
+ discriminator: [
11740
+ 145,
11741
+ 140,
11742
+ 193,
11743
+ 74,
11744
+ 12,
11745
+ 98,
11746
+ 74,
11747
+ 130
11748
+ ]
11749
+ },
10786
11750
  {
10787
11751
  name: "OrderStatus",
10788
11752
  discriminator: [
@@ -10796,6 +11760,19 @@ var clob_exchange_default = {
10796
11760
  3
10797
11761
  ]
10798
11762
  },
11763
+ {
11764
+ name: "RedeemFeeOrderRecord",
11765
+ discriminator: [
11766
+ 88,
11767
+ 3,
11768
+ 122,
11769
+ 192,
11770
+ 131,
11771
+ 243,
11772
+ 143,
11773
+ 146
11774
+ ]
11775
+ },
10799
11776
  {
10800
11777
  name: "SignedOrderRecord",
10801
11778
  discriminator: [
@@ -10992,6 +11969,53 @@ var clob_exchange_default = {
10992
11969
  ]
10993
11970
  }
10994
11971
  },
11972
+ {
11973
+ name: "CollectFeeOrderRecord",
11974
+ docs: [
11975
+ "On-chain record of a signed CollectFeeOrder.",
11976
+ "Created by `register_collect_fee_order` after Ed25519 verification.",
11977
+ "Read and marked collected by `batch_collect_redeem_early`.",
11978
+ "",
11979
+ 'PDA seeds: [b"collect_order", user, nonce_le_bytes]'
11980
+ ],
11981
+ type: {
11982
+ kind: "struct",
11983
+ fields: [
11984
+ {
11985
+ name: "user",
11986
+ type: "pubkey"
11987
+ },
11988
+ {
11989
+ name: "condition",
11990
+ type: "pubkey"
11991
+ },
11992
+ {
11993
+ name: "token_mint",
11994
+ type: "pubkey"
11995
+ },
11996
+ {
11997
+ name: "amount",
11998
+ type: "u64"
11999
+ },
12000
+ {
12001
+ name: "nonce",
12002
+ type: "u64"
12003
+ },
12004
+ {
12005
+ name: "expiry",
12006
+ type: "i64"
12007
+ },
12008
+ {
12009
+ name: "is_collected",
12010
+ type: "bool"
12011
+ },
12012
+ {
12013
+ name: "bump",
12014
+ type: "u8"
12015
+ }
12016
+ ]
12017
+ }
12018
+ },
10995
12019
  {
10996
12020
  name: "ComplementaryMatchEvent",
10997
12021
  type: {
@@ -11224,6 +12248,57 @@ var clob_exchange_default = {
11224
12248
  ]
11225
12249
  }
11226
12250
  },
12251
+ {
12252
+ name: "RedeemFeeOrderRecord",
12253
+ docs: [
12254
+ "On-chain record of a signed RedeemFeeOrder.",
12255
+ "Created by `register_redeem_fee_order` after Ed25519 verification.",
12256
+ "Read and marked collected by `batch_redeem_with_fee` / `batch_merge_with_fee`.",
12257
+ "",
12258
+ 'PDA seeds: [b"redeem_fee_order", user, nonce_le_bytes]'
12259
+ ],
12260
+ type: {
12261
+ kind: "struct",
12262
+ fields: [
12263
+ {
12264
+ name: "user",
12265
+ type: "pubkey"
12266
+ },
12267
+ {
12268
+ name: "condition",
12269
+ type: "pubkey"
12270
+ },
12271
+ {
12272
+ name: "token_mint",
12273
+ type: "pubkey"
12274
+ },
12275
+ {
12276
+ name: "amount",
12277
+ type: "u64"
12278
+ },
12279
+ {
12280
+ name: "taker_amount",
12281
+ type: "u64"
12282
+ },
12283
+ {
12284
+ name: "nonce",
12285
+ type: "u64"
12286
+ },
12287
+ {
12288
+ name: "expiry",
12289
+ type: "i64"
12290
+ },
12291
+ {
12292
+ name: "is_collected",
12293
+ type: "bool"
12294
+ },
12295
+ {
12296
+ name: "bump",
12297
+ type: "u8"
12298
+ }
12299
+ ]
12300
+ }
12301
+ },
11227
12302
  {
11228
12303
  name: "SignedOrderRecord",
11229
12304
  docs: [
@@ -17798,6 +18873,6 @@ function buildApproveAllOutcomeTokensTx(condition, signer, payer, delegate, prog
17798
18873
  return tx;
17799
18874
  }
17800
18875
 
17801
- export { AccountNotFoundError, AdminClient, ClobClient, CtfClient, DisputeClient, FEE_DENOMINATOR, FeeManagementClient, HookClient, IX_SYSVAR, InvalidParamError, MAX_APPROVE_AMOUNT, MarketClient, MarketOracleClient, OracleClient, PDA, PresaleClient, QuestionStatus, ReferralClient, SEEDS, UnauthorizedError, XMarketError, XMarketSDK, buildApproveAllOutcomeTokensTx, buildApproveCollateralTx, buildBatchedCollectFeeEd25519Instruction, buildBatchedEd25519Instruction, buildCreateUserAtasTx, buildOrder, buildOrderFromPrice, deserializeSignedOrder, detectMatchType, generateContentHash, generateQuestionId, getOrderSignBytes, orderAmountsFromPrice, serializeCollectFeeOrderToBytes, serializeOrderToBytes, serializeSignedOrder, signOrder, signOrderWithKeypair, verifySignedOrder };
18876
+ export { AccountNotFoundError, AdminClient, ClobClient, CtfClient, DisputeClient, FEE_DENOMINATOR, FeeManagementClient, HookClient, IX_SYSVAR, InvalidParamError, MAX_APPROVE_AMOUNT, MarketClient, MarketOracleClient, OracleClient, PDA, PresaleClient, QuestionStatus, ReferralClient, SEEDS, UnauthorizedError, XMarketError, XMarketSDK, buildApproveAllOutcomeTokensTx, buildApproveCollateralTx, buildBatchedCollectFeeEd25519Instruction, buildBatchedEd25519Instruction, buildBatchedRedeemFeeEd25519Instruction, buildCreateUserAtasTx, buildOrder, buildOrderFromPrice, deserializeSignedOrder, detectMatchType, generateContentHash, generateQuestionId, getOrderSignBytes, orderAmountsFromPrice, serializeCollectFeeOrderToBytes, serializeOrderToBytes, serializeRedeemFeeOrderToBytes, serializeSignedOrder, signOrder, signOrderWithKeypair, verifySignedOrder };
17802
18877
  //# sourceMappingURL=index.mjs.map
17803
18878
  //# sourceMappingURL=index.mjs.map