@theliem/xmarket-sdk 3.20.0 → 3.22.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, VersionedTransaction } from '@solana/web3.js';
3
+ import { PublicKey, Transaction, TransactionInstruction, Keypair, AddressLookupTableAccount, VersionedTransaction } from '@solana/web3.js';
4
4
  import BN from 'bn.js';
5
5
 
6
6
  interface ProgramIds {
@@ -281,6 +281,11 @@ declare class HookClient {
281
281
  configPda(): PublicKey;
282
282
  /** One-time setup. Caller becomes owner. */
283
283
  initialize(initialWhitelist: PublicKey[]): Promise<TxResult>;
284
+ /**
285
+ * Returns initializeExtraAccountMetaList instruction if the account doesn't exist yet, else null.
286
+ * Used by ClobClient to auto-prepend when extraAccountMetaList is missing.
287
+ */
288
+ buildInitHookIxIfNeeded(mint: PublicKey, payer: PublicKey): Promise<TransactionInstruction | null>;
284
289
  /**
285
290
  * Register extra account metas for a Token-2022 YES/NO mint.
286
291
  * Must be called once per mint after CTF creates it.
@@ -632,6 +637,8 @@ declare class ClobClient {
632
637
  /** Injected by XMarketSDK — enables auto-derive of marketOracleVault for presale markets */
633
638
  ctfClient?: CtfClient;
634
639
  qmConfigPda?: PublicKey;
640
+ /** Injected by XMarketSDK — enables auto-init extraAccountMetaList if missing */
641
+ hookClient?: HookClient;
635
642
  /** Cached company_address from fee_config to avoid repeated RPC calls */
636
643
  private _companyAddress?;
637
644
  /** Cached referral_vault from fee_config */
@@ -831,7 +838,13 @@ declare class ClobClient {
831
838
  */
832
839
  buildBatchCollectRedeemEarlyTx(signedOrders: SignedCollectFeeOrder[], condition: PublicKey, outcomeIndex: 0 | 1, operator: PublicKey, payer: PublicKey, opts?: {
833
840
  marketOracleVault?: PublicKey;
841
+ lookupTable?: AddressLookupTableAccount;
834
842
  }): Promise<VersionedTransaction>;
843
+ /**
844
+ * Build ALT with static accounts for a condition — no order-specific PDAs needed.
845
+ * Use before buildBatchCollectRedeemEarlyTx when no prior buildMatchOrdersTx ran in this session.
846
+ */
847
+ buildAltForCondition(condition: PublicKey, _payer: PublicKey, collateralMint?: PublicKey): Promise<AddressLookupTableAccount>;
835
848
  fetchConfig(): Promise<ClobConfig | null>;
836
849
  fetchOrderStatus(maker: PublicKey, nonce: anchor.BN): Promise<OrderStatus | null>;
837
850
  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, VersionedTransaction } from '@solana/web3.js';
3
+ import { PublicKey, Transaction, TransactionInstruction, Keypair, AddressLookupTableAccount, VersionedTransaction } from '@solana/web3.js';
4
4
  import BN from 'bn.js';
5
5
 
6
6
  interface ProgramIds {
@@ -281,6 +281,11 @@ declare class HookClient {
281
281
  configPda(): PublicKey;
282
282
  /** One-time setup. Caller becomes owner. */
283
283
  initialize(initialWhitelist: PublicKey[]): Promise<TxResult>;
284
+ /**
285
+ * Returns initializeExtraAccountMetaList instruction if the account doesn't exist yet, else null.
286
+ * Used by ClobClient to auto-prepend when extraAccountMetaList is missing.
287
+ */
288
+ buildInitHookIxIfNeeded(mint: PublicKey, payer: PublicKey): Promise<TransactionInstruction | null>;
284
289
  /**
285
290
  * Register extra account metas for a Token-2022 YES/NO mint.
286
291
  * Must be called once per mint after CTF creates it.
@@ -632,6 +637,8 @@ declare class ClobClient {
632
637
  /** Injected by XMarketSDK — enables auto-derive of marketOracleVault for presale markets */
633
638
  ctfClient?: CtfClient;
634
639
  qmConfigPda?: PublicKey;
640
+ /** Injected by XMarketSDK — enables auto-init extraAccountMetaList if missing */
641
+ hookClient?: HookClient;
635
642
  /** Cached company_address from fee_config to avoid repeated RPC calls */
636
643
  private _companyAddress?;
637
644
  /** Cached referral_vault from fee_config */
@@ -831,7 +838,13 @@ declare class ClobClient {
831
838
  */
832
839
  buildBatchCollectRedeemEarlyTx(signedOrders: SignedCollectFeeOrder[], condition: PublicKey, outcomeIndex: 0 | 1, operator: PublicKey, payer: PublicKey, opts?: {
833
840
  marketOracleVault?: PublicKey;
841
+ lookupTable?: AddressLookupTableAccount;
834
842
  }): Promise<VersionedTransaction>;
843
+ /**
844
+ * Build ALT with static accounts for a condition — no order-specific PDAs needed.
845
+ * Use before buildBatchCollectRedeemEarlyTx when no prior buildMatchOrdersTx ran in this session.
846
+ */
847
+ buildAltForCondition(condition: PublicKey, _payer: PublicKey, collateralMint?: PublicKey): Promise<AddressLookupTableAccount>;
835
848
  fetchConfig(): Promise<ClobConfig | null>;
836
849
  fetchOrderStatus(maker: PublicKey, nonce: anchor.BN): Promise<OrderStatus | null>;
837
850
  fetchOrderRecord(maker: PublicKey, nonce: anchor.BN): Promise<{
package/dist/index.js CHANGED
@@ -380,7 +380,7 @@ var OracleClient = class {
380
380
  owner: acc.owner,
381
381
  admin: acc.admin,
382
382
  questionCount: acc.questionCount.toNumber(),
383
- whitelist: acc.whitelist,
383
+ whitelist: acc.whitelist.slice(0, acc.whitelistLen),
384
384
  whitelistLen: acc.whitelistLen,
385
385
  isPaused: acc.isPaused,
386
386
  bump: acc.bump
@@ -433,6 +433,23 @@ var HookClient = class {
433
433
  }).rpc();
434
434
  return { signature: sig };
435
435
  }
436
+ /**
437
+ * Returns initializeExtraAccountMetaList instruction if the account doesn't exist yet, else null.
438
+ * Used by ClobClient to auto-prepend when extraAccountMetaList is missing.
439
+ */
440
+ async buildInitHookIxIfNeeded(mint, payer) {
441
+ const [extraAccountMetaList] = PDA.extraAccountMetaList(mint, this.programIds);
442
+ const existing = await this.provider.connection.getAccountInfo(extraAccountMetaList);
443
+ if (existing) return null;
444
+ return this.program.methods.initializeExtraAccountMetaList().accounts({
445
+ payer,
446
+ extraAccountMetaList,
447
+ mint,
448
+ hookConfig: this.configPda(),
449
+ tokenProgram: splToken.TOKEN_2022_PROGRAM_ID,
450
+ systemProgram: web3_js.SystemProgram.programId
451
+ }).instruction();
452
+ }
436
453
  /**
437
454
  * Register extra account metas for a Token-2022 YES/NO mint.
438
455
  * Must be called once per mint after CTF creates it.
@@ -507,7 +524,7 @@ var HookClient = class {
507
524
  const acc = await this.program.account.hookConfig.fetch(this.configPda());
508
525
  return {
509
526
  owner: acc.owner,
510
- whitelist: acc.whitelist,
527
+ whitelist: acc.whitelist.slice(0, acc.whitelistLen),
511
528
  whitelistLen: acc.whitelistLen,
512
529
  isFrozen: acc.isFrozen,
513
530
  bump: acc.bump
@@ -710,7 +727,7 @@ var MarketClient = class {
710
727
  approvedCount: acc.approvedCount.toNumber(),
711
728
  rejectedCount: acc.rejectedCount.toNumber(),
712
729
  presaleCount: acc.presaleCount.toNumber(),
713
- whitelist: acc.whitelist,
730
+ whitelist: acc.whitelist.slice(0, acc.whitelistLen),
714
731
  whitelistLen: acc.whitelistLen,
715
732
  isPaused: acc.isPaused,
716
733
  bump: acc.bump
@@ -2431,6 +2448,18 @@ ${logs.join("\n")}`);
2431
2448
  const m0 = makers[0].order;
2432
2449
  const SIDE_BUY = 0;
2433
2450
  const SIDE_SELL = 1;
2451
+ const hookInitIxs = [];
2452
+ if (this.hookClient) {
2453
+ const condition0 = t.condition;
2454
+ const [ym] = PDA.yesMint(condition0, this.programIds);
2455
+ const [nm] = PDA.noMint(condition0, this.programIds);
2456
+ const [yIx, nIx] = await Promise.all([
2457
+ this.hookClient.buildInitHookIxIfNeeded(ym, payer),
2458
+ this.hookClient.buildInitHookIxIfNeeded(nm, payer)
2459
+ ]);
2460
+ if (yIx) hookInitIxs.push(yIx);
2461
+ if (nIx) hookInitIxs.push(nIx);
2462
+ }
2434
2463
  if (t.tokenId === m0.tokenId) {
2435
2464
  let buySignedOrder, sellCandidates;
2436
2465
  if (t.side === SIDE_BUY && makers.every((m) => m.order.side === SIDE_SELL)) {
@@ -2450,7 +2479,7 @@ ${logs.join("\n")}`);
2450
2479
  opts,
2451
2480
  false
2452
2481
  );
2453
- return this._buildUnsignedVtx(ixs3, alt, payer);
2482
+ return this._buildUnsignedVtx([...hookInitIxs, ...ixs3], alt, payer);
2454
2483
  } else {
2455
2484
  throw new InvalidParamError("COMPLEMENTARY requires one BUY and one or more SELLs on same tokenId");
2456
2485
  }
@@ -2466,7 +2495,7 @@ ${logs.join("\n")}`);
2466
2495
  operator,
2467
2496
  opts
2468
2497
  );
2469
- return this._buildUnsignedVtx(ixs2, alt, payer);
2498
+ return this._buildUnsignedVtx([...hookInitIxs, ...ixs2], alt, payer);
2470
2499
  }
2471
2500
  const allBuy = t.side === SIDE_BUY && makers.every((m) => m.order.side === SIDE_BUY);
2472
2501
  const allSell = t.side === SIDE_SELL && makers.every((m) => m.order.side === SIDE_SELL);
@@ -2487,7 +2516,7 @@ ${logs.join("\n")}`);
2487
2516
  ]);
2488
2517
  await this._ensureClobOutcomeAtas(yesMint, noMint, clobConfig, clobYesAta, clobNoAta);
2489
2518
  const ix = allBuy ? await this._buildMintIx(taker, makers, collateralMint, operator, payer) : await this._buildMergeIx(taker, makers, collateralMint, operator, payer, opts);
2490
- return this._buildUnsignedVtx([ix], alt, payer);
2519
+ return this._buildUnsignedVtx([...hookInitIxs, ix], alt, payer);
2491
2520
  }
2492
2521
  await Promise.all([
2493
2522
  this.registerOrderIfNeeded(taker),
@@ -2499,7 +2528,7 @@ ${logs.join("\n")}`);
2499
2528
  const ix = allBuy ? await this._buildMintIx(yesMaker, [taker], collateralMint, operator, payer) : await this._buildMergeIx(yesMaker, [taker], collateralMint, operator, payer, opts);
2500
2529
  ixs.push(ix);
2501
2530
  }
2502
- return this._buildUnsignedVtx(ixs, alt, payer);
2531
+ return this._buildUnsignedVtx([...hookInitIxs, ...ixs], alt, payer);
2503
2532
  }
2504
2533
  // ─── batchCollectRedeemEarly ─────────────────────────────────────────────────
2505
2534
  /**
@@ -2569,10 +2598,16 @@ ${logs.join("\n")}`);
2569
2598
  }
2570
2599
  }
2571
2600
  await this._ensureClobOutcomeAtas(yesMint, noMint, clobConfig, clobYesAta, clobNoAta);
2601
+ const hookInitIxs = [];
2602
+ if (this.hookClient) {
2603
+ const ix = await this.hookClient.buildInitHookIxIfNeeded(outcomeMint, payer);
2604
+ if (ix) hookInitIxs.push(ix);
2605
+ }
2572
2606
  const ed25519Ix = buildBatchedCollectFeeEd25519Instruction(signedOrders);
2607
+ const ed25519IxIndex = 2 + hookInitIxs.length;
2573
2608
  const collectIx = await this.program.methods.batchCollectRedeemEarly(
2574
- 2,
2575
- // ix_index: Ed25519 ix is ix[2] (cuLimit=0, heapFrame=1, ed25519=2)
2609
+ ed25519IxIndex,
2610
+ // ix_index: adjusted for any prepended hook init ixs
2576
2611
  signedOrders.length,
2577
2612
  outcomeIndex
2578
2613
  ).accounts({
@@ -2595,8 +2630,83 @@ ${logs.join("\n")}`);
2595
2630
  token2022Program: splToken.TOKEN_2022_PROGRAM_ID,
2596
2631
  systemProgram: web3_js.SystemProgram.programId
2597
2632
  }).remainingAccounts([...userAccounts, ...hookAccounts, ...feeAccounts]).instruction();
2598
- const cachedAlt = this._altCache.get(condition.toBase58());
2599
- return this._buildUnsignedVtx([ed25519Ix, collectIx], cachedAlt, payer);
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);
2635
+ }
2636
+ /**
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.
2639
+ */
2640
+ async buildAltForCondition(condition, _payer, collateralMint) {
2641
+ const cacheKey = condition.toBase58();
2642
+ if (this._altCache.has(cacheKey)) return this._altCache.get(cacheKey);
2643
+ const mint = collateralMint ?? this.networkConfig.defaultCollateral.mint;
2644
+ const payer = this.walletPubkey;
2645
+ const { connection } = this.provider;
2646
+ const clobConfigPda = this.configPda();
2647
+ const [yesMint] = PDA.yesMint(condition, this.programIds);
2648
+ const [noMint] = PDA.noMint(condition, this.programIds);
2649
+ const [extraAccountMeta] = PDA.extraAccountMetaList(yesMint, this.programIds);
2650
+ const [hookConfig] = PDA.hookConfig(this.programIds);
2651
+ const [collateralVault] = PDA.collateralVault(mint, this.programIds);
2652
+ const [vaultTokenAccount] = PDA.vaultToken(mint, this.programIds);
2653
+ const clobYesAta = splToken.getAssociatedTokenAddressSync(yesMint, clobConfigPda, true, splToken.TOKEN_2022_PROGRAM_ID);
2654
+ const clobNoAta = splToken.getAssociatedTokenAddressSync(noMint, clobConfigPda, true, splToken.TOKEN_2022_PROGRAM_ID);
2655
+ const feeRecipientAddr = (await this.fetchConfig())?.feeRecipient;
2656
+ const addresses = [
2657
+ web3_js.Ed25519Program.programId,
2658
+ this.programIds.clobExchange,
2659
+ this.programIds.conditionalTokens,
2660
+ this.programIds.hook,
2661
+ splToken.TOKEN_PROGRAM_ID,
2662
+ splToken.TOKEN_2022_PROGRAM_ID,
2663
+ web3_js.SystemProgram.programId,
2664
+ web3_js.SYSVAR_INSTRUCTIONS_PUBKEY,
2665
+ clobConfigPda,
2666
+ hookConfig,
2667
+ condition,
2668
+ yesMint,
2669
+ noMint,
2670
+ extraAccountMeta,
2671
+ collateralVault,
2672
+ vaultTokenAccount,
2673
+ clobYesAta,
2674
+ clobNoAta
2675
+ ];
2676
+ if (feeRecipientAddr) addresses.push(feeRecipientAddr);
2677
+ if (this.feeConfigOwner && this.programIds.feeManagement) {
2678
+ const companyAddr = await this.companyAddress();
2679
+ const refVault = await this.referralVault();
2680
+ addresses.push(this.programIds.feeManagement);
2681
+ addresses.push(PDA.feeConfig(this.feeConfigOwner, this.programIds)[0]);
2682
+ addresses.push(PDA.marketFeeOverride(condition, this.programIds)[0]);
2683
+ if (companyAddr) addresses.push(splToken.getAssociatedTokenAddressSync(mint, companyAddr));
2684
+ if (refVault) addresses.push(refVault);
2685
+ const oracleVault = await this.getMarketOracleVault(condition, mint) ?? payer;
2686
+ addresses.push(oracleVault);
2687
+ }
2688
+ const slot = await connection.getSlot("finalized");
2689
+ const [createIx, altAddress] = web3_js.AddressLookupTableProgram.createLookupTable(
2690
+ { authority: payer, payer, recentSlot: slot }
2691
+ );
2692
+ const BATCH = 30;
2693
+ const extendIxs = [];
2694
+ for (let i = 0; i < addresses.length; i += BATCH) {
2695
+ extendIxs.push(web3_js.AddressLookupTableProgram.extendLookupTable(
2696
+ { payer, authority: payer, lookupTable: altAddress, addresses: addresses.slice(i, i + BATCH) }
2697
+ ));
2698
+ }
2699
+ await this._sendLegacyTx([createIx, extendIxs[0]]);
2700
+ for (let i = 1; i < extendIxs.length; i++) await this._sendLegacyTx([extendIxs[i]]);
2701
+ for (let attempt = 0; attempt < 30; attempt++) {
2702
+ await new Promise((r) => setTimeout(r, 1e3));
2703
+ const res = await connection.getAddressLookupTable(altAddress);
2704
+ if (res.value && res.value.state.addresses.length === addresses.length) {
2705
+ this._altCache.set(cacheKey, res.value);
2706
+ return res.value;
2707
+ }
2708
+ }
2709
+ throw new Error(`ALT ${altAddress.toBase58()} not active after 30s`);
2600
2710
  }
2601
2711
  // ─── Queries ─────────────────────────────────────────────────────────────────
2602
2712
  async fetchConfig() {
@@ -16412,6 +16522,7 @@ var XMarketSDK = class {
16412
16522
  }
16413
16523
  this._clob.ctfClient = this.ctf;
16414
16524
  this._clob.qmConfigPda = this.market.configPda;
16525
+ this._clob.hookClient = this.hook;
16415
16526
  }
16416
16527
  return this._clob;
16417
16528
  }