@theliem/xmarket-sdk 3.0.1 → 3.1.1

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
@@ -1,12 +1,15 @@
1
1
  import * as anchor4 from '@coral-xyz/anchor';
2
- import { SYSVAR_INSTRUCTIONS_PUBKEY, PublicKey, SystemProgram, SYSVAR_RENT_PUBKEY, TransactionInstruction, Ed25519Program, TransactionMessage, VersionedTransaction, Connection, Transaction } from '@solana/web3.js';
2
+ import { PublicKey, SYSVAR_INSTRUCTIONS_PUBKEY, SystemProgram, SYSVAR_RENT_PUBKEY, TransactionInstruction, Ed25519Program, AddressLookupTableProgram, TransactionMessage, VersionedTransaction, Connection, Transaction } from '@solana/web3.js';
3
3
  import { createHash } from 'crypto';
4
- import { TOKEN_2022_PROGRAM_ID, TOKEN_PROGRAM_ID, getAssociatedTokenAddressSync, ASSOCIATED_TOKEN_PROGRAM_ID, createApproveInstruction } from '@solana/spl-token';
5
- import oracleIdl from './oracle-FZJJIJGI.json';
4
+ import { TOKEN_2022_PROGRAM_ID, getAssociatedTokenAddressSync, ASSOCIATED_TOKEN_PROGRAM_ID, TOKEN_PROGRAM_ID, createApproveInstruction } from '@solana/spl-token';
5
+ import oracleIdl from './oracle-O53KMXDK.json';
6
6
  import hookIdl from './hook-THBRGUM6.json';
7
- import questionMarketIdl from './question_market-CB6ZUZ5E.json';
7
+ import questionMarketIdl from './question_market-RP3J3N2M.json';
8
8
  import conditionalTokensIdl from './conditional_tokens-3O5V46N5.json';
9
9
  import clobExchangeIdl from './clob_exchange-MQF4NI27.json';
10
+ import feeManagementIdl from './fee_management-VGF77YXG.json';
11
+ import presaleIdl from './presale-Q4NDVQFN.json';
12
+ import marketOracleIdl from './market_oracle-E6UUARGR.json';
10
13
  import BN4 from 'bn.js';
11
14
  import * as nacl from 'tweetnacl';
12
15
 
@@ -27,7 +30,18 @@ var SEEDS = {
27
30
  hookConfig: Buffer.from("hook_config"),
28
31
  extraAccountMetas: Buffer.from("extra-account-metas"),
29
32
  clobConfig: Buffer.from("clob_config"),
30
- order: Buffer.from("order")
33
+ order: Buffer.from("order"),
34
+ feeConfig: Buffer.from("fee_config"),
35
+ questionFee: Buffer.from("question_fee"),
36
+ marketFee: Buffer.from("market_fee"),
37
+ // Presale
38
+ presale: Buffer.from("presale"),
39
+ qtMint: Buffer.from("qt_mint"),
40
+ qtAuthority: Buffer.from("qt_authority"),
41
+ userBuy: Buffer.from("user_buy"),
42
+ // Market Oracle
43
+ marketOracle: Buffer.from("market_oracle"),
44
+ userClaim: Buffer.from("user_claim")
31
45
  };
32
46
  var PDA = class {
33
47
  // ─── Question Market ────────────────────────────────────────────────────────
@@ -139,6 +153,74 @@ var PDA = class {
139
153
  programIds.clobExchange
140
154
  );
141
155
  }
156
+ // ─── Fee Management ─────────────────────────────────────────────────────────
157
+ static feeConfig(owner, programIds) {
158
+ if (!programIds.feeManagement) throw new Error("feeManagement program ID not configured");
159
+ return PublicKey.findProgramAddressSync(
160
+ [SEEDS.feeConfig, owner.toBuffer()],
161
+ programIds.feeManagement
162
+ );
163
+ }
164
+ static questionFee(conditionPda, programIds) {
165
+ if (!programIds.feeManagement) throw new Error("feeManagement program ID not configured");
166
+ return PublicKey.findProgramAddressSync(
167
+ [SEEDS.questionFee, conditionPda.toBuffer()],
168
+ programIds.feeManagement
169
+ );
170
+ }
171
+ static marketFeeOverride(conditionPda, programIds) {
172
+ if (!programIds.feeManagement) throw new Error("feeManagement program ID not configured");
173
+ return PublicKey.findProgramAddressSync(
174
+ [SEEDS.marketFee, conditionPda.toBuffer()],
175
+ programIds.feeManagement
176
+ );
177
+ }
178
+ // ─── Presale ─────────────────────────────────────────────────────────────────
179
+ static presale(questionMarketConfig, presaleIndex, programIds) {
180
+ if (!programIds.presale) throw new Error("presale program ID not configured");
181
+ const idxBuf = Buffer.alloc(8);
182
+ idxBuf.writeBigUInt64LE(BigInt(presaleIndex.toString()));
183
+ return PublicKey.findProgramAddressSync(
184
+ [SEEDS.presale, questionMarketConfig.toBuffer(), idxBuf],
185
+ programIds.presale
186
+ );
187
+ }
188
+ static qtMint(presalePda, programIds) {
189
+ if (!programIds.presale) throw new Error("presale program ID not configured");
190
+ return PublicKey.findProgramAddressSync(
191
+ [SEEDS.qtMint, presalePda.toBuffer()],
192
+ programIds.presale
193
+ );
194
+ }
195
+ static qtAuthority(presalePda, programIds) {
196
+ if (!programIds.presale) throw new Error("presale program ID not configured");
197
+ return PublicKey.findProgramAddressSync(
198
+ [SEEDS.qtAuthority, presalePda.toBuffer()],
199
+ programIds.presale
200
+ );
201
+ }
202
+ static userBuyRecord(presalePda, user, programIds) {
203
+ if (!programIds.presale) throw new Error("presale program ID not configured");
204
+ return PublicKey.findProgramAddressSync(
205
+ [SEEDS.userBuy, presalePda.toBuffer(), user.toBuffer()],
206
+ programIds.presale
207
+ );
208
+ }
209
+ // ─── Market Oracle ────────────────────────────────────────────────────────────
210
+ static marketOraclePda(questionPda, programIds) {
211
+ if (!programIds.marketOracle) throw new Error("marketOracle program ID not configured");
212
+ return PublicKey.findProgramAddressSync(
213
+ [SEEDS.marketOracle, questionPda.toBuffer()],
214
+ programIds.marketOracle
215
+ );
216
+ }
217
+ static userClaimRecord(marketOraclePda, user, programIds) {
218
+ if (!programIds.marketOracle) throw new Error("marketOracle program ID not configured");
219
+ return PublicKey.findProgramAddressSync(
220
+ [SEEDS.userClaim, marketOraclePda.toBuffer(), user.toBuffer()],
221
+ programIds.marketOracle
222
+ );
223
+ }
142
224
  };
143
225
  function generateQuestionId(content, salt) {
144
226
  const input = content + (salt ?? Date.now());
@@ -171,7 +253,7 @@ var OracleClient = class {
171
253
  }).rpc();
172
254
  return { signature: sig };
173
255
  }
174
- /** Admin or owner adds an address to the oracle whitelist. */
256
+ /** Admin or owner adds an address to the oracle resolver whitelist. */
175
257
  async addToWhitelist(address, ownerPubkey) {
176
258
  const sig = await this.program.methods.addToWhitelist(address).accounts({
177
259
  authority: this.walletPubkey,
@@ -180,7 +262,7 @@ var OracleClient = class {
180
262
  }).rpc();
181
263
  return { signature: sig };
182
264
  }
183
- /** Admin or owner removes an address from the oracle whitelist. */
265
+ /** Admin or owner removes an address from the oracle resolver whitelist. */
184
266
  async removeFromWhitelist(address, ownerPubkey) {
185
267
  const sig = await this.program.methods.removeFromWhitelist(address).accounts({
186
268
  authority: this.walletPubkey,
@@ -218,6 +300,7 @@ var OracleClient = class {
218
300
  async updateAdmin(newAdmin, ownerPubkey) {
219
301
  const sig = await this.program.methods.updateAdmin(newAdmin).accounts({
220
302
  owner: this.walletPubkey,
303
+ payer: this.walletPubkey,
221
304
  oracleConfig: this.configPda(ownerPubkey)
222
305
  }).rpc();
223
306
  return { signature: sig };
@@ -399,6 +482,7 @@ var QuestionStatus = /* @__PURE__ */ ((QuestionStatus2) => {
399
482
  QuestionStatus2["Resolved"] = "resolved";
400
483
  return QuestionStatus2;
401
484
  })(QuestionStatus || {});
485
+ var FEE_DENOMINATOR = 1e6;
402
486
  var XMarketError = class extends Error {
403
487
  constructor(message, code) {
404
488
  super(message);
@@ -426,6 +510,7 @@ var InvalidParamError = class extends XMarketError {
426
510
  };
427
511
 
428
512
  // src/programs/market.ts
513
+ var TOKEN_METADATA_PROGRAM_ID = new PublicKey("metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s");
429
514
  var MarketClient = class {
430
515
  constructor(program, provider, programIds, ownerPubkey) {
431
516
  this.program = program;
@@ -448,51 +533,12 @@ var MarketClient = class {
448
533
  systemProgram: SystemProgram.programId
449
534
  }).transaction();
450
535
  }
451
- /**
452
- * Build createQuestion transaction.
453
- * @param payer - Pays rent for all new accounts (can differ from creator)
454
- * @param creator - Identity of the question creator (signs but does not pay)
455
- */
456
- async createQuestion(params, oracle, creator = this.walletPubkey, payer = creator) {
457
- const questionId = params.questionId ?? generateQuestionId(params.content);
458
- const contentHash = params.contentHash ?? generateContentHash(params.content);
459
- const [questionPda] = PDA.question(this.configPda, questionId, this.programIds);
460
- const [conditionPda] = PDA.condition(oracle, questionId, this.programIds);
461
- const [yesMint] = PDA.yesMint(conditionPda, this.programIds);
462
- const [noMint] = PDA.noMint(conditionPda, this.programIds);
463
- const [mintAuthority] = PDA.mintAuthority(conditionPda, this.programIds);
464
- const [collateralVault] = PDA.collateralVault(params.collateralMint, this.programIds);
465
- const tx = await this.program.methods.createQuestionWithCondition({
466
- questionId: Array.from(questionId),
467
- contentHash: Array.from(contentHash),
468
- hookProgram: params.hookProgram,
469
- authorizedClob: params.authorizedClob,
470
- expirationTime: new anchor4.BN(params.expirationTime)
471
- }).accounts({
472
- payer,
473
- creator,
474
- config: this.configPda,
475
- question: questionPda,
476
- currencyMint: params.collateralMint,
477
- oracle,
478
- condition: conditionPda,
479
- yesMint,
480
- noMint,
481
- mintAuthority,
482
- collateralVault,
483
- conditionalTokensProgram: this.programIds.conditionalTokens,
484
- tokenProgram: TOKEN_2022_PROGRAM_ID,
485
- systemProgram: SystemProgram.programId,
486
- rent: SYSVAR_RENT_PUBKEY
487
- }).transaction();
488
- return { tx, questionPda, conditionPda, questionId };
489
- }
490
536
  /**
491
537
  * Build createQuestionAdmin transaction (whitelist/admin path — status = Approved immediately).
492
538
  * @param creator - Whitelisted creator (must be in whitelist or be admin/owner)
493
539
  * @param payer - Fee payer (pays rent; can differ from creator)
494
540
  */
495
- async createQuestionAdmin(params, oracle, creator = this.walletPubkey, payer = creator) {
541
+ async createQuestionAdmin(params, oracle, creator = this.walletPubkey, payer = this.walletPubkey) {
496
542
  const questionId = params.questionId ?? generateQuestionId(params.content);
497
543
  const contentHash = params.contentHash ?? generateContentHash(params.content);
498
544
  const [questionPda] = PDA.question(this.configPda, questionId, this.programIds);
@@ -586,6 +632,7 @@ var MarketClient = class {
586
632
  questionCount: acc.questionCount.toNumber(),
587
633
  approvedCount: acc.approvedCount.toNumber(),
588
634
  rejectedCount: acc.rejectedCount.toNumber(),
635
+ presaleCount: acc.presaleCount.toNumber(),
589
636
  whitelist: acc.whitelist,
590
637
  whitelistLen: acc.whitelistLen,
591
638
  isPaused: acc.isPaused,
@@ -637,6 +684,163 @@ var MarketClient = class {
637
684
  if (!q || !q.condition) return { yes: null, no: null };
638
685
  return this.ctfClient.fetchBothPositions(q.condition, owner);
639
686
  }
687
+ // ─── Presale instructions ────────────────────────────────────────────────────
688
+ /**
689
+ * Any user creates a presale + initial buy (question-market::create_presale).
690
+ * Reads agents_rev / company_rev from fee_config.
691
+ *
692
+ * @param feeConfig fee_management fee_config PDA (owner = feeConfigOwner)
693
+ * @param currencyMint collateral token (e.g. USDC)
694
+ * @param presaleIndex config.presale_count — fetch config first or pass 0 for first presale
695
+ */
696
+ async createPresale(params, feeConfig, currencyMint, presaleIndex, creator = this.walletPubkey, payer = creator) {
697
+ if (!this.programIds.presale) throw new Error("presale program ID not configured");
698
+ const [presalePda] = PDA.presale(this.configPda, presaleIndex, this.programIds);
699
+ const [qtMint] = PDA.qtMint(presalePda, this.programIds);
700
+ const [qtAuthority] = PDA.qtAuthority(presalePda, this.programIds);
701
+ const [userBuyRecord] = PDA.userBuyRecord(presalePda, creator, this.programIds);
702
+ const presaleVault = getAssociatedTokenAddressSync(currencyMint, presalePda, true);
703
+ const creatorQtAta = getAssociatedTokenAddressSync(qtMint, creator);
704
+ const creatorCurrencyAta = getAssociatedTokenAddressSync(currencyMint, creator);
705
+ const [qtMetadata] = PublicKey.findProgramAddressSync(
706
+ [Buffer.from("metadata"), TOKEN_METADATA_PROGRAM_ID.toBuffer(), qtMint.toBuffer()],
707
+ TOKEN_METADATA_PROGRAM_ID
708
+ );
709
+ const tx = await this.program.methods.createPresale({
710
+ price: params.price,
711
+ startTime: params.startTime,
712
+ endTime: params.endTime,
713
+ initialBuyAmount: params.initialBuyAmount
714
+ }).accounts({
715
+ creator,
716
+ payer,
717
+ config: this.configPda,
718
+ feeConfig,
719
+ presale: presalePda,
720
+ qtMint,
721
+ qtAuthority,
722
+ currencyMint,
723
+ presaleVault,
724
+ creatorCurrencyAta,
725
+ creatorQtAta,
726
+ userBuyRecord,
727
+ qtMetadata,
728
+ tokenMetadataProgram: TOKEN_METADATA_PROGRAM_ID,
729
+ presaleProgram: this.programIds.presale,
730
+ tokenProgram: TOKEN_PROGRAM_ID,
731
+ associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID,
732
+ systemProgram: SystemProgram.programId,
733
+ rent: SYSVAR_RENT_PUBKEY
734
+ }).transaction();
735
+ return { tx, presalePda, qtMint };
736
+ }
737
+ /**
738
+ * Whitelist-only: approve presale → creates question + CTF condition + market_oracle in one tx.
739
+ *
740
+ * @param presalePda the presale account
741
+ * @param contentHash 32-byte hash for question content
742
+ * @param hookProgram token-2022 transfer hook program
743
+ * @param authorizedClob clob program allowed to do CTF transfers
744
+ * @param expirationTime Unix seconds
745
+ * @param creator presale creator pubkey (stored in question)
746
+ * @param currencyMint collateral mint
747
+ */
748
+ async approvePresale(presalePda, contentHash, hookProgram, authorizedClob, expirationTime, creator, currencyMint, caller = this.walletPubkey, payer = caller) {
749
+ if (!this.programIds.presale) throw new Error("presale program ID not configured");
750
+ if (!this.programIds.marketOracle) throw new Error("marketOracle program ID not configured");
751
+ const questionId = presalePda.toBytes();
752
+ const [questionPda] = PDA.question(this.configPda, questionId, this.programIds);
753
+ const marketConfig = await this.fetchConfig();
754
+ if (!marketConfig) throw new Error("QuestionMarketConfig not found");
755
+ const oraclePubkey = marketConfig.oracle;
756
+ const [conditionPda] = PDA.condition(oraclePubkey, questionId, this.programIds);
757
+ const [yesMint] = PDA.yesMint(conditionPda, this.programIds);
758
+ const [noMint] = PDA.noMint(conditionPda, this.programIds);
759
+ const [mintAuthority] = PDA.mintAuthority(conditionPda, this.programIds);
760
+ const [collateralVault] = PDA.collateralVault(currencyMint, this.programIds);
761
+ const [marketOraclePda] = PDA.marketOraclePda(questionPda, this.programIds);
762
+ const marketOracleVault = getAssociatedTokenAddressSync(currencyMint, marketOraclePda, true);
763
+ const tx = await this.program.methods.approvePresale({
764
+ contentHash: Array.from(contentHash),
765
+ hookProgram,
766
+ authorizedClob,
767
+ expirationTime,
768
+ creator
769
+ }).accounts({
770
+ caller,
771
+ payer,
772
+ config: this.configPda,
773
+ presale: presalePda,
774
+ question: questionPda,
775
+ currencyMint,
776
+ oracle: oraclePubkey,
777
+ condition: conditionPda,
778
+ yesMint,
779
+ noMint,
780
+ mintAuthority,
781
+ collateralVault,
782
+ marketOracle: marketOraclePda,
783
+ marketOracleVault,
784
+ conditionalTokensProgram: this.programIds.conditionalTokens,
785
+ presaleProgram: this.programIds.presale,
786
+ marketOracleProgram: this.programIds.marketOracle,
787
+ tokenProgram: TOKEN_PROGRAM_ID,
788
+ token2022Program: TOKEN_2022_PROGRAM_ID,
789
+ associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID,
790
+ systemProgram: SystemProgram.programId,
791
+ rent: SYSVAR_RENT_PUBKEY
792
+ }).transaction();
793
+ return { tx, questionPda, conditionPda, marketOraclePda, marketOracleVault };
794
+ }
795
+ /**
796
+ * Whitelist-only: reject presale so users can refund.
797
+ */
798
+ async rejectPresale(presalePda, caller = this.walletPubkey) {
799
+ if (!this.programIds.presale) throw new Error("presale program ID not configured");
800
+ return this.program.methods.rejectPresale().accounts({
801
+ caller,
802
+ config: this.configPda,
803
+ presale: presalePda,
804
+ presaleProgram: this.programIds.presale
805
+ }).transaction();
806
+ }
807
+ /**
808
+ * Whitelist-only: distribute presale vault funds → agents_rev% + company_rev% + rest to creator.
809
+ * Must be called after approvePresale.
810
+ */
811
+ async collectPresaleRevenue(presalePda, currencyMint, referralAddress, companyAddress, caller = this.walletPubkey) {
812
+ if (!this.programIds.presale) throw new Error("presale program ID not configured");
813
+ const presaleVault = getAssociatedTokenAddressSync(currencyMint, presalePda, true);
814
+ const referralTokenAccount = getAssociatedTokenAddressSync(currencyMint, referralAddress);
815
+ const companyTokenAccount = getAssociatedTokenAddressSync(currencyMint, companyAddress);
816
+ return this.program.methods.collectPresaleRevenue().accounts({
817
+ caller,
818
+ config: this.configPda,
819
+ presale: presalePda,
820
+ presaleVault,
821
+ currencyMint,
822
+ referralTokenAccount,
823
+ companyTokenAccount,
824
+ presaleProgram: this.programIds.presale,
825
+ tokenProgram: TOKEN_PROGRAM_ID,
826
+ associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID,
827
+ systemProgram: SystemProgram.programId
828
+ }).transaction();
829
+ }
830
+ /**
831
+ * Whitelist-only: snapshot MST supply so holders can claim trading fees.
832
+ * Call after oracle resolves the question.
833
+ */
834
+ async collectTradingFee(marketOraclePda, qtMint, caller = this.walletPubkey) {
835
+ if (!this.programIds.marketOracle) throw new Error("marketOracle program ID not configured");
836
+ return this.program.methods.collectTradingFee().accounts({
837
+ caller,
838
+ config: this.configPda,
839
+ marketOracle: marketOraclePda,
840
+ qtMint,
841
+ marketOracleProgram: this.programIds.marketOracle
842
+ }).transaction();
843
+ }
640
844
  };
641
845
  var CtfClient = class {
642
846
  constructor(program, provider, programIds) {
@@ -1046,14 +1250,138 @@ var IX_SYSVAR = SYSVAR_INSTRUCTIONS_PUBKEY;
1046
1250
  // src/programs/clob.ts
1047
1251
  var CLOB_WHITELIST_SEED = Buffer.from("clob_whitelist");
1048
1252
  var ClobClient = class {
1049
- constructor(program, provider, programIds) {
1253
+ constructor(program, provider, programIds, networkConfig) {
1254
+ /** ALT cache: condition.toBase58() → loaded ALT account */
1255
+ this._altCache = /* @__PURE__ */ new Map();
1050
1256
  this.program = program;
1051
1257
  this.provider = provider;
1052
1258
  this.programIds = programIds;
1259
+ this.networkConfig = networkConfig;
1260
+ }
1261
+ async companyAddress() {
1262
+ if (!this.feeClient || !this.feeConfigOwner) return void 0;
1263
+ if (!this._companyAddress) {
1264
+ const cfg = await this.feeClient.fetchFeeConfig(this.feeConfigOwner);
1265
+ if (cfg) this._companyAddress = cfg.companyAddress;
1266
+ }
1267
+ return this._companyAddress;
1053
1268
  }
1054
1269
  get walletPubkey() {
1055
1270
  return this.provider.wallet.publicKey;
1056
1271
  }
1272
+ /**
1273
+ * Get or create an ALT for a condition.
1274
+ * First call: creates + extends ALT on-chain, waits for activation (~2s).
1275
+ * Subsequent calls for same condition: returns cached ALT instantly.
1276
+ * BE devs never interact with this — called automatically by matchOrders.
1277
+ */
1278
+ async ensureAlt(condition, collateralMint, buyerPubkey, buyerNonce, makers) {
1279
+ const cacheKey = condition.toBase58();
1280
+ if (this._altCache.has(cacheKey)) {
1281
+ return this._altCache.get(cacheKey);
1282
+ }
1283
+ const { connection } = this.provider;
1284
+ const payer = this.walletPubkey;
1285
+ const [yesMint] = PDA.yesMint(condition, this.programIds);
1286
+ const [extraAccountMeta] = PDA.extraAccountMetaList(yesMint, this.programIds);
1287
+ const [hookConfig] = PDA.hookConfig(this.programIds);
1288
+ const [buyOrderStatus] = PDA.orderStatus(buyerPubkey, buyerNonce, this.programIds);
1289
+ const [buyerPosition] = PDA.position(condition, 1, buyerPubkey, this.programIds);
1290
+ const clobConfigPda = this.configPda();
1291
+ const feeRecipientAddr = (await this.fetchConfig())?.feeRecipient;
1292
+ const addresses = [
1293
+ // instruction program IDs — must be in ALT to keep static keys minimal
1294
+ Ed25519Program.programId,
1295
+ this.programIds.clobExchange,
1296
+ // other programs
1297
+ this.programIds.conditionalTokens,
1298
+ this.programIds.hook,
1299
+ TOKEN_PROGRAM_ID,
1300
+ TOKEN_2022_PROGRAM_ID,
1301
+ SystemProgram.programId,
1302
+ SYSVAR_INSTRUCTIONS_PUBKEY,
1303
+ // config PDAs
1304
+ clobConfigPda,
1305
+ hookConfig,
1306
+ this.whitelistEntryPda(payer),
1307
+ // condition PDAs
1308
+ condition,
1309
+ yesMint,
1310
+ extraAccountMeta,
1311
+ // buyer pubkey + ATAs + PDAs
1312
+ buyerPubkey,
1313
+ getAssociatedTokenAddressSync(collateralMint, buyerPubkey),
1314
+ getAssociatedTokenAddressSync(yesMint, buyerPubkey, false, TOKEN_2022_PROGRAM_ID),
1315
+ buyerPosition,
1316
+ buyOrderStatus
1317
+ ];
1318
+ if (feeRecipientAddr) addresses.push(feeRecipientAddr);
1319
+ for (const m of makers) {
1320
+ const seller = m.order.maker;
1321
+ const [sellerPos] = PDA.position(condition, 1, seller, this.programIds);
1322
+ const [sellerStatus] = PDA.orderStatus(seller, m.order.nonce, this.programIds);
1323
+ addresses.push(
1324
+ seller,
1325
+ getAssociatedTokenAddressSync(yesMint, seller, false, TOKEN_2022_PROGRAM_ID),
1326
+ getAssociatedTokenAddressSync(collateralMint, seller),
1327
+ sellerPos,
1328
+ sellerStatus
1329
+ );
1330
+ }
1331
+ if (this.programIds.feeManagement && this.feeConfigOwner) {
1332
+ const companyAddr = await this.companyAddress();
1333
+ addresses.push(
1334
+ this.programIds.feeManagement,
1335
+ PDA.feeConfig(this.feeConfigOwner, this.programIds)[0],
1336
+ PDA.marketFeeOverride(condition, this.programIds)[0]
1337
+ );
1338
+ if (companyAddr) {
1339
+ addresses.push(getAssociatedTokenAddressSync(collateralMint, companyAddr));
1340
+ }
1341
+ addresses.push(payer);
1342
+ }
1343
+ const slot = await connection.getSlot("finalized");
1344
+ const [createIx, altAddress] = AddressLookupTableProgram.createLookupTable({
1345
+ authority: payer,
1346
+ payer,
1347
+ recentSlot: slot
1348
+ });
1349
+ const BATCH = 30;
1350
+ const extendIxs = [];
1351
+ for (let i = 0; i < addresses.length; i += BATCH) {
1352
+ extendIxs.push(AddressLookupTableProgram.extendLookupTable({
1353
+ payer,
1354
+ authority: payer,
1355
+ lookupTable: altAddress,
1356
+ addresses: addresses.slice(i, i + BATCH)
1357
+ }));
1358
+ }
1359
+ await this._sendLegacyTx([createIx, extendIxs[0]]);
1360
+ for (let i = 1; i < extendIxs.length; i++) {
1361
+ await this._sendLegacyTx([extendIxs[i]]);
1362
+ }
1363
+ for (let attempt = 0; attempt < 30; attempt++) {
1364
+ await new Promise((r) => setTimeout(r, 1e3));
1365
+ const res = await connection.getAddressLookupTable(altAddress);
1366
+ if (res.value && res.value.state.addresses.length === addresses.length) {
1367
+ this._altCache.set(cacheKey, res.value);
1368
+ return res.value;
1369
+ }
1370
+ }
1371
+ throw new Error(`ALT ${altAddress.toBase58()} not active after 30s`);
1372
+ }
1373
+ async _sendLegacyTx(instructions) {
1374
+ const { connection } = this.provider;
1375
+ const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash();
1376
+ const { Transaction: Transaction4 } = await import('@solana/web3.js');
1377
+ const tx = new Transaction4();
1378
+ tx.recentBlockhash = blockhash;
1379
+ tx.feePayer = this.walletPubkey;
1380
+ tx.add(...instructions);
1381
+ const signed = await this.provider.wallet.signTransaction(tx);
1382
+ const sig = await connection.sendRawTransaction(signed.serialize());
1383
+ await connection.confirmTransaction({ signature: sig, blockhash, lastValidBlockHeight }, "confirmed");
1384
+ }
1057
1385
  /**
1058
1386
  * Send a match transaction as versioned (v0).
1059
1387
  * Pass a pre-built AddressLookupTableAccount to compress account keys and
@@ -1063,7 +1391,7 @@ var ClobClient = class {
1063
1391
  * If `whitelistedWallet` is provided and differs from `this.provider.wallet`,
1064
1392
  * both wallets sign the transaction (whitelisted operator + payer).
1065
1393
  */
1066
- async _sendMatchTx(instructions, lookupTable, whitelistedWallet) {
1394
+ async sendMatchTx(instructions, lookupTable, whitelistedWallet) {
1067
1395
  const { connection } = this.provider;
1068
1396
  const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash();
1069
1397
  const message = new TransactionMessage({
@@ -1172,7 +1500,13 @@ var ClobClient = class {
1172
1500
  *
1173
1501
  * remaining_accounts: [hook×3] [seller×5 × N]
1174
1502
  */
1175
- async matchComplementary(buySigned, makersSigned, collateralMint, feeRecipient, whitelistedWallet, lookupTable) {
1503
+ /** Build Ed25519 + matchComplementary instructions without sending.
1504
+ *
1505
+ * If `buySigned.order.fee > 0` and `feeClient` + `feeConfigOwner` are wired in,
1506
+ * automatically appends 5 fee_management remaining_accounts so the program CPIs
1507
+ * to distribute_fee internally. No manual `feeDistribute` param needed.
1508
+ */
1509
+ async buildMatchComplementaryIxs(buySigned, makersSigned, collateralMint, feeRecipient, whitelisted, opts) {
1176
1510
  const condition = buySigned.order.condition;
1177
1511
  const tokenId = buySigned.order.tokenId;
1178
1512
  const [outcomeMint] = tokenId === 1 ? PDA.yesMint(condition, this.programIds) : PDA.noMint(condition, this.programIds);
@@ -1202,12 +1536,23 @@ var ClobClient = class {
1202
1536
  { pubkey: sellOrderStatus, isSigner: false, isWritable: true }
1203
1537
  ];
1204
1538
  });
1205
- const whitelisted = whitelistedWallet.publicKey;
1539
+ let feeAccounts = [];
1540
+ if (buySigned.order.fee.gtn(0) && this.programIds.feeManagement && this.feeConfigOwner) {
1541
+ const companyAddr = await this.companyAddress();
1542
+ if (companyAddr) {
1543
+ const oracleVault = opts?.marketOracleVault ?? this.walletPubkey;
1544
+ feeAccounts = [
1545
+ { pubkey: this.programIds.feeManagement, isSigner: false, isWritable: false },
1546
+ { pubkey: PDA.feeConfig(this.feeConfigOwner, this.programIds)[0], isSigner: false, isWritable: false },
1547
+ { pubkey: PDA.marketFeeOverride(condition, this.programIds)[0], isSigner: false, isWritable: false },
1548
+ { pubkey: getAssociatedTokenAddressSync(collateralMint, companyAddr), isSigner: false, isWritable: true },
1549
+ { pubkey: oracleVault, isSigner: false, isWritable: true }
1550
+ ];
1551
+ }
1552
+ }
1206
1553
  const whitelistEntry = this.whitelistEntryPda(whitelisted);
1207
1554
  const makerNonces = makersSigned.map((m) => m.order.nonce);
1208
- const ed25519Ixs = [
1209
- buildBatchedEd25519Instruction([buySigned, ...makersSigned])
1210
- ];
1555
+ const ed25519Ix = buildBatchedEd25519Instruction([buySigned, ...makersSigned]);
1211
1556
  const matchIx = await this.program.methods.matchComplementary(buySigned.order.nonce, makerNonces).accounts({
1212
1557
  whitelisted,
1213
1558
  payer: this.walletPubkey,
@@ -1226,12 +1571,19 @@ var ClobClient = class {
1226
1571
  tokenProgram: TOKEN_PROGRAM_ID,
1227
1572
  token2022Program: TOKEN_2022_PROGRAM_ID,
1228
1573
  systemProgram: SystemProgram.programId
1229
- }).remainingAccounts([...hookAccounts, ...makerAccounts]).instruction();
1230
- const sig = await this._sendMatchTx(
1231
- [...ed25519Ixs, matchIx],
1232
- lookupTable,
1233
- whitelistedWallet
1574
+ }).remainingAccounts([...hookAccounts, ...makerAccounts, ...feeAccounts]).instruction();
1575
+ return [ed25519Ix, matchIx];
1576
+ }
1577
+ async matchComplementary(buySigned, makersSigned, collateralMint, feeRecipient, whitelistedWallet, lookupTable, opts) {
1578
+ const ixs = await this.buildMatchComplementaryIxs(
1579
+ buySigned,
1580
+ makersSigned,
1581
+ collateralMint,
1582
+ feeRecipient,
1583
+ whitelistedWallet.publicKey,
1584
+ opts
1234
1585
  );
1586
+ const sig = await this.sendMatchTx(ixs, lookupTable, whitelistedWallet);
1235
1587
  return { signature: sig };
1236
1588
  }
1237
1589
  /**
@@ -1306,7 +1658,7 @@ var ClobClient = class {
1306
1658
  break;
1307
1659
  }
1308
1660
  }
1309
- const sig = await this._sendMatchTx(
1661
+ const sig = await this.sendMatchTx(
1310
1662
  [...ed25519Ixs, matchIx],
1311
1663
  lookupTable,
1312
1664
  whitelistedWallet
@@ -1383,7 +1735,7 @@ var ClobClient = class {
1383
1735
  break;
1384
1736
  }
1385
1737
  }
1386
- const sig = await this._sendMatchTx(
1738
+ const sig = await this.sendMatchTx(
1387
1739
  [...ed25519Ixs, matchIx],
1388
1740
  lookupTable,
1389
1741
  whitelistedWallet
@@ -1401,15 +1753,37 @@ var ClobClient = class {
1401
1753
  *
1402
1754
  * All makers must have the same tokenId and side as makers[0].
1403
1755
  */
1404
- async matchOrders(taker, makers, collateralMint, feeRecipient, whitelistedWallet, lookupTable) {
1756
+ /**
1757
+ * Auto-detect match type and execute in a single transaction.
1758
+ * ALT is managed automatically (created on first call per condition, cached thereafter).
1759
+ * feeRecipient and collateralMint are derived from on-chain config.
1760
+ * Fee distribution (distribute_fee CPI) fires automatically when order.fee > 0.
1761
+ *
1762
+ * @param opts.marketOracleVault Required for presale markets (is_admin=false).
1763
+ * Pass the ATA of the market_oracle PDA so 50% of fee goes there.
1764
+ * For admin markets (is_admin=true) omit — payer is used as placeholder (no transfer).
1765
+ */
1766
+ async matchOrders(taker, makers, opts) {
1405
1767
  if (makers.length === 0) throw new InvalidParamError("At least 1 maker required");
1768
+ const collateralMint = this.networkConfig.defaultCollateral.mint;
1769
+ const cfg = await this.fetchConfig();
1770
+ if (!cfg) throw new InvalidParamError("CLOB config not found on-chain");
1771
+ const feeRecipient = cfg.feeRecipient;
1772
+ const whitelistedWallet = this.provider.wallet;
1773
+ const alt = await this.ensureAlt(
1774
+ taker.order.condition,
1775
+ collateralMint,
1776
+ taker.order.maker,
1777
+ taker.order.nonce,
1778
+ makers
1779
+ );
1406
1780
  const t = taker.order;
1407
1781
  const m0 = makers[0].order;
1408
1782
  const SIDE_BUY = 0;
1409
1783
  const SIDE_SELL = 1;
1410
1784
  if (t.tokenId === m0.tokenId) {
1411
1785
  if (t.side === SIDE_BUY && makers.every((m) => m.order.side === SIDE_SELL)) {
1412
- return this.matchComplementary(taker, makers, collateralMint, feeRecipient, whitelistedWallet, lookupTable);
1786
+ return this.matchComplementary(taker, makers, collateralMint, feeRecipient, whitelistedWallet, alt, opts);
1413
1787
  }
1414
1788
  if (t.side === SIDE_SELL && makers.every((m) => m.order.side === SIDE_BUY)) {
1415
1789
  throw new InvalidParamError("COMPLEMENTARY N-maker: taker must be the BUY side");
@@ -1418,19 +1792,11 @@ var ClobClient = class {
1418
1792
  }
1419
1793
  const allBuy = t.side === SIDE_BUY && makers.every((m) => m.order.side === SIDE_BUY);
1420
1794
  const allSell = t.side === SIDE_SELL && makers.every((m) => m.order.side === SIDE_SELL);
1421
- if (!allBuy && !allSell) {
1422
- throw new InvalidParamError("MINT/MERGE: all orders must be the same side (all BUY or all SELL)");
1423
- }
1424
- if (t.tokenId !== 1) {
1425
- throw new InvalidParamError("MINT/MERGE: taker must be the YES side (tokenId=1)");
1426
- }
1427
- if (!makers.every((m) => m.order.tokenId === 0)) {
1428
- throw new InvalidParamError("MINT/MERGE: all makers must be the NO side (tokenId=0)");
1429
- }
1430
- if (allBuy) {
1431
- return this.matchMintOrders(taker, makers, collateralMint, feeRecipient, whitelistedWallet, lookupTable);
1432
- }
1433
- return this.matchMergeOrders(taker, makers, collateralMint, feeRecipient, whitelistedWallet, lookupTable);
1795
+ if (!allBuy && !allSell) throw new InvalidParamError("MINT/MERGE: all orders must be same side");
1796
+ if (t.tokenId !== 1) throw new InvalidParamError("MINT/MERGE: taker must be YES (tokenId=1)");
1797
+ if (!makers.every((m) => m.order.tokenId === 0)) throw new InvalidParamError("MINT/MERGE: makers must be NO (tokenId=0)");
1798
+ if (allBuy) return this.matchMintOrders(taker, makers, collateralMint, feeRecipient, whitelistedWallet, alt);
1799
+ return this.matchMergeOrders(taker, makers, collateralMint, feeRecipient, whitelistedWallet, alt);
1434
1800
  }
1435
1801
  // ─── Whitelist admin ─────────────────────────────────────────────────────────
1436
1802
  /** Add an address to the CLOB whitelist (owner only). */
@@ -1529,6 +1895,389 @@ var ClobClient = class {
1529
1895
  return status?.isCancelled === true;
1530
1896
  }
1531
1897
  };
1898
+ var FeeManagementClient = class {
1899
+ constructor(program, provider, programIds) {
1900
+ this.program = program;
1901
+ this.provider = provider;
1902
+ this.programIds = programIds;
1903
+ }
1904
+ async initFeeConfig(admin, companyAddress, referralAddress, presaleRevenueAddress, investorsMarketRev, companyMarketRev, agentsPresaleRev, companyPresaleRev, authority, payer) {
1905
+ const [feeConfigPda] = PDA.feeConfig(authority, this.programIds);
1906
+ const sig = await this.program.methods.initialize({
1907
+ admin,
1908
+ companyAddress,
1909
+ referralAddress,
1910
+ presaleRevenueAddress,
1911
+ investorsMarketRev,
1912
+ companyMarketRev,
1913
+ agentsPresaleRev,
1914
+ companyPresaleRev
1915
+ }).accounts({
1916
+ authority,
1917
+ payer,
1918
+ feeConfig: feeConfigPda,
1919
+ systemProgram: SystemProgram.programId
1920
+ }).signers([]).rpc();
1921
+ return { signature: sig };
1922
+ }
1923
+ async fetchFeeConfig(owner) {
1924
+ try {
1925
+ const [pda] = PDA.feeConfig(owner, this.programIds);
1926
+ return await this.program.account.feeConfig.fetch(pda);
1927
+ } catch {
1928
+ return null;
1929
+ }
1930
+ }
1931
+ /**
1932
+ * Fetch per-question fees for a condition.
1933
+ * Returns null if no fees have been set yet.
1934
+ */
1935
+ async fetchQuestionFee(conditionPda) {
1936
+ try {
1937
+ const [pda] = PDA.questionFee(conditionPda, this.programIds);
1938
+ const acc = await this.program.account.questionFee.fetch(pda);
1939
+ return {
1940
+ conditionId: new Uint8Array(acc.conditionId),
1941
+ mergeFee: acc.mergeFee,
1942
+ redeemFee: acc.redeemFee,
1943
+ swapFee: acc.swapFee,
1944
+ bump: acc.bump
1945
+ };
1946
+ } catch {
1947
+ return null;
1948
+ }
1949
+ }
1950
+ /**
1951
+ * Set per-question fees for a condition.
1952
+ * @param conditionPda - condition PDA from the question
1953
+ * @param mergeFee - fee out of FEE_DENOMINATOR (1_000_000), e.g. 2_000 = 0.2%
1954
+ * @param redeemFee - fee out of FEE_DENOMINATOR
1955
+ * @param swapFee - trading fee out of FEE_DENOMINATOR
1956
+ * @param feeConfigOwner - pubkey that owns the fee_config PDA (usually market deployer)
1957
+ * @param authority - signer authorized in fee_config whitelist / admin / owner
1958
+ * @param payer - rent + tx fee payer
1959
+ */
1960
+ async updateFeeConfig(companyAddress, referralAddress, presaleRevenueAddress, investorsMarketRev, companyMarketRev, agentsPresaleRev, companyPresaleRev, authority, payer) {
1961
+ const [feeConfigPda] = PDA.feeConfig(authority, this.programIds);
1962
+ const sig = await this.program.methods.updateConfig({
1963
+ companyAddress,
1964
+ referralAddress,
1965
+ presaleRevenueAddress,
1966
+ investorsMarketRev,
1967
+ companyMarketRev,
1968
+ agentsPresaleRev,
1969
+ companyPresaleRev
1970
+ }).accounts({
1971
+ authority,
1972
+ payer,
1973
+ feeConfig: feeConfigPda
1974
+ }).signers([]).rpc();
1975
+ return { signature: sig };
1976
+ }
1977
+ async setMarketFeeOverride(conditionPda, investors, company, isAdmin, feeConfigOwner, authority, payer) {
1978
+ const [feeConfigPda] = PDA.feeConfig(feeConfigOwner, this.programIds);
1979
+ const [marketFeeOverridePda] = PDA.marketFeeOverride(conditionPda, this.programIds);
1980
+ const sig = await this.program.methods.setMarketFeeOverride(conditionPda, investors, company, isAdmin).accounts({
1981
+ authority,
1982
+ payer,
1983
+ feeConfig: feeConfigPda,
1984
+ marketFeeOverride: marketFeeOverridePda,
1985
+ systemProgram: SystemProgram.programId
1986
+ }).signers([]).rpc();
1987
+ return { signature: sig };
1988
+ }
1989
+ async buildDistributeFeeIx(conditionPda, amount, feeConfigOwner, sourceAta, companyAta, marketOracleVault, authority) {
1990
+ const [feeConfigPda] = PDA.feeConfig(feeConfigOwner, this.programIds);
1991
+ const [marketFeeOverridePda] = PDA.marketFeeOverride(conditionPda, this.programIds);
1992
+ return this.program.methods.distributeFee(conditionPda, amount).accounts({
1993
+ feeConfig: feeConfigPda,
1994
+ marketFeeOverride: marketFeeOverridePda,
1995
+ authority,
1996
+ sourceAta,
1997
+ companyAta,
1998
+ marketOracleVault,
1999
+ tokenProgram: new PublicKey("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA")
2000
+ }).instruction();
2001
+ }
2002
+ async distributeFee(conditionPda, amount, feeConfigOwner, sourceAta, companyAta, marketOracleVault, authority) {
2003
+ const [feeConfigPda] = PDA.feeConfig(feeConfigOwner, this.programIds);
2004
+ const [marketFeeOverridePda] = PDA.marketFeeOverride(conditionPda, this.programIds);
2005
+ const sig = await this.program.methods.distributeFee(conditionPda, amount).accounts({
2006
+ feeConfig: feeConfigPda,
2007
+ marketFeeOverride: marketFeeOverridePda,
2008
+ authority,
2009
+ sourceAta,
2010
+ companyAta,
2011
+ marketOracleVault,
2012
+ tokenProgram: new PublicKey("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA")
2013
+ }).signers([]).rpc();
2014
+ return { signature: sig };
2015
+ }
2016
+ async setQuestionFee(conditionPda, mergeFee, redeemFee, swapFee, feeConfigOwner, authority, payer) {
2017
+ const [feeConfigPda] = PDA.feeConfig(feeConfigOwner, this.programIds);
2018
+ const [questionFeePda] = PDA.questionFee(conditionPda, this.programIds);
2019
+ const sig = await this.program.methods.setQuestionFee(
2020
+ Array.from(conditionPda.toBytes()),
2021
+ mergeFee,
2022
+ redeemFee,
2023
+ swapFee
2024
+ ).accounts({
2025
+ authority,
2026
+ payer,
2027
+ feeConfig: feeConfigPda,
2028
+ questionFee: questionFeePda,
2029
+ systemProgram: SystemProgram.programId
2030
+ }).signers([]).rpc();
2031
+ return { signature: sig };
2032
+ }
2033
+ };
2034
+ var PresaleClient = class {
2035
+ constructor(program, provider, programIds) {
2036
+ this.program = program;
2037
+ this.provider = provider;
2038
+ this.programIds = programIds;
2039
+ }
2040
+ get walletPubkey() {
2041
+ return this.provider.wallet.publicKey;
2042
+ }
2043
+ presalePda(questionMarketConfig, presaleIndex) {
2044
+ return PDA.presale(questionMarketConfig, presaleIndex, this.programIds)[0];
2045
+ }
2046
+ qtMintPda(presalePda) {
2047
+ return PDA.qtMint(presalePda, this.programIds)[0];
2048
+ }
2049
+ qtAuthorityPda(presalePda) {
2050
+ return PDA.qtAuthority(presalePda, this.programIds)[0];
2051
+ }
2052
+ userBuyRecordPda(presalePda, user) {
2053
+ return PDA.userBuyRecord(presalePda, user, this.programIds)[0];
2054
+ }
2055
+ /**
2056
+ * Buy MST tokens during presale.
2057
+ * qtAmount: amount of MST to receive (9 decimals).
2058
+ * USDC cost = qtAmount * price / 1e9.
2059
+ */
2060
+ async buy(presalePda, qtAmount, buyer = this.walletPubkey, payer = this.walletPubkey, signers = []) {
2061
+ const presale = await this.fetchPresale(presalePda);
2062
+ if (!presale) throw new Error(`Presale not found: ${presalePda.toBase58()}`);
2063
+ const qtMint = presale.qtMint;
2064
+ const currencyMint = presale.currencyMint;
2065
+ const qtAuthority = this.qtAuthorityPda(presalePda);
2066
+ const userBuyRecord = this.userBuyRecordPda(presalePda, buyer);
2067
+ const buyerQtAta = getAssociatedTokenAddressSync(qtMint, buyer);
2068
+ const buyerCurrencyAta = getAssociatedTokenAddressSync(currencyMint, buyer);
2069
+ const presaleVault = getAssociatedTokenAddressSync(currencyMint, presalePda, true);
2070
+ const sig = await this.program.methods.buy(qtAmount).accounts({
2071
+ buyer,
2072
+ payer,
2073
+ presale: presalePda,
2074
+ qtMint,
2075
+ qtAuthority,
2076
+ buyerQtAta,
2077
+ buyerCurrencyAta,
2078
+ presaleVault,
2079
+ currencyMint,
2080
+ userBuyRecord,
2081
+ tokenProgram: TOKEN_PROGRAM_ID,
2082
+ associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID,
2083
+ systemProgram: SystemProgram.programId
2084
+ }).signers(signers).rpc();
2085
+ return { signature: sig };
2086
+ }
2087
+ /**
2088
+ * Refund: burn user's MST and return USDC.
2089
+ * Only callable when presale status = Rejected.
2090
+ */
2091
+ async refund(presalePda, user = this.walletPubkey, signers = []) {
2092
+ const presale = await this.fetchPresale(presalePda);
2093
+ if (!presale) throw new Error(`Presale not found: ${presalePda.toBase58()}`);
2094
+ const qtMint = presale.qtMint;
2095
+ const currencyMint = presale.currencyMint;
2096
+ const userBuyRecord = this.userBuyRecordPda(presalePda, user);
2097
+ const userQtAta = getAssociatedTokenAddressSync(qtMint, user);
2098
+ const userCurrencyAta = getAssociatedTokenAddressSync(currencyMint, user);
2099
+ const presaleVault = getAssociatedTokenAddressSync(currencyMint, presalePda, true);
2100
+ const sig = await this.program.methods.refund().accounts({
2101
+ user,
2102
+ presale: presalePda,
2103
+ qtMint,
2104
+ userQtAta,
2105
+ userCurrencyAta,
2106
+ presaleVault,
2107
+ currencyMint,
2108
+ userBuyRecord,
2109
+ tokenProgram: TOKEN_PROGRAM_ID,
2110
+ associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID,
2111
+ systemProgram: SystemProgram.programId
2112
+ }).signers(signers).rpc();
2113
+ return { signature: sig };
2114
+ }
2115
+ /**
2116
+ * Creator claims their share of presale revenue after distribute_presale_revenue.
2117
+ */
2118
+ async claimRevenue(presalePda, creator = this.walletPubkey, signers = []) {
2119
+ const presale = await this.fetchPresale(presalePda);
2120
+ if (!presale) throw new Error(`Presale not found: ${presalePda.toBase58()}`);
2121
+ const currencyMint = presale.currencyMint;
2122
+ const presaleVault = getAssociatedTokenAddressSync(currencyMint, presalePda, true);
2123
+ const creatorCurrencyAta = getAssociatedTokenAddressSync(currencyMint, creator);
2124
+ const sig = await this.program.methods.claimRevenue().accounts({
2125
+ creator,
2126
+ presale: presalePda,
2127
+ presaleVault,
2128
+ creatorCurrencyAta,
2129
+ currencyMint,
2130
+ tokenProgram: TOKEN_PROGRAM_ID,
2131
+ associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID,
2132
+ systemProgram: SystemProgram.programId
2133
+ }).signers(signers).rpc();
2134
+ return { signature: sig };
2135
+ }
2136
+ /**
2137
+ * Transfer creator_claimable_revenue (80%) to BOTMM wallet.
2138
+ * Call after collectPresaleRevenue (distribute_presale_revenue).
2139
+ */
2140
+ async distributeBotmmRevenue(presalePda, botmmAddress, currencyMint) {
2141
+ if (!currencyMint) {
2142
+ const presale = await this.fetchPresale(presalePda);
2143
+ if (!presale) throw new Error(`Presale not found: ${presalePda.toBase58()}`);
2144
+ currencyMint = presale.currencyMint;
2145
+ }
2146
+ const presaleVault = getAssociatedTokenAddressSync(currencyMint, presalePda, true);
2147
+ const botmmTokenAccount = getAssociatedTokenAddressSync(currencyMint, botmmAddress);
2148
+ return this.program.methods.distributeBotmmRevenue().accounts({
2149
+ presale: presalePda,
2150
+ presaleVault,
2151
+ currencyMint,
2152
+ botmmTokenAccount,
2153
+ tokenProgram: TOKEN_PROGRAM_ID
2154
+ }).transaction();
2155
+ }
2156
+ // ─── Queries ─────────────────────────────────────────────────────────────────
2157
+ async fetchPresale(presalePda) {
2158
+ try {
2159
+ const acc = await this.program.account.presaleAccount.fetch(presalePda);
2160
+ const rawStatus = acc.status;
2161
+ const status = rawStatus.approved !== void 0 ? "approved" : rawStatus.rejected !== void 0 ? "rejected" : "pending";
2162
+ return {
2163
+ version: acc.version,
2164
+ questionMarketConfig: acc.questionMarketConfig,
2165
+ presaleIndex: acc.presaleIndex,
2166
+ creator: acc.creator,
2167
+ currencyMint: acc.currencyMint,
2168
+ qtMint: acc.qtMint,
2169
+ price: acc.price,
2170
+ startTime: acc.startTime,
2171
+ endTime: acc.endTime,
2172
+ status,
2173
+ soldTokenAmount: acc.soldTokenAmount,
2174
+ initialTokenAmountCreator: acc.initialTokenAmountCreator,
2175
+ agentsRev: acc.agentsRev,
2176
+ companyRev: acc.companyRev,
2177
+ referralAddress: acc.referralAddress,
2178
+ companyAddress: acc.companyAddress,
2179
+ isDistributeRevenue: acc.isDistributeRevenue,
2180
+ creatorClaimableRevenue: acc.creatorClaimableRevenue,
2181
+ bump: acc.bump
2182
+ };
2183
+ } catch {
2184
+ return null;
2185
+ }
2186
+ }
2187
+ async fetchUserBuyRecord(presalePda, user) {
2188
+ try {
2189
+ const pda = this.userBuyRecordPda(presalePda, user);
2190
+ const acc = await this.program.account.userBuyRecord.fetch(pda);
2191
+ return {
2192
+ user: acc.user,
2193
+ presale: acc.presale,
2194
+ currencyAmount: acc.currencyAmount,
2195
+ bump: acc.bump
2196
+ };
2197
+ } catch {
2198
+ return null;
2199
+ }
2200
+ }
2201
+ };
2202
+ var MarketOracleClient = class {
2203
+ constructor(program, provider, programIds) {
2204
+ this.program = program;
2205
+ this.provider = provider;
2206
+ this.programIds = programIds;
2207
+ }
2208
+ get walletPubkey() {
2209
+ return this.provider.wallet.publicKey;
2210
+ }
2211
+ marketOraclePda(questionPda) {
2212
+ return PDA.marketOraclePda(questionPda, this.programIds)[0];
2213
+ }
2214
+ userClaimRecordPda(marketOraclePda, user) {
2215
+ return PDA.userClaimRecord(marketOraclePda, user, this.programIds)[0];
2216
+ }
2217
+ /**
2218
+ * User burns their MST and claims proportional share of oracle vault USDC.
2219
+ * Call after market.collectTradingFee snapshotted qt supply.
2220
+ */
2221
+ async claimFeesShare(marketOraclePda, user = this.walletPubkey, payer = this.walletPubkey, signers = []) {
2222
+ const oracle = await this.fetchMarketOracle(marketOraclePda);
2223
+ if (!oracle) throw new Error(`MarketOracle not found: ${marketOraclePda.toBase58()}`);
2224
+ const currencyMint = oracle.currencyMint;
2225
+ const qtMint = oracle.qtMint;
2226
+ const marketOracleVault = getAssociatedTokenAddressSync(currencyMint, marketOraclePda, true);
2227
+ const userQtAta = getAssociatedTokenAddressSync(qtMint, user);
2228
+ const userCurrencyAta = getAssociatedTokenAddressSync(currencyMint, user);
2229
+ const userClaimRecord = this.userClaimRecordPda(marketOraclePda, user);
2230
+ const sig = await this.program.methods.claimFeesShare().accounts({
2231
+ user,
2232
+ payer,
2233
+ marketOracle: marketOraclePda,
2234
+ marketOracleVault,
2235
+ currencyMint,
2236
+ qtMint,
2237
+ userQtAta,
2238
+ userCurrencyAta,
2239
+ userClaimRecord,
2240
+ tokenProgram: TOKEN_PROGRAM_ID,
2241
+ associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID,
2242
+ systemProgram: SystemProgram.programId
2243
+ }).signers(signers).rpc();
2244
+ return { signature: sig };
2245
+ }
2246
+ // ─── Queries ─────────────────────────────────────────────────────────────────
2247
+ async fetchMarketOracle(marketOraclePda) {
2248
+ try {
2249
+ const acc = await this.program.account.marketOracleAccount.fetch(marketOraclePda);
2250
+ return {
2251
+ version: acc.version,
2252
+ question: acc.question,
2253
+ questionMarketConfig: acc.questionMarketConfig,
2254
+ currencyMint: acc.currencyMint,
2255
+ creator: acc.creator,
2256
+ qtMint: acc.qtMint,
2257
+ feesDistributed: acc.feesDistributed,
2258
+ qtTotalSupply: acc.qtTotalSupply,
2259
+ totalClaimed: acc.totalClaimed,
2260
+ bump: acc.bump
2261
+ };
2262
+ } catch {
2263
+ return null;
2264
+ }
2265
+ }
2266
+ async fetchUserClaimRecord(marketOraclePda, user) {
2267
+ try {
2268
+ const pda = this.userClaimRecordPda(marketOraclePda, user);
2269
+ const acc = await this.program.account.userClaimRecord.fetch(pda);
2270
+ return {
2271
+ user: acc.user,
2272
+ marketOracle: acc.marketOracle,
2273
+ hasClaimed: acc.hasClaimed,
2274
+ bump: acc.bump
2275
+ };
2276
+ } catch {
2277
+ return null;
2278
+ }
2279
+ }
2280
+ };
1532
2281
  var XMarketSDK = class {
1533
2282
  constructor(config, wallet, marketOwner) {
1534
2283
  this.networkConfig = config;
@@ -1576,10 +2325,38 @@ var XMarketSDK = class {
1576
2325
  get clob() {
1577
2326
  if (!this._clob) {
1578
2327
  const program = new anchor4.Program(this._withAddress(clobExchangeIdl, this._programIds.clobExchange), this.provider);
1579
- this._clob = new ClobClient(program, this.provider, this._programIds);
2328
+ this._clob = new ClobClient(program, this.provider, this._programIds, this.networkConfig);
2329
+ if (this.networkConfig.feeConfigOwner && this._programIds.feeManagement) {
2330
+ this._clob.feeConfigOwner = this.networkConfig.feeConfigOwner;
2331
+ this._clob.feeClient = this.fee;
2332
+ }
1580
2333
  }
1581
2334
  return this._clob;
1582
2335
  }
2336
+ get fee() {
2337
+ if (!this._fee) {
2338
+ if (!this._programIds.feeManagement) throw new Error("feeManagement program ID not configured in NetworkConfig");
2339
+ const program = new anchor4.Program(this._withAddress(feeManagementIdl, this._programIds.feeManagement), this.provider);
2340
+ this._fee = new FeeManagementClient(program, this.provider, this._programIds);
2341
+ }
2342
+ return this._fee;
2343
+ }
2344
+ get presale() {
2345
+ if (!this._presale) {
2346
+ if (!this._programIds.presale) throw new Error("presale program ID not configured in NetworkConfig");
2347
+ const program = new anchor4.Program(this._withAddress(presaleIdl, this._programIds.presale), this.provider);
2348
+ this._presale = new PresaleClient(program, this.provider, this._programIds);
2349
+ }
2350
+ return this._presale;
2351
+ }
2352
+ get marketOracle() {
2353
+ if (!this._marketOracle) {
2354
+ if (!this._programIds.marketOracle) throw new Error("marketOracle program ID not configured in NetworkConfig");
2355
+ const program = new anchor4.Program(this._withAddress(marketOracleIdl, this._programIds.marketOracle), this.provider);
2356
+ this._marketOracle = new MarketOracleClient(program, this.provider, this._programIds);
2357
+ }
2358
+ return this._marketOracle;
2359
+ }
1583
2360
  };
1584
2361
  function buildOrder(params) {
1585
2362
  return {
@@ -1709,6 +2486,6 @@ function buildApproveAllOutcomeTokensTx(condition, signer, payer, delegate, prog
1709
2486
  return tx;
1710
2487
  }
1711
2488
 
1712
- export { AccountNotFoundError, ClobClient, CtfClient, HookClient, IX_SYSVAR, InvalidParamError, MAX_APPROVE_AMOUNT, MarketClient, OracleClient, PDA, QuestionStatus, SEEDS, UnauthorizedError, XMarketError, XMarketSDK, buildApproveAllOutcomeTokensTx, buildApproveCollateralTx, buildBatchedEd25519Instruction, buildOrder, deserializeSignedOrder, detectMatchType, generateContentHash, generateQuestionId, getOrderSignBytes, serializeOrderToBytes, serializeSignedOrder, signOrder, signOrderWithKeypair, verifySignedOrder };
2489
+ export { AccountNotFoundError, ClobClient, CtfClient, FEE_DENOMINATOR, FeeManagementClient, HookClient, IX_SYSVAR, InvalidParamError, MAX_APPROVE_AMOUNT, MarketClient, MarketOracleClient, OracleClient, PDA, PresaleClient, QuestionStatus, SEEDS, UnauthorizedError, XMarketError, XMarketSDK, buildApproveAllOutcomeTokensTx, buildApproveCollateralTx, buildBatchedEd25519Instruction, buildOrder, deserializeSignedOrder, detectMatchType, generateContentHash, generateQuestionId, getOrderSignBytes, serializeOrderToBytes, serializeSignedOrder, signOrder, signOrderWithKeypair, verifySignedOrder };
1713
2490
  //# sourceMappingURL=index.mjs.map
1714
2491
  //# sourceMappingURL=index.mjs.map