@theliem/xmarket-sdk 3.29.0 → 4.0.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 +142 -700
- package/dist/index.d.ts +142 -700
- package/dist/index.js +369 -2780
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +370 -2776
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import * as anchor6 from '@coral-xyz/anchor';
|
|
2
2
|
import { PublicKey, SYSVAR_INSTRUCTIONS_PUBKEY, SystemProgram, SYSVAR_RENT_PUBKEY, ComputeBudgetProgram, TransactionMessage, VersionedTransaction, Transaction, TransactionInstruction, Ed25519Program, AddressLookupTableProgram, Connection } from '@solana/web3.js';
|
|
3
3
|
import { createHash } from 'crypto';
|
|
4
|
-
import { TOKEN_PROGRAM_ID, getAssociatedTokenAddressSync, ASSOCIATED_TOKEN_PROGRAM_ID, createAssociatedTokenAccountIdempotentInstruction,
|
|
4
|
+
import { TOKEN_PROGRAM_ID, getAssociatedTokenAddressSync, ASSOCIATED_TOKEN_PROGRAM_ID, createAssociatedTokenAccountIdempotentInstruction, createApproveInstruction } from '@solana/spl-token';
|
|
5
5
|
import BN4 from 'bn.js';
|
|
6
6
|
import * as nacl from 'tweetnacl';
|
|
7
7
|
|
|
8
|
-
// src/sdk
|
|
8
|
+
// src/sdk.ts
|
|
9
9
|
var SEEDS = {
|
|
10
10
|
config: Buffer.from("config"),
|
|
11
11
|
question: Buffer.from("question"),
|
|
@@ -19,8 +19,6 @@ var SEEDS = {
|
|
|
19
19
|
reporter: Buffer.from("reporter"),
|
|
20
20
|
result: Buffer.from("result"),
|
|
21
21
|
ctfConfig: Buffer.from("ctf_config"),
|
|
22
|
-
hookConfig: Buffer.from("hook_config"),
|
|
23
|
-
extraAccountMetas: Buffer.from("extra-account-metas"),
|
|
24
22
|
clobConfig: Buffer.from("clob_config"),
|
|
25
23
|
order: Buffer.from("order"),
|
|
26
24
|
feeConfig: Buffer.from("fee_config"),
|
|
@@ -125,19 +123,6 @@ var PDA = class {
|
|
|
125
123
|
programIds.oracle
|
|
126
124
|
);
|
|
127
125
|
}
|
|
128
|
-
// ─── Hook ───────────────────────────────────────────────────────────────────
|
|
129
|
-
static hookConfig(programIds) {
|
|
130
|
-
return PublicKey.findProgramAddressSync(
|
|
131
|
-
[SEEDS.hookConfig],
|
|
132
|
-
programIds.hook
|
|
133
|
-
);
|
|
134
|
-
}
|
|
135
|
-
static extraAccountMetaList(mint, programIds) {
|
|
136
|
-
return PublicKey.findProgramAddressSync(
|
|
137
|
-
[SEEDS.extraAccountMetas, mint.toBuffer()],
|
|
138
|
-
programIds.hook
|
|
139
|
-
);
|
|
140
|
-
}
|
|
141
126
|
// ─── CLOB ───────────────────────────────────────────────────────────────────
|
|
142
127
|
static clobConfig(programIds) {
|
|
143
128
|
return PublicKey.findProgramAddressSync(
|
|
@@ -322,41 +307,49 @@ var OracleClient = class {
|
|
|
322
307
|
}).rpc();
|
|
323
308
|
return { signature: sig };
|
|
324
309
|
}
|
|
325
|
-
/** Admin or owner
|
|
326
|
-
async
|
|
327
|
-
const
|
|
310
|
+
/** Admin or owner registers a reporter PDA. */
|
|
311
|
+
async addReporter(reporterAddress, ownerPubkey) {
|
|
312
|
+
const oracleConfig = this.configPda(ownerPubkey);
|
|
313
|
+
const [reporterPda] = PDA.reporter(oracleConfig, reporterAddress, this.programIds);
|
|
314
|
+
const sig = await this.program.methods.addReporter().accounts({
|
|
328
315
|
authority: this.walletPubkey,
|
|
329
|
-
|
|
330
|
-
|
|
316
|
+
oracleConfig,
|
|
317
|
+
reporterAddress,
|
|
318
|
+
reporter: reporterPda,
|
|
319
|
+
systemProgram: SystemProgram.programId
|
|
331
320
|
}).rpc();
|
|
332
321
|
return { signature: sig };
|
|
333
322
|
}
|
|
334
|
-
/** Admin or owner removes
|
|
335
|
-
async
|
|
336
|
-
const
|
|
323
|
+
/** Admin or owner removes a reporter PDA. */
|
|
324
|
+
async removeReporter(reporterAddress, ownerPubkey) {
|
|
325
|
+
const oracleConfig = this.configPda(ownerPubkey);
|
|
326
|
+
const [reporterPda] = PDA.reporter(oracleConfig, reporterAddress, this.programIds);
|
|
327
|
+
const sig = await this.program.methods.removeReporter().accounts({
|
|
337
328
|
authority: this.walletPubkey,
|
|
338
|
-
|
|
339
|
-
|
|
329
|
+
oracleConfig,
|
|
330
|
+
reporterAddress,
|
|
331
|
+
reporter: reporterPda,
|
|
332
|
+
systemProgram: SystemProgram.programId
|
|
340
333
|
}).rpc();
|
|
341
334
|
return { signature: sig };
|
|
342
335
|
}
|
|
343
336
|
/**
|
|
344
|
-
*
|
|
345
|
-
*
|
|
337
|
+
* Registered reporter resolves a question.
|
|
338
|
+
* reporterSigner signs; payer covers rent for question_result PDA.
|
|
346
339
|
*/
|
|
347
|
-
async resolveQuestion(questionId, outcomeCount, payoutNumerators,
|
|
340
|
+
async resolveQuestion(questionId, outcomeCount, payoutNumerators, reporterSigner = this.walletPubkey, payer = this.walletPubkey, ownerPubkey) {
|
|
348
341
|
const oracleConfig = this.configPda(ownerPubkey);
|
|
342
|
+
const [reporterPda] = PDA.reporter(oracleConfig, reporterSigner, this.programIds);
|
|
349
343
|
const [questionResultPda] = PDA.questionResult(oracleConfig, questionId, this.programIds);
|
|
350
344
|
return this.program.methods.resolveQuestion(
|
|
351
345
|
Array.from(questionId),
|
|
352
346
|
outcomeCount,
|
|
353
347
|
payoutNumerators.map((n) => new anchor6.BN(n))
|
|
354
348
|
).accounts({
|
|
355
|
-
|
|
349
|
+
reporterSigner,
|
|
356
350
|
oracleConfig,
|
|
351
|
+
reporter: reporterPda,
|
|
357
352
|
questionResult: questionResultPda,
|
|
358
|
-
condition: conditionPda,
|
|
359
|
-
conditionalTokensProgram: this.programIds.conditionalTokens,
|
|
360
353
|
payer,
|
|
361
354
|
systemProgram: SystemProgram.programId
|
|
362
355
|
}).transaction();
|
|
@@ -396,8 +389,7 @@ var OracleClient = class {
|
|
|
396
389
|
owner: acc.owner,
|
|
397
390
|
admin: acc.admin,
|
|
398
391
|
questionCount: acc.questionCount.toNumber(),
|
|
399
|
-
|
|
400
|
-
whitelistLen: acc.whitelistLen,
|
|
392
|
+
reporterCount: acc.reporterCount.toNumber(),
|
|
401
393
|
isPaused: acc.isPaused,
|
|
402
394
|
bump: acc.bump
|
|
403
395
|
};
|
|
@@ -405,6 +397,17 @@ var OracleClient = class {
|
|
|
405
397
|
return null;
|
|
406
398
|
}
|
|
407
399
|
}
|
|
400
|
+
/** Check if an address is a registered reporter (Reporter PDA exists). */
|
|
401
|
+
async isReporter(reporterAddress, ownerPubkey) {
|
|
402
|
+
try {
|
|
403
|
+
const oracleConfig = this.configPda(ownerPubkey);
|
|
404
|
+
const [reporterPda] = PDA.reporter(oracleConfig, reporterAddress, this.programIds);
|
|
405
|
+
const info = await this.provider.connection.getAccountInfo(reporterPda);
|
|
406
|
+
return info !== null;
|
|
407
|
+
} catch {
|
|
408
|
+
return false;
|
|
409
|
+
}
|
|
410
|
+
}
|
|
408
411
|
async fetchQuestionResult(questionId, ownerPubkey) {
|
|
409
412
|
try {
|
|
410
413
|
const oracleConfig = this.configPda(ownerPubkey);
|
|
@@ -463,9 +466,9 @@ var InvalidParamError = class extends XMarketError {
|
|
|
463
466
|
}
|
|
464
467
|
};
|
|
465
468
|
|
|
466
|
-
// src/programs/market
|
|
469
|
+
// src/programs/market.ts
|
|
467
470
|
var TOKEN_METADATA_PROGRAM_ID = new PublicKey("metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s");
|
|
468
|
-
var
|
|
471
|
+
var MarketClient = class {
|
|
469
472
|
constructor(program, provider, programIds, ownerPubkey) {
|
|
470
473
|
this.program = program;
|
|
471
474
|
this.provider = provider;
|
|
@@ -658,7 +661,7 @@ var MarketClientV2 = class {
|
|
|
658
661
|
/**
|
|
659
662
|
* Convenience: fetch YES and NO token balances for a question.
|
|
660
663
|
* Returns null for each if question not approved or position not initialized.
|
|
661
|
-
* Requires ctfClient to be injected (done automatically by
|
|
664
|
+
* Requires ctfClient to be injected (done automatically by XMarketSDK).
|
|
662
665
|
*/
|
|
663
666
|
async fetchQuestionBalances(questionPda, owner) {
|
|
664
667
|
if (!this.ctfClient) return { yes: null, no: null };
|
|
@@ -879,6 +882,27 @@ var MarketClientV2 = class {
|
|
|
879
882
|
systemProgram: SystemProgram.programId
|
|
880
883
|
}).transaction();
|
|
881
884
|
}
|
|
885
|
+
/**
|
|
886
|
+
* Resolve a question by reading the oracle question_result PDA and updating the CTF condition.
|
|
887
|
+
* Must be called after sdk.oracle.resolveQuestion records the result.
|
|
888
|
+
* Caller must be on the question_market whitelist.
|
|
889
|
+
*/
|
|
890
|
+
async resolveQuestion(questionId, conditionPda, oracleOwner, payer = this.walletPubkey) {
|
|
891
|
+
if (!this.programIds.oracle) throw new Error("oracle program ID not configured");
|
|
892
|
+
const [questionPda] = PDA.question(this.configPda, questionId, this.programIds);
|
|
893
|
+
const oracleConfigPda = PDA.oracleConfig(oracleOwner, this.programIds)[0];
|
|
894
|
+
const [questionResult] = PDA.questionResult(oracleConfigPda, questionId, this.programIds);
|
|
895
|
+
return this.program.methods.resolveQuestion(Array.from(questionId)).accounts({
|
|
896
|
+
payer,
|
|
897
|
+
config: this.configPda,
|
|
898
|
+
question: questionPda,
|
|
899
|
+
questionResult,
|
|
900
|
+
condition: conditionPda,
|
|
901
|
+
ctfProgram: this.programIds.conditionalTokens,
|
|
902
|
+
oracleProgram: this.programIds.oracle,
|
|
903
|
+
systemProgram: SystemProgram.programId
|
|
904
|
+
}).transaction();
|
|
905
|
+
}
|
|
882
906
|
/**
|
|
883
907
|
* Whitelist-only: snapshot MST supply so holders can claim trading fees.
|
|
884
908
|
* Call after oracle resolves the question.
|
|
@@ -894,7 +918,7 @@ var MarketClientV2 = class {
|
|
|
894
918
|
}).transaction();
|
|
895
919
|
}
|
|
896
920
|
};
|
|
897
|
-
var
|
|
921
|
+
var CtfClient = class {
|
|
898
922
|
constructor(program, provider, programIds) {
|
|
899
923
|
this.program = program;
|
|
900
924
|
this.provider = provider;
|
|
@@ -1483,8 +1507,8 @@ function _detectMatchType(a, b) {
|
|
|
1483
1507
|
);
|
|
1484
1508
|
}
|
|
1485
1509
|
|
|
1486
|
-
// src/programs/clob
|
|
1487
|
-
var
|
|
1510
|
+
// src/programs/clob.ts
|
|
1511
|
+
var ClobClient = class {
|
|
1488
1512
|
constructor(program, provider, programIds, networkConfig) {
|
|
1489
1513
|
/** Cache: conditionPda.toBase58() → marketOracleVault ATA */
|
|
1490
1514
|
this._marketOracleVaultCache = /* @__PURE__ */ new Map();
|
|
@@ -1692,8 +1716,8 @@ var ClobClientV2 = class {
|
|
|
1692
1716
|
async _sendLegacyTxSig(instructions) {
|
|
1693
1717
|
const { connection } = this.provider;
|
|
1694
1718
|
const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash();
|
|
1695
|
-
const { Transaction:
|
|
1696
|
-
const tx = new
|
|
1719
|
+
const { Transaction: Transaction12 } = await import('@solana/web3.js');
|
|
1720
|
+
const tx = new Transaction12();
|
|
1697
1721
|
tx.recentBlockhash = blockhash;
|
|
1698
1722
|
tx.feePayer = this.walletPubkey;
|
|
1699
1723
|
tx.add(...instructions);
|
|
@@ -1719,10 +1743,10 @@ ${logs.join("\n")}`);
|
|
|
1719
1743
|
connection.getAccountInfo(clobYesAta),
|
|
1720
1744
|
connection.getAccountInfo(clobNoAta)
|
|
1721
1745
|
]);
|
|
1722
|
-
const { createAssociatedTokenAccountIdempotentInstruction:
|
|
1746
|
+
const { createAssociatedTokenAccountIdempotentInstruction: createAssociatedTokenAccountIdempotentInstruction5 } = await import('@solana/spl-token');
|
|
1723
1747
|
const ixs = [];
|
|
1724
1748
|
if (!yesInfo) {
|
|
1725
|
-
ixs.push(
|
|
1749
|
+
ixs.push(createAssociatedTokenAccountIdempotentInstruction5(
|
|
1726
1750
|
this.walletPubkey,
|
|
1727
1751
|
clobYesAta,
|
|
1728
1752
|
clobConfig,
|
|
@@ -1731,7 +1755,7 @@ ${logs.join("\n")}`);
|
|
|
1731
1755
|
));
|
|
1732
1756
|
}
|
|
1733
1757
|
if (!noInfo) {
|
|
1734
|
-
ixs.push(
|
|
1758
|
+
ixs.push(createAssociatedTokenAccountIdempotentInstruction5(
|
|
1735
1759
|
this.walletPubkey,
|
|
1736
1760
|
clobNoAta,
|
|
1737
1761
|
clobConfig,
|
|
@@ -3725,75 +3749,97 @@ var DisputeClient = class {
|
|
|
3725
3749
|
|
|
3726
3750
|
// src/idls/oracle.json
|
|
3727
3751
|
var oracle_default = {
|
|
3728
|
-
address: "
|
|
3752
|
+
address: "JE3iUvfv2DjhHnEqf2cFtzMtqn1AYQ5s32e1fzkL6KTo",
|
|
3729
3753
|
metadata: {
|
|
3730
|
-
name: "
|
|
3754
|
+
name: "oracle_v2",
|
|
3731
3755
|
version: "0.1.0",
|
|
3732
3756
|
spec: "0.1.0",
|
|
3733
3757
|
description: "Oracle program for XMarket prediction platform"
|
|
3734
3758
|
},
|
|
3735
3759
|
instructions: [
|
|
3736
3760
|
{
|
|
3737
|
-
name: "
|
|
3761
|
+
name: "add_reporter",
|
|
3738
3762
|
docs: [
|
|
3739
|
-
"Add
|
|
3763
|
+
"Add a new reporter to the oracle whitelist"
|
|
3740
3764
|
],
|
|
3741
3765
|
discriminator: [
|
|
3742
|
-
|
|
3743
|
-
|
|
3744
|
-
|
|
3745
|
-
|
|
3746
|
-
|
|
3747
|
-
|
|
3748
|
-
|
|
3749
|
-
|
|
3766
|
+
158,
|
|
3767
|
+
153,
|
|
3768
|
+
12,
|
|
3769
|
+
6,
|
|
3770
|
+
217,
|
|
3771
|
+
41,
|
|
3772
|
+
252,
|
|
3773
|
+
157
|
|
3750
3774
|
],
|
|
3751
3775
|
accounts: [
|
|
3752
3776
|
{
|
|
3753
3777
|
name: "authority",
|
|
3754
|
-
|
|
3755
|
-
|
|
3756
|
-
|
|
3757
|
-
name: "payer",
|
|
3778
|
+
docs: [
|
|
3779
|
+
"Admin or owner who can add reporters"
|
|
3780
|
+
],
|
|
3758
3781
|
writable: true,
|
|
3759
3782
|
signer: true
|
|
3760
3783
|
},
|
|
3761
3784
|
{
|
|
3762
3785
|
name: "oracle_config",
|
|
3786
|
+
docs: [
|
|
3787
|
+
"The oracle configuration"
|
|
3788
|
+
],
|
|
3789
|
+
writable: true
|
|
3790
|
+
},
|
|
3791
|
+
{
|
|
3792
|
+
name: "reporter_address",
|
|
3793
|
+
docs: [
|
|
3794
|
+
"The address being whitelisted as a reporter"
|
|
3795
|
+
]
|
|
3796
|
+
},
|
|
3797
|
+
{
|
|
3798
|
+
name: "reporter",
|
|
3799
|
+
docs: [
|
|
3800
|
+
"The reporter account (PDA)"
|
|
3801
|
+
],
|
|
3763
3802
|
writable: true,
|
|
3764
3803
|
pda: {
|
|
3765
3804
|
seeds: [
|
|
3766
3805
|
{
|
|
3767
3806
|
kind: "const",
|
|
3768
3807
|
value: [
|
|
3769
|
-
|
|
3808
|
+
114,
|
|
3809
|
+
101,
|
|
3810
|
+
112,
|
|
3770
3811
|
111,
|
|
3771
|
-
|
|
3772
|
-
|
|
3773
|
-
|
|
3774
|
-
|
|
3812
|
+
114,
|
|
3813
|
+
116,
|
|
3814
|
+
101,
|
|
3815
|
+
114
|
|
3775
3816
|
]
|
|
3776
3817
|
},
|
|
3777
3818
|
{
|
|
3778
3819
|
kind: "account",
|
|
3779
|
-
path: "oracle_config
|
|
3780
|
-
|
|
3820
|
+
path: "oracle_config"
|
|
3821
|
+
},
|
|
3822
|
+
{
|
|
3823
|
+
kind: "account",
|
|
3824
|
+
path: "reporter_address"
|
|
3781
3825
|
}
|
|
3782
3826
|
]
|
|
3783
3827
|
}
|
|
3784
|
-
}
|
|
3785
|
-
],
|
|
3786
|
-
args: [
|
|
3828
|
+
},
|
|
3787
3829
|
{
|
|
3788
|
-
name: "
|
|
3789
|
-
|
|
3830
|
+
name: "system_program",
|
|
3831
|
+
docs: [
|
|
3832
|
+
"System program for account creation"
|
|
3833
|
+
],
|
|
3834
|
+
address: "11111111111111111111111111111111"
|
|
3790
3835
|
}
|
|
3791
|
-
]
|
|
3836
|
+
],
|
|
3837
|
+
args: []
|
|
3792
3838
|
},
|
|
3793
3839
|
{
|
|
3794
3840
|
name: "initialize",
|
|
3795
3841
|
docs: [
|
|
3796
|
-
"Initialize a new Oracle configuration
|
|
3842
|
+
"Initialize a new Oracle configuration"
|
|
3797
3843
|
],
|
|
3798
3844
|
discriminator: [
|
|
3799
3845
|
175,
|
|
@@ -3849,7 +3895,7 @@ var oracle_default = {
|
|
|
3849
3895
|
{
|
|
3850
3896
|
name: "pause",
|
|
3851
3897
|
docs: [
|
|
3852
|
-
"Pause or unpause the oracle
|
|
3898
|
+
"Pause or unpause the oracle"
|
|
3853
3899
|
],
|
|
3854
3900
|
discriminator: [
|
|
3855
3901
|
211,
|
|
@@ -3869,11 +3915,6 @@ var oracle_default = {
|
|
|
3869
3915
|
],
|
|
3870
3916
|
signer: true
|
|
3871
3917
|
},
|
|
3872
|
-
{
|
|
3873
|
-
name: "payer",
|
|
3874
|
-
writable: true,
|
|
3875
|
-
signer: true
|
|
3876
|
-
},
|
|
3877
3918
|
{
|
|
3878
3919
|
name: "oracle_config",
|
|
3879
3920
|
docs: [
|
|
@@ -3890,67 +3931,82 @@ var oracle_default = {
|
|
|
3890
3931
|
]
|
|
3891
3932
|
},
|
|
3892
3933
|
{
|
|
3893
|
-
name: "
|
|
3934
|
+
name: "remove_reporter",
|
|
3894
3935
|
docs: [
|
|
3895
|
-
"Remove
|
|
3936
|
+
"Remove (deactivate) a reporter from the oracle whitelist"
|
|
3896
3937
|
],
|
|
3897
3938
|
discriminator: [
|
|
3898
|
-
|
|
3899
|
-
|
|
3900
|
-
|
|
3901
|
-
|
|
3902
|
-
|
|
3903
|
-
|
|
3904
|
-
|
|
3905
|
-
|
|
3939
|
+
165,
|
|
3940
|
+
229,
|
|
3941
|
+
140,
|
|
3942
|
+
210,
|
|
3943
|
+
40,
|
|
3944
|
+
24,
|
|
3945
|
+
27,
|
|
3946
|
+
34
|
|
3906
3947
|
],
|
|
3907
3948
|
accounts: [
|
|
3908
3949
|
{
|
|
3909
3950
|
name: "authority",
|
|
3951
|
+
docs: [
|
|
3952
|
+
"Admin or owner who can remove reporters"
|
|
3953
|
+
],
|
|
3910
3954
|
signer: true
|
|
3911
3955
|
},
|
|
3912
3956
|
{
|
|
3913
|
-
name: "
|
|
3914
|
-
|
|
3915
|
-
|
|
3957
|
+
name: "oracle_config",
|
|
3958
|
+
docs: [
|
|
3959
|
+
"The oracle configuration"
|
|
3960
|
+
],
|
|
3961
|
+
writable: true
|
|
3916
3962
|
},
|
|
3917
3963
|
{
|
|
3918
|
-
name: "
|
|
3964
|
+
name: "reporter_address",
|
|
3965
|
+
docs: [
|
|
3966
|
+
"The address being removed as a reporter"
|
|
3967
|
+
]
|
|
3968
|
+
},
|
|
3969
|
+
{
|
|
3970
|
+
name: "reporter",
|
|
3971
|
+
docs: [
|
|
3972
|
+
"The reporter account (PDA)"
|
|
3973
|
+
],
|
|
3919
3974
|
writable: true,
|
|
3920
3975
|
pda: {
|
|
3921
3976
|
seeds: [
|
|
3922
3977
|
{
|
|
3923
3978
|
kind: "const",
|
|
3924
3979
|
value: [
|
|
3925
|
-
|
|
3980
|
+
114,
|
|
3981
|
+
101,
|
|
3982
|
+
112,
|
|
3926
3983
|
111,
|
|
3927
|
-
|
|
3928
|
-
|
|
3929
|
-
|
|
3930
|
-
|
|
3984
|
+
114,
|
|
3985
|
+
116,
|
|
3986
|
+
101,
|
|
3987
|
+
114
|
|
3931
3988
|
]
|
|
3932
3989
|
},
|
|
3933
3990
|
{
|
|
3934
3991
|
kind: "account",
|
|
3935
|
-
path: "oracle_config
|
|
3936
|
-
|
|
3992
|
+
path: "oracle_config"
|
|
3993
|
+
},
|
|
3994
|
+
{
|
|
3995
|
+
kind: "account",
|
|
3996
|
+
path: "reporter_address"
|
|
3937
3997
|
}
|
|
3938
3998
|
]
|
|
3939
3999
|
}
|
|
3940
4000
|
}
|
|
3941
4001
|
],
|
|
3942
|
-
args: [
|
|
3943
|
-
{
|
|
3944
|
-
name: "address",
|
|
3945
|
-
type: "pubkey"
|
|
3946
|
-
}
|
|
3947
|
-
]
|
|
4002
|
+
args: []
|
|
3948
4003
|
},
|
|
3949
4004
|
{
|
|
3950
4005
|
name: "resolve_question",
|
|
3951
4006
|
docs: [
|
|
3952
|
-
"Resolve a question \u2014 whitelisted
|
|
3953
|
-
"
|
|
4007
|
+
"Resolve a question \u2014 called by whitelisted reporter",
|
|
4008
|
+
"Creates a QuestionResult PDA with the payout vector.",
|
|
4009
|
+
"QuestionMarket reads this to finalize the condition."
|
|
3954
4010
|
],
|
|
3955
4011
|
discriminator: [
|
|
3956
4012
|
52,
|
|
@@ -3964,43 +4020,23 @@ var oracle_default = {
|
|
|
3964
4020
|
],
|
|
3965
4021
|
accounts: [
|
|
3966
4022
|
{
|
|
3967
|
-
name: "
|
|
4023
|
+
name: "reporter_signer",
|
|
3968
4024
|
docs: [
|
|
3969
|
-
"
|
|
4025
|
+
"The reporter resolving this question"
|
|
3970
4026
|
],
|
|
3971
4027
|
signer: true
|
|
3972
4028
|
},
|
|
3973
4029
|
{
|
|
3974
4030
|
name: "oracle_config",
|
|
3975
4031
|
docs: [
|
|
3976
|
-
"
|
|
4032
|
+
"The oracle configuration"
|
|
3977
4033
|
],
|
|
3978
|
-
writable: true
|
|
3979
|
-
pda: {
|
|
3980
|
-
seeds: [
|
|
3981
|
-
{
|
|
3982
|
-
kind: "const",
|
|
3983
|
-
value: [
|
|
3984
|
-
99,
|
|
3985
|
-
111,
|
|
3986
|
-
110,
|
|
3987
|
-
102,
|
|
3988
|
-
105,
|
|
3989
|
-
103
|
|
3990
|
-
]
|
|
3991
|
-
},
|
|
3992
|
-
{
|
|
3993
|
-
kind: "account",
|
|
3994
|
-
path: "oracle_config.owner",
|
|
3995
|
-
account: "OracleConfig"
|
|
3996
|
-
}
|
|
3997
|
-
]
|
|
3998
|
-
}
|
|
4034
|
+
writable: true
|
|
3999
4035
|
},
|
|
4000
4036
|
{
|
|
4001
|
-
name: "
|
|
4037
|
+
name: "reporter",
|
|
4002
4038
|
docs: [
|
|
4003
|
-
"
|
|
4039
|
+
"The reporter account (must be whitelisted and active)"
|
|
4004
4040
|
],
|
|
4005
4041
|
writable: true,
|
|
4006
4042
|
pda: {
|
|
@@ -4010,10 +4046,12 @@ var oracle_default = {
|
|
|
4010
4046
|
value: [
|
|
4011
4047
|
114,
|
|
4012
4048
|
101,
|
|
4013
|
-
|
|
4014
|
-
|
|
4015
|
-
|
|
4016
|
-
116
|
|
4049
|
+
112,
|
|
4050
|
+
111,
|
|
4051
|
+
114,
|
|
4052
|
+
116,
|
|
4053
|
+
101,
|
|
4054
|
+
114
|
|
4017
4055
|
]
|
|
4018
4056
|
},
|
|
4019
4057
|
{
|
|
@@ -4021,16 +4059,16 @@ var oracle_default = {
|
|
|
4021
4059
|
path: "oracle_config"
|
|
4022
4060
|
},
|
|
4023
4061
|
{
|
|
4024
|
-
kind: "
|
|
4025
|
-
path: "
|
|
4062
|
+
kind: "account",
|
|
4063
|
+
path: "reporter_signer"
|
|
4026
4064
|
}
|
|
4027
4065
|
]
|
|
4028
4066
|
}
|
|
4029
4067
|
},
|
|
4030
4068
|
{
|
|
4031
|
-
name: "
|
|
4069
|
+
name: "question_result",
|
|
4032
4070
|
docs: [
|
|
4033
|
-
"
|
|
4071
|
+
"The question result account (PDA) - stores the resolution"
|
|
4034
4072
|
],
|
|
4035
4073
|
writable: true,
|
|
4036
4074
|
pda: {
|
|
@@ -4038,15 +4076,12 @@ var oracle_default = {
|
|
|
4038
4076
|
{
|
|
4039
4077
|
kind: "const",
|
|
4040
4078
|
value: [
|
|
4041
|
-
|
|
4042
|
-
|
|
4043
|
-
|
|
4044
|
-
|
|
4045
|
-
|
|
4046
|
-
116
|
|
4047
|
-
105,
|
|
4048
|
-
111,
|
|
4049
|
-
110
|
|
4079
|
+
114,
|
|
4080
|
+
101,
|
|
4081
|
+
115,
|
|
4082
|
+
117,
|
|
4083
|
+
108,
|
|
4084
|
+
116
|
|
4050
4085
|
]
|
|
4051
4086
|
},
|
|
4052
4087
|
{
|
|
@@ -4057,29 +4092,22 @@ var oracle_default = {
|
|
|
4057
4092
|
kind: "arg",
|
|
4058
4093
|
path: "question_id"
|
|
4059
4094
|
}
|
|
4060
|
-
]
|
|
4061
|
-
program: {
|
|
4062
|
-
kind: "account",
|
|
4063
|
-
path: "conditional_tokens_program"
|
|
4064
|
-
}
|
|
4095
|
+
]
|
|
4065
4096
|
}
|
|
4066
4097
|
},
|
|
4067
|
-
{
|
|
4068
|
-
name: "conditional_tokens_program",
|
|
4069
|
-
docs: [
|
|
4070
|
-
"ConditionalTokens program"
|
|
4071
|
-
]
|
|
4072
|
-
},
|
|
4073
4098
|
{
|
|
4074
4099
|
name: "payer",
|
|
4075
4100
|
docs: [
|
|
4076
|
-
"Payer for
|
|
4101
|
+
"Payer for account creation"
|
|
4077
4102
|
],
|
|
4078
4103
|
writable: true,
|
|
4079
4104
|
signer: true
|
|
4080
4105
|
},
|
|
4081
4106
|
{
|
|
4082
4107
|
name: "system_program",
|
|
4108
|
+
docs: [
|
|
4109
|
+
"System program for account creation"
|
|
4110
|
+
],
|
|
4083
4111
|
address: "11111111111111111111111111111111"
|
|
4084
4112
|
}
|
|
4085
4113
|
],
|
|
@@ -4146,7 +4174,7 @@ var oracle_default = {
|
|
|
4146
4174
|
{
|
|
4147
4175
|
name: "update_admin",
|
|
4148
4176
|
docs: [
|
|
4149
|
-
"Update the admin of the oracle
|
|
4177
|
+
"Update the admin of the oracle"
|
|
4150
4178
|
],
|
|
4151
4179
|
discriminator: [
|
|
4152
4180
|
161,
|
|
@@ -4166,11 +4194,6 @@ var oracle_default = {
|
|
|
4166
4194
|
],
|
|
4167
4195
|
signer: true
|
|
4168
4196
|
},
|
|
4169
|
-
{
|
|
4170
|
-
name: "payer",
|
|
4171
|
-
writable: true,
|
|
4172
|
-
signer: true
|
|
4173
|
-
},
|
|
4174
4197
|
{
|
|
4175
4198
|
name: "oracle_config",
|
|
4176
4199
|
docs: [
|
|
@@ -4213,72 +4236,81 @@ var oracle_default = {
|
|
|
4213
4236
|
254,
|
|
4214
4237
|
226
|
|
4215
4238
|
]
|
|
4239
|
+
},
|
|
4240
|
+
{
|
|
4241
|
+
name: "Reporter",
|
|
4242
|
+
discriminator: [
|
|
4243
|
+
233,
|
|
4244
|
+
37,
|
|
4245
|
+
148,
|
|
4246
|
+
250,
|
|
4247
|
+
155,
|
|
4248
|
+
158,
|
|
4249
|
+
118,
|
|
4250
|
+
161
|
|
4251
|
+
]
|
|
4216
4252
|
}
|
|
4217
4253
|
],
|
|
4218
|
-
|
|
4219
|
-
{
|
|
4220
|
-
name: "WhitelistUpdated",
|
|
4221
|
-
discriminator: [
|
|
4222
|
-
205,
|
|
4223
|
-
110,
|
|
4224
|
-
205,
|
|
4225
|
-
193,
|
|
4226
|
-
238,
|
|
4227
|
-
237,
|
|
4228
|
-
220,
|
|
4229
|
-
22
|
|
4230
|
-
]
|
|
4231
|
-
}
|
|
4232
|
-
],
|
|
4233
|
-
types: [
|
|
4254
|
+
types: [
|
|
4234
4255
|
{
|
|
4235
4256
|
name: "OracleConfig",
|
|
4257
|
+
docs: [
|
|
4258
|
+
"Global configuration for the Oracle program"
|
|
4259
|
+
],
|
|
4236
4260
|
type: {
|
|
4237
4261
|
kind: "struct",
|
|
4238
4262
|
fields: [
|
|
4239
|
-
{
|
|
4240
|
-
name: "version",
|
|
4241
|
-
type: "u8"
|
|
4242
|
-
},
|
|
4243
4263
|
{
|
|
4244
4264
|
name: "owner",
|
|
4265
|
+
docs: [
|
|
4266
|
+
"Owner of the oracle (can transfer ownership)"
|
|
4267
|
+
],
|
|
4245
4268
|
type: "pubkey"
|
|
4246
4269
|
},
|
|
4247
4270
|
{
|
|
4248
4271
|
name: "admin",
|
|
4272
|
+
docs: [
|
|
4273
|
+
"Admin who can add/remove reporters"
|
|
4274
|
+
],
|
|
4249
4275
|
type: "pubkey"
|
|
4250
4276
|
},
|
|
4251
4277
|
{
|
|
4252
4278
|
name: "question_count",
|
|
4279
|
+
docs: [
|
|
4280
|
+
"Total number of questions resolved through this oracle"
|
|
4281
|
+
],
|
|
4253
4282
|
type: "u64"
|
|
4254
4283
|
},
|
|
4255
4284
|
{
|
|
4256
|
-
name: "
|
|
4257
|
-
|
|
4258
|
-
|
|
4259
|
-
|
|
4260
|
-
|
|
4261
|
-
]
|
|
4262
|
-
}
|
|
4263
|
-
},
|
|
4264
|
-
{
|
|
4265
|
-
name: "whitelist_len",
|
|
4266
|
-
type: "u8"
|
|
4285
|
+
name: "reporter_count",
|
|
4286
|
+
docs: [
|
|
4287
|
+
"Total number of active reporters"
|
|
4288
|
+
],
|
|
4289
|
+
type: "u64"
|
|
4267
4290
|
},
|
|
4268
4291
|
{
|
|
4269
4292
|
name: "is_paused",
|
|
4293
|
+
docs: [
|
|
4294
|
+
"Whether the oracle is paused"
|
|
4295
|
+
],
|
|
4270
4296
|
type: "bool"
|
|
4271
4297
|
},
|
|
4272
4298
|
{
|
|
4273
4299
|
name: "bump",
|
|
4300
|
+
docs: [
|
|
4301
|
+
"Bump seed for PDA derivation"
|
|
4302
|
+
],
|
|
4274
4303
|
type: "u8"
|
|
4275
4304
|
},
|
|
4276
4305
|
{
|
|
4277
4306
|
name: "_reserved",
|
|
4307
|
+
docs: [
|
|
4308
|
+
"Reserved space for future upgrades"
|
|
4309
|
+
],
|
|
4278
4310
|
type: {
|
|
4279
4311
|
array: [
|
|
4280
4312
|
"u8",
|
|
4281
|
-
|
|
4313
|
+
64
|
|
4282
4314
|
]
|
|
4283
4315
|
}
|
|
4284
4316
|
}
|
|
@@ -4287,19 +4319,24 @@ var oracle_default = {
|
|
|
4287
4319
|
},
|
|
4288
4320
|
{
|
|
4289
4321
|
name: "QuestionResult",
|
|
4322
|
+
docs: [
|
|
4323
|
+
"Stores the resolution result for a question"
|
|
4324
|
+
],
|
|
4290
4325
|
type: {
|
|
4291
4326
|
kind: "struct",
|
|
4292
4327
|
fields: [
|
|
4293
|
-
{
|
|
4294
|
-
name: "version",
|
|
4295
|
-
type: "u8"
|
|
4296
|
-
},
|
|
4297
4328
|
{
|
|
4298
4329
|
name: "oracle_config",
|
|
4330
|
+
docs: [
|
|
4331
|
+
"The oracle config that resolved this question"
|
|
4332
|
+
],
|
|
4299
4333
|
type: "pubkey"
|
|
4300
4334
|
},
|
|
4301
4335
|
{
|
|
4302
4336
|
name: "question_id",
|
|
4337
|
+
docs: [
|
|
4338
|
+
"Unique identifier for the question (32-byte hash)"
|
|
4339
|
+
],
|
|
4303
4340
|
type: {
|
|
4304
4341
|
array: [
|
|
4305
4342
|
"u8",
|
|
@@ -4309,78 +4346,125 @@ var oracle_default = {
|
|
|
4309
4346
|
},
|
|
4310
4347
|
{
|
|
4311
4348
|
name: "outcome_index",
|
|
4349
|
+
docs: [
|
|
4350
|
+
"Which outcome won (for binary: 0=NO, 1=YES)"
|
|
4351
|
+
],
|
|
4312
4352
|
type: "u8"
|
|
4313
4353
|
},
|
|
4314
4354
|
{
|
|
4315
4355
|
name: "outcome_count",
|
|
4356
|
+
docs: [
|
|
4357
|
+
"Number of outcomes in this question"
|
|
4358
|
+
],
|
|
4316
4359
|
type: "u8"
|
|
4317
4360
|
},
|
|
4318
4361
|
{
|
|
4319
4362
|
name: "payout_numerators",
|
|
4320
4363
|
docs: [
|
|
4321
|
-
"
|
|
4364
|
+
"Full payout vector representing the payout ratios",
|
|
4365
|
+
"For binary YES win: [0, 1], for NO win: [1, 0]",
|
|
4366
|
+
"For multi-outcome: [0, 0, 1, 0] means outcome 2 won"
|
|
4322
4367
|
],
|
|
4323
4368
|
type: {
|
|
4324
|
-
|
|
4325
|
-
"u64",
|
|
4326
|
-
8
|
|
4327
|
-
]
|
|
4369
|
+
vec: "u64"
|
|
4328
4370
|
}
|
|
4329
4371
|
},
|
|
4330
4372
|
{
|
|
4331
4373
|
name: "is_resolved",
|
|
4374
|
+
docs: [
|
|
4375
|
+
"Whether the question has been resolved"
|
|
4376
|
+
],
|
|
4332
4377
|
type: "bool"
|
|
4333
4378
|
},
|
|
4334
4379
|
{
|
|
4335
4380
|
name: "resolved_at",
|
|
4381
|
+
docs: [
|
|
4382
|
+
"Timestamp when the question was resolved"
|
|
4383
|
+
],
|
|
4336
4384
|
type: "i64"
|
|
4337
4385
|
},
|
|
4338
4386
|
{
|
|
4339
4387
|
name: "reporter",
|
|
4388
|
+
docs: [
|
|
4389
|
+
"The reporter who resolved this question"
|
|
4390
|
+
],
|
|
4340
4391
|
type: "pubkey"
|
|
4341
4392
|
},
|
|
4342
4393
|
{
|
|
4343
4394
|
name: "condition",
|
|
4395
|
+
docs: [
|
|
4396
|
+
"Optional link to ConditionalTokens condition (if resolved via CPI)"
|
|
4397
|
+
],
|
|
4344
4398
|
type: {
|
|
4345
4399
|
option: "pubkey"
|
|
4346
4400
|
}
|
|
4347
4401
|
},
|
|
4348
4402
|
{
|
|
4349
4403
|
name: "bump",
|
|
4404
|
+
docs: [
|
|
4405
|
+
"Bump seed for PDA derivation"
|
|
4406
|
+
],
|
|
4350
4407
|
type: "u8"
|
|
4351
|
-
},
|
|
4352
|
-
{
|
|
4353
|
-
name: "_reserved",
|
|
4354
|
-
type: {
|
|
4355
|
-
array: [
|
|
4356
|
-
"u8",
|
|
4357
|
-
64
|
|
4358
|
-
]
|
|
4359
|
-
}
|
|
4360
4408
|
}
|
|
4361
4409
|
]
|
|
4362
4410
|
}
|
|
4363
4411
|
},
|
|
4364
4412
|
{
|
|
4365
|
-
name: "
|
|
4413
|
+
name: "Reporter",
|
|
4414
|
+
docs: [
|
|
4415
|
+
"Represents a whitelisted reporter who can resolve questions"
|
|
4416
|
+
],
|
|
4366
4417
|
type: {
|
|
4367
4418
|
kind: "struct",
|
|
4368
4419
|
fields: [
|
|
4369
4420
|
{
|
|
4370
4421
|
name: "oracle_config",
|
|
4422
|
+
docs: [
|
|
4423
|
+
"The oracle config this reporter belongs to"
|
|
4424
|
+
],
|
|
4371
4425
|
type: "pubkey"
|
|
4372
4426
|
},
|
|
4373
4427
|
{
|
|
4374
|
-
name: "
|
|
4428
|
+
name: "reporter",
|
|
4429
|
+
docs: [
|
|
4430
|
+
"The reporter's public key"
|
|
4431
|
+
],
|
|
4375
4432
|
type: "pubkey"
|
|
4376
4433
|
},
|
|
4377
4434
|
{
|
|
4378
|
-
name: "
|
|
4435
|
+
name: "is_active",
|
|
4436
|
+
docs: [
|
|
4437
|
+
"Whether the reporter is currently active"
|
|
4438
|
+
],
|
|
4379
4439
|
type: "bool"
|
|
4380
4440
|
},
|
|
4381
4441
|
{
|
|
4382
|
-
name: "
|
|
4383
|
-
|
|
4442
|
+
name: "questions_reported",
|
|
4443
|
+
docs: [
|
|
4444
|
+
"Number of questions this reporter has resolved"
|
|
4445
|
+
],
|
|
4446
|
+
type: "u64"
|
|
4447
|
+
},
|
|
4448
|
+
{
|
|
4449
|
+
name: "added_at",
|
|
4450
|
+
docs: [
|
|
4451
|
+
"Timestamp when the reporter was added"
|
|
4452
|
+
],
|
|
4453
|
+
type: "i64"
|
|
4454
|
+
},
|
|
4455
|
+
{
|
|
4456
|
+
name: "last_updated",
|
|
4457
|
+
docs: [
|
|
4458
|
+
"Timestamp when the reporter was last updated"
|
|
4459
|
+
],
|
|
4460
|
+
type: "i64"
|
|
4461
|
+
},
|
|
4462
|
+
{
|
|
4463
|
+
name: "bump",
|
|
4464
|
+
docs: [
|
|
4465
|
+
"Bump seed for PDA derivation"
|
|
4466
|
+
],
|
|
4467
|
+
type: "u8"
|
|
4384
4468
|
}
|
|
4385
4469
|
]
|
|
4386
4470
|
}
|
|
@@ -4388,8 +4472,8 @@ var oracle_default = {
|
|
|
4388
4472
|
]
|
|
4389
4473
|
};
|
|
4390
4474
|
|
|
4391
|
-
// src/idls/
|
|
4392
|
-
var
|
|
4475
|
+
// src/idls/question_market.json
|
|
4476
|
+
var question_market_default = {
|
|
4393
4477
|
address: "6aYGVgSPNgFxNB9f25UvKrzMs91cGh7urNZKdtnMUm6k",
|
|
4394
4478
|
metadata: {
|
|
4395
4479
|
name: "question_market_v2",
|
|
@@ -4724,19 +4808,19 @@ var question_market_v2_default = {
|
|
|
4724
4808
|
},
|
|
4725
4809
|
{
|
|
4726
4810
|
name: "fee_management_program",
|
|
4727
|
-
address: "
|
|
4811
|
+
address: "HZ5ec3NbwceUfyzZkwGEzDxQHpr4p4L9JV1gmcPDyXYw"
|
|
4728
4812
|
},
|
|
4729
4813
|
{
|
|
4730
4814
|
name: "presale_program",
|
|
4731
|
-
address: "
|
|
4815
|
+
address: "H9GzTEu5giM1k9HJm126Pp6C6b3iKWahbF7RJj8Jr3zJ"
|
|
4732
4816
|
},
|
|
4733
4817
|
{
|
|
4734
4818
|
name: "market_oracle_program",
|
|
4735
|
-
address: "
|
|
4819
|
+
address: "4o7VyLGV79AynuTjTxDvsUfZKS11bX5SkSsk5zHKVovG"
|
|
4736
4820
|
},
|
|
4737
4821
|
{
|
|
4738
4822
|
name: "admin_program",
|
|
4739
|
-
address: "
|
|
4823
|
+
address: "3E2b2H3ZDMXjqQ1VKDz8zsVXWdRaH5Mjdd7qFB13Uejn"
|
|
4740
4824
|
},
|
|
4741
4825
|
{
|
|
4742
4826
|
name: "token_program",
|
|
@@ -4998,11 +5082,11 @@ var question_market_v2_default = {
|
|
|
4998
5082
|
},
|
|
4999
5083
|
{
|
|
5000
5084
|
name: "presale_program",
|
|
5001
|
-
address: "
|
|
5085
|
+
address: "H9GzTEu5giM1k9HJm126Pp6C6b3iKWahbF7RJj8Jr3zJ"
|
|
5002
5086
|
},
|
|
5003
5087
|
{
|
|
5004
5088
|
name: "admin_program",
|
|
5005
|
-
address: "
|
|
5089
|
+
address: "3E2b2H3ZDMXjqQ1VKDz8zsVXWdRaH5Mjdd7qFB13Uejn"
|
|
5006
5090
|
},
|
|
5007
5091
|
{
|
|
5008
5092
|
name: "token_program",
|
|
@@ -5084,7 +5168,7 @@ var question_market_v2_default = {
|
|
|
5084
5168
|
},
|
|
5085
5169
|
{
|
|
5086
5170
|
name: "market_oracle_program",
|
|
5087
|
-
address: "
|
|
5171
|
+
address: "4o7VyLGV79AynuTjTxDvsUfZKS11bX5SkSsk5zHKVovG"
|
|
5088
5172
|
}
|
|
5089
5173
|
],
|
|
5090
5174
|
args: []
|
|
@@ -5312,7 +5396,7 @@ var question_market_v2_default = {
|
|
|
5312
5396
|
},
|
|
5313
5397
|
{
|
|
5314
5398
|
name: "presale_program",
|
|
5315
|
-
address: "
|
|
5399
|
+
address: "H9GzTEu5giM1k9HJm126Pp6C6b3iKWahbF7RJj8Jr3zJ"
|
|
5316
5400
|
},
|
|
5317
5401
|
{
|
|
5318
5402
|
name: "token_program",
|
|
@@ -5448,7 +5532,7 @@ var question_market_v2_default = {
|
|
|
5448
5532
|
},
|
|
5449
5533
|
{
|
|
5450
5534
|
name: "fee_management_program",
|
|
5451
|
-
address: "
|
|
5535
|
+
address: "HZ5ec3NbwceUfyzZkwGEzDxQHpr4p4L9JV1gmcPDyXYw"
|
|
5452
5536
|
},
|
|
5453
5537
|
{
|
|
5454
5538
|
name: "token_program",
|
|
@@ -5641,7 +5725,7 @@ var question_market_v2_default = {
|
|
|
5641
5725
|
},
|
|
5642
5726
|
{
|
|
5643
5727
|
name: "presale_program",
|
|
5644
|
-
address: "
|
|
5728
|
+
address: "H9GzTEu5giM1k9HJm126Pp6C6b3iKWahbF7RJj8Jr3zJ"
|
|
5645
5729
|
}
|
|
5646
5730
|
],
|
|
5647
5731
|
args: []
|
|
@@ -7247,8 +7331,8 @@ var question_market_v2_default = {
|
|
|
7247
7331
|
]
|
|
7248
7332
|
};
|
|
7249
7333
|
|
|
7250
|
-
// src/idls/
|
|
7251
|
-
var
|
|
7334
|
+
// src/idls/conditional_tokens.json
|
|
7335
|
+
var conditional_tokens_default = {
|
|
7252
7336
|
address: "3f4vBEgXo9y4Ndrn8KWnNpLLtt4VAGkmKWqXpGS1BLDB",
|
|
7253
7337
|
metadata: {
|
|
7254
7338
|
name: "conditional_tokens_v2",
|
|
@@ -8950,8 +9034,8 @@ var conditional_tokens_v2_default = {
|
|
|
8950
9034
|
]
|
|
8951
9035
|
};
|
|
8952
9036
|
|
|
8953
|
-
// src/idls/
|
|
8954
|
-
var
|
|
9037
|
+
// src/idls/clob_exchange.json
|
|
9038
|
+
var clob_exchange_default = {
|
|
8955
9039
|
address: "43ubx86ZnGJ4bzD8uZY91uoUzJdK2jULwSSVk8zHjzEY",
|
|
8956
9040
|
metadata: {
|
|
8957
9041
|
name: "clob_exchange_v2",
|
|
@@ -17783,8 +17867,8 @@ var dispute_default = {
|
|
|
17783
17867
|
]
|
|
17784
17868
|
};
|
|
17785
17869
|
|
|
17786
|
-
// src/sdk
|
|
17787
|
-
var
|
|
17870
|
+
// src/sdk.ts
|
|
17871
|
+
var XMarketSDK = class {
|
|
17788
17872
|
constructor(config, wallet, marketOwner) {
|
|
17789
17873
|
this.networkConfig = config;
|
|
17790
17874
|
this.provider = new anchor6.AnchorProvider(
|
|
@@ -17806,17 +17890,10 @@ var XMarketSDKV2 = class {
|
|
|
17806
17890
|
}
|
|
17807
17891
|
return this._oracle;
|
|
17808
17892
|
}
|
|
17809
|
-
/**
|
|
17810
|
-
* V2 does not use a hook program — calling this getter throws an error.
|
|
17811
|
-
* The hook is not needed for plain SPL YES/NO mints.
|
|
17812
|
-
*/
|
|
17813
|
-
get hook() {
|
|
17814
|
-
throw new Error("XMarketSDKV2: no hook client \u2014 V2 uses plain SPL token (TOKEN_PROGRAM_ID), no transfer hook.");
|
|
17815
|
-
}
|
|
17816
17893
|
get market() {
|
|
17817
17894
|
if (!this._market) {
|
|
17818
|
-
const program = new anchor6.Program(this._withAddress(
|
|
17819
|
-
this._market = new
|
|
17895
|
+
const program = new anchor6.Program(this._withAddress(question_market_default, this._programIds.questionMarket), this.provider);
|
|
17896
|
+
this._market = new MarketClient(program, this.provider, this._programIds, this._marketOwner);
|
|
17820
17897
|
this._market.ctfClient = this.ctf;
|
|
17821
17898
|
this._market.feeConfigOwner = this.networkConfig.feeConfigOwner ?? this._marketOwner;
|
|
17822
17899
|
}
|
|
@@ -17824,15 +17901,15 @@ var XMarketSDKV2 = class {
|
|
|
17824
17901
|
}
|
|
17825
17902
|
get ctf() {
|
|
17826
17903
|
if (!this._ctf) {
|
|
17827
|
-
const program = new anchor6.Program(this._withAddress(
|
|
17828
|
-
this._ctf = new
|
|
17904
|
+
const program = new anchor6.Program(this._withAddress(conditional_tokens_default, this._programIds.conditionalTokens), this.provider);
|
|
17905
|
+
this._ctf = new CtfClient(program, this.provider, this._programIds);
|
|
17829
17906
|
}
|
|
17830
17907
|
return this._ctf;
|
|
17831
17908
|
}
|
|
17832
17909
|
get clob() {
|
|
17833
17910
|
if (!this._clob) {
|
|
17834
|
-
const program = new anchor6.Program(this._withAddress(
|
|
17835
|
-
this._clob = new
|
|
17911
|
+
const program = new anchor6.Program(this._withAddress(clob_exchange_default, this._programIds.clobExchange), this.provider);
|
|
17912
|
+
this._clob = new ClobClient(program, this.provider, this._programIds, this.networkConfig);
|
|
17836
17913
|
if (this.networkConfig.feeConfigOwner && this._programIds.feeManagement) {
|
|
17837
17914
|
this._clob.feeConfigOwner = this.networkConfig.feeConfigOwner;
|
|
17838
17915
|
this._clob.feeClient = this.fee;
|
|
@@ -17891,2521 +17968,27 @@ var XMarketSDKV2 = class {
|
|
|
17891
17968
|
return this._dispute;
|
|
17892
17969
|
}
|
|
17893
17970
|
};
|
|
17894
|
-
var
|
|
17895
|
-
|
|
17896
|
-
|
|
17897
|
-
|
|
17898
|
-
|
|
17899
|
-
|
|
17900
|
-
|
|
17901
|
-
|
|
17902
|
-
|
|
17903
|
-
|
|
17904
|
-
return PDA.hookConfig(this.programIds)[0];
|
|
17905
|
-
}
|
|
17906
|
-
// ─── Instructions ────────────────────────────────────────────────────────────
|
|
17907
|
-
/** One-time setup. Caller becomes owner. */
|
|
17908
|
-
async initialize(initialWhitelist) {
|
|
17909
|
-
const sig = await this.program.methods.initializeHookConfig(initialWhitelist).accounts({
|
|
17910
|
-
owner: this.walletPubkey,
|
|
17911
|
-
hookConfig: this.configPda(),
|
|
17912
|
-
systemProgram: SystemProgram.programId
|
|
17913
|
-
}).rpc();
|
|
17914
|
-
return { signature: sig };
|
|
17915
|
-
}
|
|
17916
|
-
/**
|
|
17917
|
-
* Returns initializeExtraAccountMetaList instruction if the account doesn't exist yet, else null.
|
|
17918
|
-
* Used by ClobClient to auto-prepend when extraAccountMetaList is missing.
|
|
17919
|
-
*/
|
|
17920
|
-
async buildInitHookIxIfNeeded(mint, payer) {
|
|
17921
|
-
const [extraAccountMetaList] = PDA.extraAccountMetaList(mint, this.programIds);
|
|
17922
|
-
const existing = await this.provider.connection.getAccountInfo(extraAccountMetaList);
|
|
17923
|
-
if (existing) return null;
|
|
17924
|
-
return this.program.methods.initializeExtraAccountMetaList().accounts({
|
|
17925
|
-
payer,
|
|
17926
|
-
extraAccountMetaList,
|
|
17927
|
-
mint,
|
|
17928
|
-
hookConfig: this.configPda(),
|
|
17929
|
-
tokenProgram: TOKEN_2022_PROGRAM_ID,
|
|
17930
|
-
systemProgram: SystemProgram.programId
|
|
17931
|
-
}).instruction();
|
|
17932
|
-
}
|
|
17933
|
-
/**
|
|
17934
|
-
* Register extra account metas for a Token-2022 YES/NO mint.
|
|
17935
|
-
* Must be called once per mint after CTF creates it.
|
|
17936
|
-
*/
|
|
17937
|
-
async initializeExtraAccountMetaList(mint) {
|
|
17938
|
-
const [extraAccountMetaList] = PDA.extraAccountMetaList(mint, this.programIds);
|
|
17939
|
-
const sig = await this.program.methods.initializeExtraAccountMetaList().accounts({
|
|
17940
|
-
payer: this.walletPubkey,
|
|
17941
|
-
extraAccountMetaList,
|
|
17942
|
-
mint,
|
|
17943
|
-
hookConfig: this.configPda(),
|
|
17944
|
-
tokenProgram: TOKEN_2022_PROGRAM_ID,
|
|
17945
|
-
systemProgram: SystemProgram.programId
|
|
17946
|
-
}).rpc();
|
|
17947
|
-
return { signature: sig };
|
|
17948
|
-
}
|
|
17949
|
-
/** Owner adds a program to the transfer whitelist. */
|
|
17950
|
-
async addToWhitelist(program) {
|
|
17951
|
-
const sig = await this.program.methods.addToWhitelist(program).accounts({
|
|
17952
|
-
owner: this.walletPubkey,
|
|
17953
|
-
hookConfig: this.configPda()
|
|
17954
|
-
}).rpc();
|
|
17955
|
-
return { signature: sig };
|
|
17956
|
-
}
|
|
17957
|
-
/** Owner removes a program from the transfer whitelist. */
|
|
17958
|
-
async removeFromWhitelist(program) {
|
|
17959
|
-
const sig = await this.program.methods.removeFromWhitelist(program).accounts({
|
|
17960
|
-
owner: this.walletPubkey,
|
|
17961
|
-
hookConfig: this.configPda()
|
|
17962
|
-
}).rpc();
|
|
17963
|
-
return { signature: sig };
|
|
17964
|
-
}
|
|
17965
|
-
/** Permanently freeze the whitelist — no further changes allowed. */
|
|
17966
|
-
async freezeWhitelist() {
|
|
17967
|
-
const sig = await this.program.methods.freezeWhitelist().accounts({
|
|
17968
|
-
owner: this.walletPubkey,
|
|
17969
|
-
hookConfig: this.configPda()
|
|
17970
|
-
}).rpc();
|
|
17971
|
-
return { signature: sig };
|
|
17972
|
-
}
|
|
17973
|
-
/**
|
|
17974
|
-
* SPL Transfer-Hook `execute` — invoked automatically by Token-2022 on every
|
|
17975
|
-
* YES/NO token transfer. Validates the destination against the whitelist.
|
|
17976
|
-
*
|
|
17977
|
-
* Calling this directly is useful for:
|
|
17978
|
-
* - Off-chain simulation ("would this transfer be allowed?")
|
|
17979
|
-
* - Integration tests that verify whitelist enforcement
|
|
17980
|
-
*
|
|
17981
|
-
* Token-2022 calls this automatically; you normally don't call it manually.
|
|
17982
|
-
*
|
|
17983
|
-
* @param sourceToken - Source token account (tokens leaving)
|
|
17984
|
-
* @param mint - The YES/NO Token-2022 mint
|
|
17985
|
-
* @param destinationToken - Destination token account (tokens arriving)
|
|
17986
|
-
* @param owner - Authority that authorized the transfer
|
|
17987
|
-
* @param amount - Token amount being transferred
|
|
17988
|
-
*/
|
|
17989
|
-
async execute(sourceToken, mint, destinationToken, owner, amount) {
|
|
17990
|
-
const [extraAccountMetaList] = PDA.extraAccountMetaList(mint, this.programIds);
|
|
17991
|
-
const sig = await this.program.methods.execute(amount).accounts({
|
|
17992
|
-
sourceToken,
|
|
17993
|
-
mint,
|
|
17994
|
-
destinationToken,
|
|
17995
|
-
owner,
|
|
17996
|
-
extraAccountMetaList,
|
|
17997
|
-
hookConfig: this.configPda()
|
|
17998
|
-
}).rpc();
|
|
17999
|
-
return { signature: sig };
|
|
18000
|
-
}
|
|
18001
|
-
// ─── Queries ─────────────────────────────────────────────────────────────────
|
|
18002
|
-
async fetchConfig() {
|
|
18003
|
-
try {
|
|
18004
|
-
const acc = await this.program.account.hookConfig.fetch(this.configPda());
|
|
18005
|
-
return {
|
|
18006
|
-
owner: acc.owner,
|
|
18007
|
-
whitelist: acc.whitelist.slice(0, acc.whitelistLen),
|
|
18008
|
-
whitelistLen: acc.whitelistLen,
|
|
18009
|
-
isFrozen: acc.isFrozen,
|
|
18010
|
-
bump: acc.bump
|
|
18011
|
-
};
|
|
18012
|
-
} catch {
|
|
18013
|
-
return null;
|
|
18014
|
-
}
|
|
18015
|
-
}
|
|
18016
|
-
async isWhitelisted(program) {
|
|
18017
|
-
const config = await this.fetchConfig();
|
|
18018
|
-
if (!config) return false;
|
|
18019
|
-
return config.whitelist.some((p) => p.equals(program));
|
|
18020
|
-
}
|
|
18021
|
-
};
|
|
18022
|
-
var TOKEN_METADATA_PROGRAM_ID2 = new PublicKey("metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s");
|
|
18023
|
-
var MarketClient = class {
|
|
18024
|
-
constructor(program, provider, programIds, ownerPubkey) {
|
|
18025
|
-
this.program = program;
|
|
18026
|
-
this.provider = provider;
|
|
18027
|
-
this.programIds = programIds;
|
|
18028
|
-
this.configPda = PDA.questionMarketConfig(ownerPubkey, programIds)[0];
|
|
18029
|
-
}
|
|
18030
|
-
get walletPubkey() {
|
|
18031
|
-
return this.provider.wallet.publicKey;
|
|
18032
|
-
}
|
|
18033
|
-
// ─── Instructions (return Transaction — caller signs + sends) ───────────────
|
|
18034
|
-
async initialize(admin, oracle, owner = this.walletPubkey) {
|
|
18035
|
-
return this.program.methods.initialize({
|
|
18036
|
-
admin,
|
|
18037
|
-
conditionalTokensProgram: this.programIds.conditionalTokens,
|
|
18038
|
-
oracle
|
|
18039
|
-
}).accounts({
|
|
18040
|
-
owner,
|
|
18041
|
-
config: this.configPda,
|
|
18042
|
-
systemProgram: SystemProgram.programId
|
|
18043
|
-
}).transaction();
|
|
18044
|
-
}
|
|
18045
|
-
/**
|
|
18046
|
-
* Build createQuestionAdmin transaction (whitelist/admin path — status = Approved immediately).
|
|
18047
|
-
* @param creator - Whitelisted creator (must be in whitelist or be admin/owner)
|
|
18048
|
-
* @param payer - Fee payer (pays rent; can differ from creator)
|
|
18049
|
-
*/
|
|
18050
|
-
async createQuestionAdmin(params, oracle, creator = this.walletPubkey, payer = this.walletPubkey) {
|
|
18051
|
-
const questionId = params.questionId ?? generateQuestionId(params.content);
|
|
18052
|
-
const contentHash = params.contentHash ?? generateContentHash(params.content);
|
|
18053
|
-
const [questionPda] = PDA.question(this.configPda, questionId, this.programIds);
|
|
18054
|
-
const [conditionPda] = PDA.condition(oracle, questionId, this.programIds);
|
|
18055
|
-
const [yesMint] = PDA.yesMint(conditionPda, this.programIds);
|
|
18056
|
-
const [noMint] = PDA.noMint(conditionPda, this.programIds);
|
|
18057
|
-
const [mintAuthority] = PDA.mintAuthority(conditionPda, this.programIds);
|
|
18058
|
-
const [collateralVault] = PDA.collateralVault(params.collateralMint, this.programIds);
|
|
18059
|
-
if (!this.programIds.feeManagement) throw new Error("feeManagement program ID not configured");
|
|
18060
|
-
if (!this.feeConfigOwner) throw new Error("feeConfigOwner not configured");
|
|
18061
|
-
const [questionFeePda] = PDA.questionFee(conditionPda, this.programIds);
|
|
18062
|
-
const [feeConfigPda] = PDA.feeConfig(this.feeConfigOwner, this.programIds);
|
|
18063
|
-
const [marketFeeOverride] = PDA.marketFeeOverride(conditionPda, this.programIds);
|
|
18064
|
-
const tx = await this.program.methods.createQuestionAdmin({
|
|
18065
|
-
questionId: Array.from(questionId),
|
|
18066
|
-
contentHash: Array.from(contentHash),
|
|
18067
|
-
hookProgram: params.hookProgram,
|
|
18068
|
-
authorizedClob: params.authorizedClob,
|
|
18069
|
-
expirationTime: new anchor6.BN(params.expirationTime)
|
|
18070
|
-
}).accounts({
|
|
18071
|
-
creator,
|
|
17971
|
+
var MAX_APPROVE_AMOUNT = new BN4("18446744073709551615");
|
|
17972
|
+
function buildCreateUserAtasTx(condition, user, payer, programIds) {
|
|
17973
|
+
const [yesMint] = PDA.yesMint(condition, programIds);
|
|
17974
|
+
const [noMint] = PDA.noMint(condition, programIds);
|
|
17975
|
+
const yesAta = getAssociatedTokenAddressSync(yesMint, user, false, TOKEN_PROGRAM_ID);
|
|
17976
|
+
const noAta = getAssociatedTokenAddressSync(noMint, user, false, TOKEN_PROGRAM_ID);
|
|
17977
|
+
const tx = new Transaction();
|
|
17978
|
+
tx.feePayer = payer;
|
|
17979
|
+
tx.add(
|
|
17980
|
+
createAssociatedTokenAccountIdempotentInstruction(
|
|
18072
17981
|
payer,
|
|
18073
|
-
|
|
18074
|
-
|
|
18075
|
-
currencyMint: params.collateralMint,
|
|
18076
|
-
oracle,
|
|
18077
|
-
condition: conditionPda,
|
|
17982
|
+
yesAta,
|
|
17983
|
+
user,
|
|
18078
17984
|
yesMint,
|
|
18079
|
-
|
|
18080
|
-
|
|
18081
|
-
|
|
18082
|
-
|
|
18083
|
-
|
|
18084
|
-
|
|
18085
|
-
|
|
18086
|
-
feeManagementProgram: this.programIds.feeManagement,
|
|
18087
|
-
tokenProgram: TOKEN_2022_PROGRAM_ID,
|
|
18088
|
-
systemProgram: SystemProgram.programId,
|
|
18089
|
-
rent: SYSVAR_RENT_PUBKEY
|
|
18090
|
-
}).transaction();
|
|
18091
|
-
return { tx, questionPda, conditionPda, questionId };
|
|
18092
|
-
}
|
|
18093
|
-
async approveQuestion(questionPda, admin = this.walletPubkey, payer = admin) {
|
|
18094
|
-
return this.program.methods.approveQuestion().accounts({
|
|
18095
|
-
admin,
|
|
18096
|
-
payer,
|
|
18097
|
-
config: this.configPda,
|
|
18098
|
-
question: questionPda
|
|
18099
|
-
}).transaction();
|
|
18100
|
-
}
|
|
18101
|
-
async updateConfig(params, authority = this.walletPubkey, payer = authority) {
|
|
18102
|
-
return this.program.methods.updateConfig({
|
|
18103
|
-
newAdmin: params.newAdmin ?? null,
|
|
18104
|
-
newOracle: params.newOracle ?? null,
|
|
18105
|
-
isPaused: params.isPaused ?? null,
|
|
18106
|
-
newConditionalTokensProgram: params.newConditionalTokensProgram ?? null
|
|
18107
|
-
}).accounts({
|
|
18108
|
-
authority,
|
|
18109
|
-
payer,
|
|
18110
|
-
config: this.configPda
|
|
18111
|
-
}).transaction();
|
|
18112
|
-
}
|
|
18113
|
-
/** Set the admin (owner only). Replaces any existing admin. */
|
|
18114
|
-
async addAdmin(newAdmin, owner = this.walletPubkey) {
|
|
18115
|
-
return this.program.methods.addAdmin(newAdmin).accounts({
|
|
18116
|
-
owner,
|
|
18117
|
-
config: this.configPda
|
|
18118
|
-
}).transaction();
|
|
18119
|
-
}
|
|
18120
|
-
/** Clear the admin (owner only). Sets admin to default pubkey. */
|
|
18121
|
-
async removeAdmin(owner = this.walletPubkey) {
|
|
18122
|
-
return this.program.methods.removeAdmin().accounts({
|
|
18123
|
-
owner,
|
|
18124
|
-
config: this.configPda
|
|
18125
|
-
}).transaction();
|
|
18126
|
-
}
|
|
18127
|
-
async addToWhitelist(address, authority = this.walletPubkey, payer = authority) {
|
|
18128
|
-
return this.program.methods.addToWhitelist(address).accounts({
|
|
18129
|
-
authority,
|
|
18130
|
-
payer,
|
|
18131
|
-
config: this.configPda
|
|
18132
|
-
}).transaction();
|
|
18133
|
-
}
|
|
18134
|
-
async removeFromWhitelist(address, authority = this.walletPubkey, payer = authority) {
|
|
18135
|
-
return this.program.methods.removeFromWhitelist(address).accounts({
|
|
18136
|
-
authority,
|
|
18137
|
-
payer,
|
|
18138
|
-
config: this.configPda
|
|
18139
|
-
}).transaction();
|
|
18140
|
-
}
|
|
18141
|
-
async growConfig(owner = this.walletPubkey, payer = owner) {
|
|
18142
|
-
return this.program.methods.growConfig().accounts({
|
|
18143
|
-
payer,
|
|
18144
|
-
owner,
|
|
18145
|
-
config: this.configPda,
|
|
18146
|
-
systemProgram: SystemProgram.programId
|
|
18147
|
-
}).transaction();
|
|
18148
|
-
}
|
|
18149
|
-
async restoreConfig(snapshot, owner = this.walletPubkey, payer = owner) {
|
|
18150
|
-
return this.program.methods.restoreConfig(Array.from(snapshot)).accounts({
|
|
18151
|
-
payer,
|
|
18152
|
-
owner,
|
|
18153
|
-
config: this.configPda,
|
|
18154
|
-
systemProgram: SystemProgram.programId
|
|
18155
|
-
}).transaction();
|
|
18156
|
-
}
|
|
18157
|
-
async bumpPresaleCount(count, authority) {
|
|
18158
|
-
return this.program.methods.bumpPresaleCount(new anchor6.BN(count)).accounts({ authority, config: this.configPda }).transaction();
|
|
18159
|
-
}
|
|
18160
|
-
// ─── Queries ─────────────────────────────────────────────────────────────────
|
|
18161
|
-
async fetchConfig() {
|
|
18162
|
-
try {
|
|
18163
|
-
const acc = await this.program.account.questionMarketConfig.fetch(this.configPda);
|
|
18164
|
-
return {
|
|
18165
|
-
owner: acc.owner,
|
|
18166
|
-
admin: acc.admin,
|
|
18167
|
-
oracle: acc.oracle,
|
|
18168
|
-
conditionalTokensProgram: acc.conditionalTokensProgram,
|
|
18169
|
-
questionCount: acc.questionCount.toNumber(),
|
|
18170
|
-
approvedCount: acc.approvedCount.toNumber(),
|
|
18171
|
-
rejectedCount: acc.rejectedCount.toNumber(),
|
|
18172
|
-
presaleCount: acc.presaleCount.toNumber(),
|
|
18173
|
-
whitelist: acc.whitelist.slice(0, acc.whitelistLen),
|
|
18174
|
-
whitelistLen: acc.whitelistLen,
|
|
18175
|
-
isPaused: acc.isPaused,
|
|
18176
|
-
bump: acc.bump
|
|
18177
|
-
};
|
|
18178
|
-
} catch {
|
|
18179
|
-
return null;
|
|
18180
|
-
}
|
|
18181
|
-
}
|
|
18182
|
-
async fetchQuestion(questionPda) {
|
|
18183
|
-
try {
|
|
18184
|
-
const acc = await this.program.account.question.fetch(questionPda);
|
|
18185
|
-
return {
|
|
18186
|
-
config: acc.config,
|
|
18187
|
-
questionId: new Uint8Array(acc.questionId),
|
|
18188
|
-
contentHash: new Uint8Array(acc.contentHash),
|
|
18189
|
-
expirationTime: acc.expirationTime.toNumber(),
|
|
18190
|
-
currencyMint: acc.currencyMint,
|
|
18191
|
-
creator: acc.creator,
|
|
18192
|
-
condition: acc.condition ?? null,
|
|
18193
|
-
status: this._parseStatus(acc.status),
|
|
18194
|
-
createdAt: acc.createdAt.toNumber(),
|
|
18195
|
-
approvedAt: acc.approvedAt.toNumber(),
|
|
18196
|
-
resolvedAt: acc.resolvedAt.toNumber(),
|
|
18197
|
-
bump: acc.bump
|
|
18198
|
-
};
|
|
18199
|
-
} catch {
|
|
18200
|
-
return null;
|
|
18201
|
-
}
|
|
18202
|
-
}
|
|
18203
|
-
questionPda(questionId) {
|
|
18204
|
-
return PDA.question(this.configPda, questionId, this.programIds)[0];
|
|
18205
|
-
}
|
|
18206
|
-
_parseStatus(raw) {
|
|
18207
|
-
if (raw.pending !== void 0) return "pending" /* Pending */;
|
|
18208
|
-
if (raw.approved !== void 0) return "approved" /* Approved */;
|
|
18209
|
-
if (raw.rejected !== void 0) return "rejected" /* Rejected */;
|
|
18210
|
-
if (raw.resolved !== void 0) return "resolved" /* Resolved */;
|
|
18211
|
-
return "pending" /* Pending */;
|
|
18212
|
-
}
|
|
18213
|
-
/**
|
|
18214
|
-
* Convenience: fetch YES and NO token balances for a question.
|
|
18215
|
-
* Returns null for each if question not approved or position not initialized.
|
|
18216
|
-
* Requires ctfClient to be injected (done automatically by XMarketSDK).
|
|
18217
|
-
*/
|
|
18218
|
-
async fetchQuestionBalances(questionPda, owner) {
|
|
18219
|
-
if (!this.ctfClient) return { yes: null, no: null };
|
|
18220
|
-
const q = await this.fetchQuestion(questionPda);
|
|
18221
|
-
if (!q || !q.condition) return { yes: null, no: null };
|
|
18222
|
-
return this.ctfClient.fetchBothPositions(q.condition, owner);
|
|
18223
|
-
}
|
|
18224
|
-
// ─── Presale instructions ────────────────────────────────────────────────────
|
|
18225
|
-
/**
|
|
18226
|
-
* Any user creates a presale + initial buy (question-market::create_presale).
|
|
18227
|
-
* Reads agents_rev / company_rev from fee_config.
|
|
18228
|
-
*
|
|
18229
|
-
* @param feeConfig fee_management fee_config PDA (owner = feeConfigOwner)
|
|
18230
|
-
* @param currencyMint collateral token (e.g. USDC)
|
|
18231
|
-
* @param presaleIndex config.presale_count — fetch config first or pass 0 for first presale
|
|
18232
|
-
*/
|
|
18233
|
-
async createPresale(params, feeConfig, currencyMint, presaleIndex, creator = this.walletPubkey, payer = creator) {
|
|
18234
|
-
if (!this.programIds.presale) throw new Error("presale program ID not configured");
|
|
18235
|
-
const [presalePda] = PDA.presale(this.configPda, presaleIndex, this.programIds);
|
|
18236
|
-
const [qtMint] = PDA.qtMint(presalePda, this.programIds);
|
|
18237
|
-
const [qtAuthority] = PDA.qtAuthority(presalePda, this.programIds);
|
|
18238
|
-
const [userBuyRecord] = PDA.userBuyRecord(presalePda, creator, this.programIds);
|
|
18239
|
-
const presaleVault = getAssociatedTokenAddressSync(currencyMint, presalePda, true);
|
|
18240
|
-
const creatorQtAta = getAssociatedTokenAddressSync(qtMint, creator);
|
|
18241
|
-
const creatorCurrencyAta = getAssociatedTokenAddressSync(currencyMint, creator);
|
|
18242
|
-
const [qtMetadata] = PublicKey.findProgramAddressSync(
|
|
18243
|
-
[Buffer.from("metadata"), TOKEN_METADATA_PROGRAM_ID2.toBuffer(), qtMint.toBuffer()],
|
|
18244
|
-
TOKEN_METADATA_PROGRAM_ID2
|
|
18245
|
-
);
|
|
18246
|
-
const tx = await this.program.methods.createPresale({
|
|
18247
|
-
price: params.price,
|
|
18248
|
-
startTime: params.startTime,
|
|
18249
|
-
endTime: params.endTime,
|
|
18250
|
-
initialBuyAmount: params.initialBuyAmount
|
|
18251
|
-
}).accounts({
|
|
18252
|
-
creator,
|
|
18253
|
-
payer,
|
|
18254
|
-
config: this.configPda,
|
|
18255
|
-
feeConfig,
|
|
18256
|
-
presale: presalePda,
|
|
18257
|
-
qtMint,
|
|
18258
|
-
qtAuthority,
|
|
18259
|
-
currencyMint,
|
|
18260
|
-
presaleVault,
|
|
18261
|
-
creatorCurrencyAta,
|
|
18262
|
-
creatorQtAta,
|
|
18263
|
-
userBuyRecord,
|
|
18264
|
-
qtMetadata,
|
|
18265
|
-
tokenMetadataProgram: TOKEN_METADATA_PROGRAM_ID2,
|
|
18266
|
-
presaleProgram: this.programIds.presale,
|
|
18267
|
-
tokenProgram: TOKEN_PROGRAM_ID,
|
|
18268
|
-
associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID,
|
|
18269
|
-
systemProgram: SystemProgram.programId,
|
|
18270
|
-
rent: SYSVAR_RENT_PUBKEY
|
|
18271
|
-
}).transaction();
|
|
18272
|
-
tx.instructions.unshift(
|
|
18273
|
-
ComputeBudgetProgram.setComputeUnitLimit({ units: 4e5 })
|
|
18274
|
-
);
|
|
18275
|
-
return { tx, presalePda, qtMint };
|
|
18276
|
-
}
|
|
18277
|
-
/**
|
|
18278
|
-
* Whitelist-only: approve presale → creates question + CTF condition + market_oracle in one tx.
|
|
18279
|
-
*
|
|
18280
|
-
* @param presalePda the presale account
|
|
18281
|
-
* @param contentHash 32-byte hash for question content
|
|
18282
|
-
* @param hookProgram token-2022 transfer hook program
|
|
18283
|
-
* @param authorizedClob clob program allowed to do CTF transfers
|
|
18284
|
-
* @param expirationTime Unix seconds
|
|
18285
|
-
* @param creator presale creator pubkey (stored in question)
|
|
18286
|
-
* @param currencyMint collateral mint
|
|
18287
|
-
*/
|
|
18288
|
-
async approvePresale(params) {
|
|
18289
|
-
const {
|
|
18290
|
-
presalePda,
|
|
18291
|
-
contentHash,
|
|
18292
|
-
hookProgram,
|
|
18293
|
-
authorizedClob,
|
|
18294
|
-
expirationTime,
|
|
18295
|
-
creator,
|
|
18296
|
-
currencyMint,
|
|
18297
|
-
referralAddress,
|
|
18298
|
-
companyAddress,
|
|
18299
|
-
adminOwner
|
|
18300
|
-
} = params;
|
|
18301
|
-
const caller = params.caller ?? this.walletPubkey;
|
|
18302
|
-
const payer = params.payer ?? caller;
|
|
18303
|
-
if (!this.programIds.presale) throw new Error("presale program ID not configured");
|
|
18304
|
-
if (!this.programIds.marketOracle) throw new Error("marketOracle program ID not configured");
|
|
18305
|
-
if (!this.programIds.feeManagement) throw new Error("feeManagement program ID not configured");
|
|
18306
|
-
if (!this.programIds.adminContract) throw new Error("adminContract program ID not configured");
|
|
18307
|
-
const questionId = presalePda.toBytes();
|
|
18308
|
-
const [questionPda] = PDA.question(this.configPda, questionId, this.programIds);
|
|
18309
|
-
const marketConfig = await this.fetchConfig();
|
|
18310
|
-
if (!marketConfig) throw new Error("QuestionMarketConfig not found");
|
|
18311
|
-
const oraclePubkey = marketConfig.oracle;
|
|
18312
|
-
const [conditionPda] = PDA.condition(oraclePubkey, questionId, this.programIds);
|
|
18313
|
-
const [yesMint] = PDA.yesMint(conditionPda, this.programIds);
|
|
18314
|
-
const [noMint] = PDA.noMint(conditionPda, this.programIds);
|
|
18315
|
-
const [mintAuthority] = PDA.mintAuthority(conditionPda, this.programIds);
|
|
18316
|
-
const [collateralVault] = PDA.collateralVault(currencyMint, this.programIds);
|
|
18317
|
-
const [marketOraclePda] = PDA.marketOraclePda(questionPda, this.programIds);
|
|
18318
|
-
const marketOracleVault = getAssociatedTokenAddressSync(currencyMint, marketOraclePda, true);
|
|
18319
|
-
const [questionFeePda] = PDA.questionFee(conditionPda, this.programIds);
|
|
18320
|
-
const presaleVault = getAssociatedTokenAddressSync(currencyMint, presalePda, true);
|
|
18321
|
-
const referralTokenAccount = getAssociatedTokenAddressSync(currencyMint, referralAddress);
|
|
18322
|
-
const companyTokenAccount = getAssociatedTokenAddressSync(currencyMint, companyAddress);
|
|
18323
|
-
const [adminConfig] = PDA.adminConfig(adminOwner, this.programIds);
|
|
18324
|
-
const adminVault = getAssociatedTokenAddressSync(currencyMint, adminConfig, true);
|
|
18325
|
-
const [claimRecord] = PDA.claimRecord(conditionPda.toBytes(), this.programIds);
|
|
18326
|
-
const feeConfigOwner = this.feeConfigOwner ?? adminOwner;
|
|
18327
|
-
const [feeConfigPda] = PDA.feeConfig(feeConfigOwner, this.programIds);
|
|
18328
|
-
const [marketFeeOverride] = PDA.marketFeeOverride(conditionPda, this.programIds);
|
|
18329
|
-
const builder = this.program.methods.approvePresale({
|
|
18330
|
-
contentHash: Array.from(contentHash),
|
|
18331
|
-
hookProgram,
|
|
18332
|
-
authorizedClob,
|
|
18333
|
-
expirationTime,
|
|
18334
|
-
creator
|
|
18335
|
-
}).accounts({
|
|
18336
|
-
caller,
|
|
18337
|
-
payer,
|
|
18338
|
-
config: this.configPda,
|
|
18339
|
-
presale: presalePda,
|
|
18340
|
-
question: questionPda,
|
|
18341
|
-
currencyMint,
|
|
18342
|
-
oracle: oraclePubkey,
|
|
18343
|
-
condition: conditionPda,
|
|
18344
|
-
yesMint,
|
|
18345
|
-
noMint,
|
|
18346
|
-
mintAuthority,
|
|
18347
|
-
collateralVault,
|
|
18348
|
-
marketOracle: marketOraclePda,
|
|
18349
|
-
marketOracleVault,
|
|
18350
|
-
presaleVault,
|
|
18351
|
-
referralTokenAccount,
|
|
18352
|
-
companyTokenAccount,
|
|
18353
|
-
adminVault,
|
|
18354
|
-
adminConfig,
|
|
18355
|
-
claimRecord,
|
|
18356
|
-
questionFee: questionFeePda,
|
|
18357
|
-
feeConfig: feeConfigPda,
|
|
18358
|
-
marketFeeOverride,
|
|
18359
|
-
feeManagementProgram: this.programIds.feeManagement,
|
|
18360
|
-
conditionalTokensProgram: this.programIds.conditionalTokens,
|
|
18361
|
-
presaleProgram: this.programIds.presale,
|
|
18362
|
-
marketOracleProgram: this.programIds.marketOracle,
|
|
18363
|
-
adminProgram: this.programIds.adminContract,
|
|
18364
|
-
tokenProgram: TOKEN_PROGRAM_ID,
|
|
18365
|
-
token2022Program: TOKEN_2022_PROGRAM_ID,
|
|
18366
|
-
associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID,
|
|
18367
|
-
systemProgram: SystemProgram.programId,
|
|
18368
|
-
rent: SYSVAR_RENT_PUBKEY
|
|
18369
|
-
});
|
|
18370
|
-
let tx;
|
|
18371
|
-
if (params.lookupTable) {
|
|
18372
|
-
const ix = await builder.instruction();
|
|
18373
|
-
const cu = ComputeBudgetProgram.setComputeUnitLimit({ units: 14e5 });
|
|
18374
|
-
const { blockhash } = await this.provider.connection.getLatestBlockhash();
|
|
18375
|
-
const msg = new TransactionMessage({
|
|
18376
|
-
payerKey: payer,
|
|
18377
|
-
recentBlockhash: blockhash,
|
|
18378
|
-
instructions: [cu, ix]
|
|
18379
|
-
}).compileToV0Message([params.lookupTable]);
|
|
18380
|
-
tx = new VersionedTransaction(msg);
|
|
18381
|
-
} else {
|
|
18382
|
-
tx = await builder.transaction();
|
|
18383
|
-
}
|
|
18384
|
-
return { tx, questionPda, conditionPda, marketOraclePda, marketOracleVault };
|
|
18385
|
-
}
|
|
18386
|
-
/**
|
|
18387
|
-
* Whitelist-only: reject presale so users can refund.
|
|
18388
|
-
*/
|
|
18389
|
-
async rejectPresale(presalePda, caller = this.walletPubkey) {
|
|
18390
|
-
if (!this.programIds.presale) throw new Error("presale program ID not configured");
|
|
18391
|
-
return this.program.methods.rejectPresale().accounts({
|
|
18392
|
-
caller,
|
|
18393
|
-
config: this.configPda,
|
|
18394
|
-
presale: presalePda,
|
|
18395
|
-
presaleProgram: this.programIds.presale
|
|
18396
|
-
}).transaction();
|
|
18397
|
-
}
|
|
18398
|
-
/**
|
|
18399
|
-
* Whitelist-only: distribute presale vault → 10% agents + 10% company + 80% botmm.
|
|
18400
|
-
* Closes presale_vault ATA and presale PDA after distribution; lamports returned to payer.
|
|
18401
|
-
*/
|
|
18402
|
-
async collectPresaleRevenue(params) {
|
|
18403
|
-
const {
|
|
18404
|
-
presalePda,
|
|
18405
|
-
currencyMint,
|
|
18406
|
-
conditionId,
|
|
18407
|
-
referralAddress,
|
|
18408
|
-
companyAddress,
|
|
18409
|
-
adminOwner
|
|
18410
|
-
} = params;
|
|
18411
|
-
const caller = params.caller ?? this.walletPubkey;
|
|
18412
|
-
const payer = params.payer ?? this.walletPubkey;
|
|
18413
|
-
if (!this.programIds.presale) throw new Error("presale program ID not configured");
|
|
18414
|
-
if (!this.programIds.adminContract) throw new Error("adminContract program ID not configured");
|
|
18415
|
-
const presaleVault = getAssociatedTokenAddressSync(currencyMint, presalePda, true);
|
|
18416
|
-
const referralTokenAccount = getAssociatedTokenAddressSync(currencyMint, referralAddress);
|
|
18417
|
-
const companyTokenAccount = getAssociatedTokenAddressSync(currencyMint, companyAddress);
|
|
18418
|
-
const [adminConfig] = PDA.adminConfig(adminOwner, this.programIds);
|
|
18419
|
-
const [claimRecord] = PDA.claimRecord(conditionId, this.programIds);
|
|
18420
|
-
const adminVault = getAssociatedTokenAddressSync(currencyMint, adminConfig, true);
|
|
18421
|
-
return this.program.methods.collectPresaleRevenue(Array.from(conditionId)).accounts({
|
|
18422
|
-
caller,
|
|
18423
|
-
config: this.configPda,
|
|
18424
|
-
presale: presalePda,
|
|
18425
|
-
presaleVault,
|
|
18426
|
-
currencyMint,
|
|
18427
|
-
referralTokenAccount,
|
|
18428
|
-
companyTokenAccount,
|
|
18429
|
-
adminVault,
|
|
18430
|
-
adminConfig,
|
|
18431
|
-
claimRecord,
|
|
18432
|
-
payer,
|
|
18433
|
-
presaleProgram: this.programIds.presale,
|
|
18434
|
-
adminProgram: this.programIds.adminContract,
|
|
18435
|
-
tokenProgram: TOKEN_PROGRAM_ID,
|
|
18436
|
-
associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID,
|
|
18437
|
-
systemProgram: SystemProgram.programId
|
|
18438
|
-
}).transaction();
|
|
18439
|
-
}
|
|
18440
|
-
/**
|
|
18441
|
-
* Whitelist-only: snapshot MST supply so holders can claim trading fees.
|
|
18442
|
-
* Call after oracle resolves the question.
|
|
18443
|
-
*/
|
|
18444
|
-
async collectTradingFee(marketOraclePda, qtMint, caller = this.walletPubkey) {
|
|
18445
|
-
if (!this.programIds.marketOracle) throw new Error("marketOracle program ID not configured");
|
|
18446
|
-
return this.program.methods.collectTradingFee().accounts({
|
|
18447
|
-
caller,
|
|
18448
|
-
config: this.configPda,
|
|
18449
|
-
marketOracle: marketOraclePda,
|
|
18450
|
-
qtMint,
|
|
18451
|
-
marketOracleProgram: this.programIds.marketOracle
|
|
18452
|
-
}).transaction();
|
|
18453
|
-
}
|
|
18454
|
-
};
|
|
18455
|
-
var CtfClient = class {
|
|
18456
|
-
constructor(program, provider, programIds) {
|
|
18457
|
-
this.program = program;
|
|
18458
|
-
this.provider = provider;
|
|
18459
|
-
this.programIds = programIds;
|
|
18460
|
-
}
|
|
18461
|
-
get walletPubkey() {
|
|
18462
|
-
return this.provider.wallet.publicKey;
|
|
18463
|
-
}
|
|
18464
|
-
// ─── Instructions ────────────────────────────────────────────────────────────
|
|
18465
|
-
/**
|
|
18466
|
-
* Create a Condition directly (bypasses QuestionMarket).
|
|
18467
|
-
* oracle is UncheckedAccount — set it to any pubkey (e.g. user wallet)
|
|
18468
|
-
* so that wallet can later sign reportPayouts.
|
|
18469
|
-
* payer covers rent for condition + mints.
|
|
18470
|
-
*/
|
|
18471
|
-
async prepareCondition(questionId, oracle, collateralMint, hookProgram, authorizedClob, payer = this.walletPubkey, signers = []) {
|
|
18472
|
-
const [conditionPda] = PDA.condition(oracle, questionId, this.programIds);
|
|
18473
|
-
const [yesMint] = PDA.yesMint(conditionPda, this.programIds);
|
|
18474
|
-
const [noMint] = PDA.noMint(conditionPda, this.programIds);
|
|
18475
|
-
const [mintAuthority] = PDA.mintAuthority(conditionPda, this.programIds);
|
|
18476
|
-
const [collateralVault] = PDA.collateralVault(collateralMint, this.programIds);
|
|
18477
|
-
const sig = await this.program.methods.prepareCondition(
|
|
18478
|
-
Array.from(questionId),
|
|
18479
|
-
hookProgram,
|
|
18480
|
-
authorizedClob
|
|
18481
|
-
).accounts({
|
|
18482
|
-
oracle,
|
|
18483
|
-
condition: conditionPda,
|
|
18484
|
-
yesMint,
|
|
18485
|
-
noMint,
|
|
18486
|
-
mintAuthority,
|
|
18487
|
-
collateralMint,
|
|
18488
|
-
collateralVault,
|
|
18489
|
-
payer,
|
|
18490
|
-
tokenProgram: TOKEN_2022_PROGRAM_ID,
|
|
18491
|
-
systemProgram: SystemProgram.programId,
|
|
18492
|
-
rent: SYSVAR_RENT_PUBKEY
|
|
18493
|
-
}).signers(signers).rpc({ skipPreflight: true });
|
|
18494
|
-
return { signature: sig, conditionPda, yesMint, noMint };
|
|
18495
|
-
}
|
|
18496
|
-
/** One-time setup. Caller becomes the CTF owner. Can only be called once. */
|
|
18497
|
-
async initializeCtfConfig() {
|
|
18498
|
-
const [ctfConfig] = PDA.ctfConfig(this.programIds);
|
|
18499
|
-
const sig = await this.program.methods.initializeCtfConfig().accounts({
|
|
18500
|
-
payer: this.walletPubkey,
|
|
18501
|
-
ctfConfig,
|
|
18502
|
-
systemProgram: SystemProgram.programId
|
|
18503
|
-
}).rpc();
|
|
18504
|
-
return { signature: sig };
|
|
18505
|
-
}
|
|
18506
|
-
/**
|
|
18507
|
-
* Create the shared collateral vault for a given collateral mint (e.g. USDC).
|
|
18508
|
-
* Only callable by the CTF owner (as stored in ctf_config).
|
|
18509
|
-
* authority defaults to the wallet — pass a different signer if needed.
|
|
18510
|
-
*/
|
|
18511
|
-
async initializeVault(collateralMint) {
|
|
18512
|
-
const [ctfConfig] = PDA.ctfConfig(this.programIds);
|
|
18513
|
-
const [collateralVault] = PDA.collateralVault(collateralMint, this.programIds);
|
|
18514
|
-
const [vaultTokenAccount] = PDA.vaultToken(collateralMint, this.programIds);
|
|
18515
|
-
const sig = await this.program.methods.initializeVault().accounts({
|
|
18516
|
-
authority: this.walletPubkey,
|
|
18517
|
-
payer: this.walletPubkey,
|
|
18518
|
-
ctfConfig,
|
|
18519
|
-
collateralMint,
|
|
18520
|
-
collateralVault,
|
|
18521
|
-
vaultTokenAccount,
|
|
18522
|
-
systemProgram: SystemProgram.programId,
|
|
18523
|
-
tokenProgram: TOKEN_PROGRAM_ID,
|
|
18524
|
-
rent: SYSVAR_RENT_PUBKEY
|
|
18525
|
-
}).rpc();
|
|
18526
|
-
return { signature: sig };
|
|
18527
|
-
}
|
|
18528
|
-
/**
|
|
18529
|
-
* Initialize an empty Position account (balance = 0) for a user.
|
|
18530
|
-
* Needed before redeemPositions when the user only holds the opposite outcome
|
|
18531
|
-
* (e.g. buyer received YES via CLOB match but never had a NO position).
|
|
18532
|
-
*
|
|
18533
|
-
* Idempotent — call `fetchPosition` first to skip if already initialized.
|
|
18534
|
-
*/
|
|
18535
|
-
async initPosition(condition, outcomeIndex, user = this.walletPubkey) {
|
|
18536
|
-
const [position] = PDA.position(condition, outcomeIndex, user, this.programIds);
|
|
18537
|
-
const sig = await this.program.methods.initPosition(outcomeIndex).accounts({
|
|
18538
|
-
user,
|
|
18539
|
-
condition,
|
|
18540
|
-
position,
|
|
18541
|
-
systemProgram: SystemProgram.programId
|
|
18542
|
-
}).rpc();
|
|
18543
|
-
return { signature: sig };
|
|
18544
|
-
}
|
|
18545
|
-
/**
|
|
18546
|
-
* Split `amount` collateral into equal YES + NO tokens.
|
|
18547
|
-
* ATAs created automatically via `init_if_needed`.
|
|
18548
|
-
*/
|
|
18549
|
-
async splitPosition(condition, collateralMint, amount, user = this.walletPubkey, payer = this.walletPubkey) {
|
|
18550
|
-
const [collateralVault] = PDA.collateralVault(collateralMint, this.programIds);
|
|
18551
|
-
const [vaultTokenAccount] = PDA.vaultToken(collateralMint, this.programIds);
|
|
18552
|
-
const [yesMint] = PDA.yesMint(condition, this.programIds);
|
|
18553
|
-
const [noMint] = PDA.noMint(condition, this.programIds);
|
|
18554
|
-
const [mintAuthority] = PDA.mintAuthority(condition, this.programIds);
|
|
18555
|
-
const [yesPosition] = PDA.position(condition, 1, user, this.programIds);
|
|
18556
|
-
const [noPosition] = PDA.position(condition, 0, user, this.programIds);
|
|
18557
|
-
const userYesAta = getAssociatedTokenAddressSync(yesMint, user, false, TOKEN_2022_PROGRAM_ID);
|
|
18558
|
-
const userNoAta = getAssociatedTokenAddressSync(noMint, user, false, TOKEN_2022_PROGRAM_ID);
|
|
18559
|
-
const userCollateral = getAssociatedTokenAddressSync(collateralMint, user);
|
|
18560
|
-
return this.program.methods.splitPosition(amount).accounts({
|
|
18561
|
-
user,
|
|
18562
|
-
payer,
|
|
18563
|
-
condition,
|
|
18564
|
-
collateralVault,
|
|
18565
|
-
vaultTokenAccount,
|
|
18566
|
-
userCollateral,
|
|
18567
|
-
yesMint,
|
|
18568
|
-
userYesAta,
|
|
18569
|
-
noMint,
|
|
18570
|
-
userNoAta,
|
|
18571
|
-
yesPosition,
|
|
18572
|
-
noPosition,
|
|
18573
|
-
mintAuthority,
|
|
18574
|
-
tokenProgram: TOKEN_PROGRAM_ID,
|
|
18575
|
-
token2022Program: TOKEN_2022_PROGRAM_ID,
|
|
18576
|
-
associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID,
|
|
18577
|
-
systemProgram: SystemProgram.programId
|
|
18578
|
-
}).transaction();
|
|
18579
|
-
}
|
|
18580
|
-
/**
|
|
18581
|
-
* Merge `amount` YES + NO tokens back into collateral.
|
|
18582
|
-
* Both token balances must be ≥ amount.
|
|
18583
|
-
*/
|
|
18584
|
-
async mergePosition(condition, collateralMint, amount, user = this.walletPubkey, payer = this.walletPubkey) {
|
|
18585
|
-
const [collateralVault] = PDA.collateralVault(collateralMint, this.programIds);
|
|
18586
|
-
const [vaultTokenAccount] = PDA.vaultToken(collateralMint, this.programIds);
|
|
18587
|
-
const [yesMint] = PDA.yesMint(condition, this.programIds);
|
|
18588
|
-
const [noMint] = PDA.noMint(condition, this.programIds);
|
|
18589
|
-
const [yesPosition] = PDA.position(condition, 1, user, this.programIds);
|
|
18590
|
-
const [noPosition] = PDA.position(condition, 0, user, this.programIds);
|
|
18591
|
-
const userYesAta = getAssociatedTokenAddressSync(yesMint, user, false, TOKEN_2022_PROGRAM_ID);
|
|
18592
|
-
const userNoAta = getAssociatedTokenAddressSync(noMint, user, false, TOKEN_2022_PROGRAM_ID);
|
|
18593
|
-
const userCollateral = getAssociatedTokenAddressSync(collateralMint, user);
|
|
18594
|
-
return this.program.methods.mergePosition(amount).accounts({
|
|
18595
|
-
user,
|
|
18596
|
-
payer,
|
|
18597
|
-
condition,
|
|
18598
|
-
collateralVault,
|
|
18599
|
-
vaultTokenAccount,
|
|
18600
|
-
userCollateral,
|
|
18601
|
-
yesMint,
|
|
18602
|
-
userYesAta,
|
|
18603
|
-
noMint,
|
|
18604
|
-
userNoAta,
|
|
18605
|
-
yesPosition,
|
|
18606
|
-
noPosition,
|
|
18607
|
-
tokenProgram: TOKEN_PROGRAM_ID,
|
|
18608
|
-
token2022Program: TOKEN_2022_PROGRAM_ID,
|
|
18609
|
-
systemProgram: SystemProgram.programId
|
|
18610
|
-
}).transaction();
|
|
18611
|
-
}
|
|
18612
|
-
/**
|
|
18613
|
-
* After condition resolves: burn outcome tokens proportional to payout
|
|
18614
|
-
* and receive USDC. Works for winning, losing, or both positions.
|
|
18615
|
-
*/
|
|
18616
|
-
async redeemPositions(condition, collateralMint, user = this.walletPubkey, payer = this.walletPubkey) {
|
|
18617
|
-
const [collateralVault] = PDA.collateralVault(collateralMint, this.programIds);
|
|
18618
|
-
const [vaultTokenAccount] = PDA.vaultToken(collateralMint, this.programIds);
|
|
18619
|
-
const [yesMint] = PDA.yesMint(condition, this.programIds);
|
|
18620
|
-
const [noMint] = PDA.noMint(condition, this.programIds);
|
|
18621
|
-
const [yesPosition] = PDA.position(condition, 1, user, this.programIds);
|
|
18622
|
-
const [noPosition] = PDA.position(condition, 0, user, this.programIds);
|
|
18623
|
-
const userYesAta = getAssociatedTokenAddressSync(yesMint, user, false, TOKEN_2022_PROGRAM_ID);
|
|
18624
|
-
const userNoAta = getAssociatedTokenAddressSync(noMint, user, false, TOKEN_2022_PROGRAM_ID);
|
|
18625
|
-
const userCollateral = getAssociatedTokenAddressSync(collateralMint, user);
|
|
18626
|
-
const createYesAtaIx = createAssociatedTokenAccountIdempotentInstruction(
|
|
18627
|
-
payer,
|
|
18628
|
-
userYesAta,
|
|
18629
|
-
user,
|
|
18630
|
-
yesMint,
|
|
18631
|
-
TOKEN_2022_PROGRAM_ID
|
|
18632
|
-
);
|
|
18633
|
-
const createNoAtaIx = createAssociatedTokenAccountIdempotentInstruction(
|
|
18634
|
-
payer,
|
|
18635
|
-
userNoAta,
|
|
18636
|
-
user,
|
|
18637
|
-
noMint,
|
|
18638
|
-
TOKEN_2022_PROGRAM_ID
|
|
18639
|
-
);
|
|
18640
|
-
const redeemIx = await this.program.methods.redeemPositions().accounts({
|
|
18641
|
-
user,
|
|
18642
|
-
payer,
|
|
18643
|
-
condition,
|
|
18644
|
-
collateralVault,
|
|
18645
|
-
vaultTokenAccount,
|
|
18646
|
-
userCollateral,
|
|
18647
|
-
yesMint,
|
|
18648
|
-
userYesAta,
|
|
18649
|
-
noMint,
|
|
18650
|
-
userNoAta,
|
|
18651
|
-
yesPosition,
|
|
18652
|
-
noPosition,
|
|
18653
|
-
tokenProgram: TOKEN_PROGRAM_ID,
|
|
18654
|
-
token2022Program: TOKEN_2022_PROGRAM_ID,
|
|
18655
|
-
systemProgram: SystemProgram.programId
|
|
18656
|
-
}).instruction();
|
|
18657
|
-
const tx = new Transaction();
|
|
18658
|
-
tx.add(createYesAtaIx, createNoAtaIx, redeemIx);
|
|
18659
|
-
return tx;
|
|
18660
|
-
}
|
|
18661
|
-
/**
|
|
18662
|
-
* Oracle directly resolves a condition with payout numerators.
|
|
18663
|
-
* Bypasses QuestionMarket — only for oracle-owned conditions.
|
|
18664
|
-
*/
|
|
18665
|
-
async reportPayouts(condition, payoutNumerators) {
|
|
18666
|
-
const sig = await this.program.methods.reportPayouts(payoutNumerators.map((n) => new anchor6.BN(n))).accounts({
|
|
18667
|
-
oracle: this.walletPubkey,
|
|
18668
|
-
condition
|
|
18669
|
-
}).rpc();
|
|
18670
|
-
return { signature: sig };
|
|
18671
|
-
}
|
|
18672
|
-
/**
|
|
18673
|
-
* Build the `transfer_position` instruction for use in a CLOB CPI.
|
|
18674
|
-
*
|
|
18675
|
-
* This instruction requires `clob_authority` (the CLOB's PDA) to sign.
|
|
18676
|
-
* A PDA can only sign from within its own program via CPI — this method
|
|
18677
|
-
* CANNOT be called directly from a wallet transaction.
|
|
18678
|
-
*
|
|
18679
|
-
* Use-cases:
|
|
18680
|
-
* - Custom CLOB implementations that call CTF.transfer_position via CPI
|
|
18681
|
-
* - Anchor CPI builders in other Rust programs
|
|
18682
|
-
*
|
|
18683
|
-
* @param condition - Condition PDA
|
|
18684
|
-
* @param outcomeMint - YES or NO mint
|
|
18685
|
-
* @param fromUser - Source wallet
|
|
18686
|
-
* @param fromTokenAccount - Source ATA
|
|
18687
|
-
* @param fromPosition - Source Position PDA
|
|
18688
|
-
* @param toUser - Destination wallet
|
|
18689
|
-
* @param toTokenAccount - Destination ATA (created if needed — payer covers rent)
|
|
18690
|
-
* @param toPosition - Destination Position PDA
|
|
18691
|
-
* @param payer - Pays rent for toPosition + toTokenAccount creation
|
|
18692
|
-
* @param clobAuthority - CLOB config PDA (must sign via CPI)
|
|
18693
|
-
* @param outcomeIndex - 0 = NO, 1 = YES
|
|
18694
|
-
* @param amount - Token amount to transfer
|
|
18695
|
-
*/
|
|
18696
|
-
async transferPositionIx(condition, outcomeMint, fromUser, fromTokenAccount, fromPosition, toUser, toTokenAccount, toPosition, payer, clobAuthority, outcomeIndex, amount) {
|
|
18697
|
-
return this.program.methods.transferPosition(outcomeIndex, amount).accounts({
|
|
18698
|
-
payer,
|
|
18699
|
-
clobAuthority,
|
|
18700
|
-
condition,
|
|
18701
|
-
outcomeMint,
|
|
18702
|
-
fromUser,
|
|
18703
|
-
fromTokenAccount,
|
|
18704
|
-
fromPosition,
|
|
18705
|
-
toUser,
|
|
18706
|
-
toTokenAccount,
|
|
18707
|
-
toPosition,
|
|
18708
|
-
token2022Program: TOKEN_2022_PROGRAM_ID,
|
|
18709
|
-
systemProgram: SystemProgram.programId
|
|
18710
|
-
}).instruction();
|
|
18711
|
-
}
|
|
18712
|
-
/**
|
|
18713
|
-
* Update the authorized CLOB on a condition.
|
|
18714
|
-
* Only callable by the condition's oracle (the wallet that signed createQuestion).
|
|
18715
|
-
*/
|
|
18716
|
-
async updateAuthorizedClob(condition, newAuthorizedClob) {
|
|
18717
|
-
const sig = await this.program.methods.updateAuthorizedClob(newAuthorizedClob).accounts({
|
|
18718
|
-
oracle: this.walletPubkey,
|
|
18719
|
-
condition
|
|
18720
|
-
}).rpc();
|
|
18721
|
-
return { signature: sig };
|
|
18722
|
-
}
|
|
18723
|
-
// ─── Queries ─────────────────────────────────────────────────────────────────
|
|
18724
|
-
async fetchCtfConfig() {
|
|
18725
|
-
try {
|
|
18726
|
-
const [ctfConfig] = PDA.ctfConfig(this.programIds);
|
|
18727
|
-
const acc = await this.program.account.ctfConfig.fetch(ctfConfig);
|
|
18728
|
-
return {
|
|
18729
|
-
owner: acc.owner,
|
|
18730
|
-
bump: acc.bump
|
|
18731
|
-
};
|
|
18732
|
-
} catch {
|
|
18733
|
-
return null;
|
|
18734
|
-
}
|
|
18735
|
-
}
|
|
18736
|
-
async fetchCondition(conditionPda) {
|
|
18737
|
-
try {
|
|
18738
|
-
const acc = await this.program.account.condition.fetch(conditionPda);
|
|
18739
|
-
return {
|
|
18740
|
-
oracle: acc.oracle,
|
|
18741
|
-
questionId: new Uint8Array(acc.questionId),
|
|
18742
|
-
outcomeSlotCount: acc.outcomeSlotCount,
|
|
18743
|
-
payoutNumerators: acc.payoutNumerators,
|
|
18744
|
-
payoutDenominator: acc.payoutDenominator,
|
|
18745
|
-
totalCollateral: acc.totalCollateral,
|
|
18746
|
-
collateralMint: acc.collateralMint,
|
|
18747
|
-
collateralVault: acc.collateralVault,
|
|
18748
|
-
yesMint: acc.yesMint,
|
|
18749
|
-
noMint: acc.noMint,
|
|
18750
|
-
hookProgram: acc.hookProgram,
|
|
18751
|
-
authorizedClob: acc.authorizedClob,
|
|
18752
|
-
isResolved: acc.isResolved,
|
|
18753
|
-
resolvedAt: acc.resolvedAt?.toNumber() ?? 0,
|
|
18754
|
-
bump: acc.bump
|
|
18755
|
-
};
|
|
18756
|
-
} catch {
|
|
18757
|
-
return null;
|
|
18758
|
-
}
|
|
18759
|
-
}
|
|
18760
|
-
async fetchVault(collateralMint) {
|
|
18761
|
-
try {
|
|
18762
|
-
const [vaultPda] = PDA.collateralVault(collateralMint, this.programIds);
|
|
18763
|
-
const acc = await this.program.account.collateralVault.fetch(vaultPda);
|
|
18764
|
-
return {
|
|
18765
|
-
collateralMint: acc.collateralMint,
|
|
18766
|
-
vaultTokenAccount: acc.vaultTokenAccount,
|
|
18767
|
-
totalLocked: acc.totalLocked,
|
|
18768
|
-
conditionCount: acc.conditionCount,
|
|
18769
|
-
bump: acc.bump,
|
|
18770
|
-
vaultBump: acc.vaultBump
|
|
18771
|
-
};
|
|
18772
|
-
} catch {
|
|
18773
|
-
return null;
|
|
18774
|
-
}
|
|
18775
|
-
}
|
|
18776
|
-
async fetchPosition(condition, outcomeIndex, owner = this.walletPubkey) {
|
|
18777
|
-
try {
|
|
18778
|
-
const [pda] = PDA.position(condition, outcomeIndex, owner, this.programIds);
|
|
18779
|
-
const acc = await this.program.account.position.fetch(pda);
|
|
18780
|
-
return {
|
|
18781
|
-
owner: acc.owner,
|
|
18782
|
-
condition: acc.condition,
|
|
18783
|
-
outcomeIndex: acc.outcomeIndex,
|
|
18784
|
-
balance: acc.balance,
|
|
18785
|
-
bump: acc.bump
|
|
18786
|
-
};
|
|
18787
|
-
} catch {
|
|
18788
|
-
return null;
|
|
18789
|
-
}
|
|
18790
|
-
}
|
|
18791
|
-
/** YES = outcome index 1, NO = outcome index 0. */
|
|
18792
|
-
async fetchBothPositions(condition, owner = this.walletPubkey) {
|
|
18793
|
-
const [yes, no] = await Promise.all([
|
|
18794
|
-
this.fetchPosition(condition, 1, owner),
|
|
18795
|
-
this.fetchPosition(condition, 0, owner)
|
|
18796
|
-
]);
|
|
18797
|
-
return { yes, no };
|
|
18798
|
-
}
|
|
18799
|
-
/** Thin wrapper: fetch position for a single outcome token (0=NO, 1=YES). */
|
|
18800
|
-
async fetchTokenBalance(condition, tokenId, owner = this.walletPubkey) {
|
|
18801
|
-
return this.fetchPosition(condition, tokenId, owner);
|
|
18802
|
-
}
|
|
18803
|
-
// ─── PDA helpers (public for consumers) ──────────────────────────────────────
|
|
18804
|
-
yesMintPda(condition) {
|
|
18805
|
-
return PDA.yesMint(condition, this.programIds)[0];
|
|
18806
|
-
}
|
|
18807
|
-
noMintPda(condition) {
|
|
18808
|
-
return PDA.noMint(condition, this.programIds)[0];
|
|
18809
|
-
}
|
|
18810
|
-
mintAuthorityPda(condition) {
|
|
18811
|
-
return PDA.mintAuthority(condition, this.programIds)[0];
|
|
18812
|
-
}
|
|
18813
|
-
collateralVaultPda(collateralMint) {
|
|
18814
|
-
return PDA.collateralVault(collateralMint, this.programIds)[0];
|
|
18815
|
-
}
|
|
18816
|
-
};
|
|
18817
|
-
var ClobClient = class {
|
|
18818
|
-
constructor(program, provider, programIds, networkConfig) {
|
|
18819
|
-
/** Cache: conditionPda.toBase58() → marketOracleVault ATA */
|
|
18820
|
-
this._marketOracleVaultCache = /* @__PURE__ */ new Map();
|
|
18821
|
-
/** ALT cache: condition.toBase58() → loaded ALT account */
|
|
18822
|
-
this._altCache = /* @__PURE__ */ new Map();
|
|
18823
|
-
this.program = program;
|
|
18824
|
-
this.provider = provider;
|
|
18825
|
-
this.programIds = programIds;
|
|
18826
|
-
this.networkConfig = networkConfig;
|
|
18827
|
-
}
|
|
18828
|
-
async companyAddress() {
|
|
18829
|
-
if (!this.feeClient || !this.feeConfigOwner) return void 0;
|
|
18830
|
-
if (!this._companyAddress) {
|
|
18831
|
-
const cfg = await this.feeClient.fetchFeeConfig(this.feeConfigOwner);
|
|
18832
|
-
if (cfg) {
|
|
18833
|
-
this._companyAddress = cfg.companyAddress;
|
|
18834
|
-
this._referralVault = cfg.referralVault;
|
|
18835
|
-
}
|
|
18836
|
-
}
|
|
18837
|
-
return this._companyAddress;
|
|
18838
|
-
}
|
|
18839
|
-
async referralVault() {
|
|
18840
|
-
await this.companyAddress();
|
|
18841
|
-
return this._referralVault;
|
|
18842
|
-
}
|
|
18843
|
-
/**
|
|
18844
|
-
* Derive marketOracleVault ATA for a condition, cached per condition.
|
|
18845
|
-
* Works for presale markets (market_oracle initialized by approvePresale).
|
|
18846
|
-
* Returns undefined if ctfClient/qmConfigPda not injected or marketOracle not configured.
|
|
18847
|
-
*/
|
|
18848
|
-
async getMarketOracleVault(condition, collateralMint) {
|
|
18849
|
-
if (!this.ctfClient || !this.qmConfigPda || !this.programIds.marketOracle) return void 0;
|
|
18850
|
-
const key = condition.toBase58();
|
|
18851
|
-
const cached = this._marketOracleVaultCache.get(key);
|
|
18852
|
-
if (cached) return cached;
|
|
18853
|
-
const cond = await this.ctfClient.fetchCondition(condition);
|
|
18854
|
-
if (!cond) return void 0;
|
|
18855
|
-
const [questionPda] = PDA.question(this.qmConfigPda, cond.questionId, this.programIds);
|
|
18856
|
-
const [marketOraclePda] = PDA.marketOraclePda(questionPda, this.programIds);
|
|
18857
|
-
const vault = getAssociatedTokenAddressSync(collateralMint, marketOraclePda, true);
|
|
18858
|
-
this._marketOracleVaultCache.set(key, vault);
|
|
18859
|
-
return vault;
|
|
18860
|
-
}
|
|
18861
|
-
/**
|
|
18862
|
-
* Returns a createATA ix for the oracle vault when:
|
|
18863
|
-
* - takerFee > 0
|
|
18864
|
-
* - marketFeeOverride exists for the condition
|
|
18865
|
-
* - oracle vault ATA is not yet initialized
|
|
18866
|
-
* Idempotent — safe to call every tx; returns null if vault already exists.
|
|
18867
|
-
*/
|
|
18868
|
-
async buildInitOracleVaultIfNeeded(condition, collateralMint, takerFee, payer) {
|
|
18869
|
-
if (takerFee.isZero()) return null;
|
|
18870
|
-
if (!this.feeConfigOwner || !this.programIds.feeManagement) return null;
|
|
18871
|
-
if (!this.ctfClient || !this.qmConfigPda || !this.programIds.marketOracle) return null;
|
|
18872
|
-
const companyAddr = await this.companyAddress();
|
|
18873
|
-
const refVault = await this.referralVault();
|
|
18874
|
-
if (!companyAddr || !refVault) return null;
|
|
18875
|
-
const feeOverridePda = PDA.marketFeeOverride(condition, this.programIds)[0];
|
|
18876
|
-
const cond = await this.ctfClient.fetchCondition(condition);
|
|
18877
|
-
if (!cond) return null;
|
|
18878
|
-
const [questionPda] = PDA.question(this.qmConfigPda, cond.questionId, this.programIds);
|
|
18879
|
-
const [marketOraclePda] = PDA.marketOraclePda(questionPda, this.programIds);
|
|
18880
|
-
const vault = getAssociatedTokenAddressSync(collateralMint, marketOraclePda, true);
|
|
18881
|
-
const [feeOverrideInfo, vaultInfo] = await Promise.all([
|
|
18882
|
-
this.provider.connection.getAccountInfo(feeOverridePda),
|
|
18883
|
-
this.provider.connection.getAccountInfo(vault)
|
|
18884
|
-
]);
|
|
18885
|
-
if (!feeOverrideInfo) return null;
|
|
18886
|
-
if (vaultInfo) return null;
|
|
18887
|
-
return createAssociatedTokenAccountIdempotentInstruction(
|
|
18888
|
-
payer,
|
|
18889
|
-
vault,
|
|
18890
|
-
marketOraclePda,
|
|
18891
|
-
collateralMint
|
|
18892
|
-
);
|
|
18893
|
-
}
|
|
18894
|
-
get walletPubkey() {
|
|
18895
|
-
return this.provider.wallet.publicKey;
|
|
18896
|
-
}
|
|
18897
|
-
/**
|
|
18898
|
-
* Get or create an ALT for a condition.
|
|
18899
|
-
* Includes order_record PDAs for taker + all makers so match tx stays under 1232 bytes.
|
|
18900
|
-
*/
|
|
18901
|
-
async ensureAlt(condition, collateralMint, takerSigned, makers) {
|
|
18902
|
-
const cacheKey = condition.toBase58();
|
|
18903
|
-
if (this._altCache.has(cacheKey)) {
|
|
18904
|
-
return this._altCache.get(cacheKey);
|
|
18905
|
-
}
|
|
18906
|
-
const { connection } = this.provider;
|
|
18907
|
-
const payer = this.walletPubkey;
|
|
18908
|
-
const taker = takerSigned.order.maker;
|
|
18909
|
-
const takerNonce = takerSigned.order.nonce;
|
|
18910
|
-
const tokenId = takerSigned.order.tokenId;
|
|
18911
|
-
const [yesMint] = PDA.yesMint(condition, this.programIds);
|
|
18912
|
-
const [noMint] = PDA.noMint(condition, this.programIds);
|
|
18913
|
-
const [extraAccountMeta] = PDA.extraAccountMetaList(yesMint, this.programIds);
|
|
18914
|
-
const [hookConfig] = PDA.hookConfig(this.programIds);
|
|
18915
|
-
const [takerOrderStatus] = PDA.orderStatus(taker, takerNonce, this.programIds);
|
|
18916
|
-
const [takerOrderRecord] = PDA.orderRecord(taker, takerNonce, this.programIds);
|
|
18917
|
-
const [takerPosition] = PDA.position(condition, tokenId, taker, this.programIds);
|
|
18918
|
-
const clobConfigPda = this.configPda();
|
|
18919
|
-
const outcomeMint = tokenId === 1 ? yesMint : noMint;
|
|
18920
|
-
const feeRecipientAddr = (await this.fetchConfig())?.feeRecipient;
|
|
18921
|
-
const addresses = [
|
|
18922
|
-
Ed25519Program.programId,
|
|
18923
|
-
this.programIds.clobExchange,
|
|
18924
|
-
this.programIds.conditionalTokens,
|
|
18925
|
-
this.programIds.hook,
|
|
18926
|
-
TOKEN_PROGRAM_ID,
|
|
18927
|
-
TOKEN_2022_PROGRAM_ID,
|
|
18928
|
-
SystemProgram.programId,
|
|
18929
|
-
SYSVAR_INSTRUCTIONS_PUBKEY,
|
|
18930
|
-
clobConfigPda,
|
|
18931
|
-
hookConfig,
|
|
18932
|
-
condition,
|
|
18933
|
-
yesMint,
|
|
18934
|
-
noMint,
|
|
18935
|
-
extraAccountMeta,
|
|
18936
|
-
taker,
|
|
18937
|
-
getAssociatedTokenAddressSync(collateralMint, taker),
|
|
18938
|
-
getAssociatedTokenAddressSync(outcomeMint, taker, false, TOKEN_2022_PROGRAM_ID),
|
|
18939
|
-
takerPosition,
|
|
18940
|
-
takerOrderStatus,
|
|
18941
|
-
takerOrderRecord
|
|
18942
|
-
];
|
|
18943
|
-
if (feeRecipientAddr) addresses.push(feeRecipientAddr);
|
|
18944
|
-
const [collateralVault] = PDA.collateralVault(collateralMint, this.programIds);
|
|
18945
|
-
const [vaultToken] = PDA.vaultToken(collateralMint, this.programIds);
|
|
18946
|
-
const [mintAuth] = PDA.mintAuthority(condition, this.programIds);
|
|
18947
|
-
const [extraMetaNo] = PDA.extraAccountMetaList(noMint, this.programIds);
|
|
18948
|
-
const clobUsdcAta = getAssociatedTokenAddressSync(collateralMint, clobConfigPda, true);
|
|
18949
|
-
const clobYesAta = getAssociatedTokenAddressSync(yesMint, clobConfigPda, true, TOKEN_2022_PROGRAM_ID);
|
|
18950
|
-
const clobNoAta = getAssociatedTokenAddressSync(noMint, clobConfigPda, true, TOKEN_2022_PROGRAM_ID);
|
|
18951
|
-
const [clobYesPos] = PDA.position(condition, 1, clobConfigPda, this.programIds);
|
|
18952
|
-
const [clobNoPos] = PDA.position(condition, 0, clobConfigPda, this.programIds);
|
|
18953
|
-
addresses.push(
|
|
18954
|
-
collateralVault,
|
|
18955
|
-
vaultToken,
|
|
18956
|
-
mintAuth,
|
|
18957
|
-
extraMetaNo,
|
|
18958
|
-
clobUsdcAta,
|
|
18959
|
-
clobYesAta,
|
|
18960
|
-
clobNoAta,
|
|
18961
|
-
clobYesPos,
|
|
18962
|
-
clobNoPos,
|
|
18963
|
-
collateralMint,
|
|
18964
|
-
ASSOCIATED_TOKEN_PROGRAM_ID
|
|
18965
|
-
);
|
|
18966
|
-
for (const m of makers) {
|
|
18967
|
-
const seller = m.order.maker;
|
|
18968
|
-
const makerTokenId = m.order.tokenId;
|
|
18969
|
-
const makerMint = makerTokenId === 1 ? yesMint : noMint;
|
|
18970
|
-
const [sellerPos] = PDA.position(condition, makerTokenId, seller, this.programIds);
|
|
18971
|
-
const [sellerStatus] = PDA.orderStatus(seller, m.order.nonce, this.programIds);
|
|
18972
|
-
const [sellerRecord] = PDA.orderRecord(seller, m.order.nonce, this.programIds);
|
|
18973
|
-
addresses.push(
|
|
18974
|
-
seller,
|
|
18975
|
-
sellerRecord,
|
|
18976
|
-
getAssociatedTokenAddressSync(makerMint, seller, false, TOKEN_2022_PROGRAM_ID),
|
|
18977
|
-
getAssociatedTokenAddressSync(collateralMint, seller),
|
|
18978
|
-
sellerPos,
|
|
18979
|
-
sellerStatus
|
|
18980
|
-
);
|
|
18981
|
-
}
|
|
18982
|
-
if (this.programIds.feeManagement && this.feeConfigOwner) {
|
|
18983
|
-
const companyAddr = await this.companyAddress();
|
|
18984
|
-
const refVault = await this.referralVault();
|
|
18985
|
-
addresses.push(
|
|
18986
|
-
this.programIds.feeManagement,
|
|
18987
|
-
PDA.feeConfig(this.feeConfigOwner, this.programIds)[0],
|
|
18988
|
-
PDA.marketFeeOverride(condition, this.programIds)[0]
|
|
18989
|
-
);
|
|
18990
|
-
if (companyAddr) {
|
|
18991
|
-
addresses.push(getAssociatedTokenAddressSync(collateralMint, companyAddr));
|
|
18992
|
-
}
|
|
18993
|
-
const oracleVaultForAlt = await this.getMarketOracleVault(condition, collateralMint) ?? payer;
|
|
18994
|
-
addresses.push(oracleVaultForAlt);
|
|
18995
|
-
if (refVault) {
|
|
18996
|
-
addresses.push(refVault);
|
|
18997
|
-
}
|
|
18998
|
-
}
|
|
18999
|
-
const slot = await connection.getSlot("finalized");
|
|
19000
|
-
const [createIx, altAddress] = AddressLookupTableProgram.createLookupTable({
|
|
19001
|
-
authority: payer,
|
|
19002
|
-
payer,
|
|
19003
|
-
recentSlot: slot
|
|
19004
|
-
});
|
|
19005
|
-
const BATCH = 30;
|
|
19006
|
-
const extendIxs = [];
|
|
19007
|
-
for (let i = 0; i < addresses.length; i += BATCH) {
|
|
19008
|
-
extendIxs.push(AddressLookupTableProgram.extendLookupTable({
|
|
19009
|
-
payer,
|
|
19010
|
-
authority: payer,
|
|
19011
|
-
lookupTable: altAddress,
|
|
19012
|
-
addresses: addresses.slice(i, i + BATCH)
|
|
19013
|
-
}));
|
|
19014
|
-
}
|
|
19015
|
-
await this._sendLegacyTx([createIx, extendIxs[0]]);
|
|
19016
|
-
for (let i = 1; i < extendIxs.length; i++) {
|
|
19017
|
-
await this._sendLegacyTx([extendIxs[i]]);
|
|
19018
|
-
}
|
|
19019
|
-
for (let attempt = 0; attempt < 30; attempt++) {
|
|
19020
|
-
await new Promise((r) => setTimeout(r, 1e3));
|
|
19021
|
-
const res = await connection.getAddressLookupTable(altAddress);
|
|
19022
|
-
if (res.value && res.value.state.addresses.length === addresses.length) {
|
|
19023
|
-
this._altCache.set(cacheKey, res.value);
|
|
19024
|
-
return res.value;
|
|
19025
|
-
}
|
|
19026
|
-
}
|
|
19027
|
-
throw new Error(`ALT ${altAddress.toBase58()} not active after 30s`);
|
|
19028
|
-
}
|
|
19029
|
-
async _sendLegacyTxSig(instructions) {
|
|
19030
|
-
const { connection } = this.provider;
|
|
19031
|
-
const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash();
|
|
19032
|
-
const { Transaction: Transaction15 } = await import('@solana/web3.js');
|
|
19033
|
-
const tx = new Transaction15();
|
|
19034
|
-
tx.recentBlockhash = blockhash;
|
|
19035
|
-
tx.feePayer = this.walletPubkey;
|
|
19036
|
-
tx.add(...instructions);
|
|
19037
|
-
const signed = await this.provider.wallet.signTransaction(tx);
|
|
19038
|
-
const sig = await connection.sendRawTransaction(signed.serialize(), { skipPreflight: true });
|
|
19039
|
-
const result = await connection.confirmTransaction({ signature: sig, blockhash, lastValidBlockHeight }, "confirmed");
|
|
19040
|
-
if (result.value.err) {
|
|
19041
|
-
const txInfo = await connection.getTransaction(sig, { maxSupportedTransactionVersion: 0 });
|
|
19042
|
-
const logs = txInfo?.meta?.logMessages ?? [];
|
|
19043
|
-
const err = new Error(`Register tx failed: ${JSON.stringify(result.value.err)}
|
|
19044
|
-
${logs.join("\n")}`);
|
|
19045
|
-
err.logs = logs;
|
|
19046
|
-
throw err;
|
|
19047
|
-
}
|
|
19048
|
-
return sig;
|
|
19049
|
-
}
|
|
19050
|
-
async _sendLegacyTx(instructions) {
|
|
19051
|
-
await this._sendLegacyTxSig(instructions);
|
|
19052
|
-
}
|
|
19053
|
-
async _ensureClobOutcomeAtas(yesMint, noMint, clobConfig, clobYesAta, clobNoAta) {
|
|
19054
|
-
const { connection } = this.provider;
|
|
19055
|
-
const [yesInfo, noInfo] = await Promise.all([
|
|
19056
|
-
connection.getAccountInfo(clobYesAta),
|
|
19057
|
-
connection.getAccountInfo(clobNoAta)
|
|
19058
|
-
]);
|
|
19059
|
-
const { createAssociatedTokenAccountIdempotentInstruction: createAssociatedTokenAccountIdempotentInstruction7 } = await import('@solana/spl-token');
|
|
19060
|
-
const ixs = [];
|
|
19061
|
-
if (!yesInfo) {
|
|
19062
|
-
ixs.push(createAssociatedTokenAccountIdempotentInstruction7(
|
|
19063
|
-
this.walletPubkey,
|
|
19064
|
-
clobYesAta,
|
|
19065
|
-
clobConfig,
|
|
19066
|
-
yesMint,
|
|
19067
|
-
TOKEN_2022_PROGRAM_ID
|
|
19068
|
-
));
|
|
19069
|
-
}
|
|
19070
|
-
if (!noInfo) {
|
|
19071
|
-
ixs.push(createAssociatedTokenAccountIdempotentInstruction7(
|
|
19072
|
-
this.walletPubkey,
|
|
19073
|
-
clobNoAta,
|
|
19074
|
-
clobConfig,
|
|
19075
|
-
noMint,
|
|
19076
|
-
TOKEN_2022_PROGRAM_ID
|
|
19077
|
-
));
|
|
19078
|
-
}
|
|
19079
|
-
if (ixs.length > 0) {
|
|
19080
|
-
await this._sendLegacyTx(ixs);
|
|
19081
|
-
}
|
|
19082
|
-
}
|
|
19083
|
-
/**
|
|
19084
|
-
* Send a match transaction as versioned (v0) with optional ALT.
|
|
19085
|
-
* Both operator wallet and payer (this.provider.wallet) sign.
|
|
19086
|
-
*/
|
|
19087
|
-
async sendMatchTx(instructions, lookupTable, whitelistedWallet) {
|
|
19088
|
-
const { connection } = this.provider;
|
|
19089
|
-
const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash();
|
|
19090
|
-
const cuLimit = ComputeBudgetProgram.setComputeUnitLimit({ units: 14e5 });
|
|
19091
|
-
const heapFrame = ComputeBudgetProgram.requestHeapFrame({ bytes: 262144 });
|
|
19092
|
-
const message = new TransactionMessage({
|
|
19093
|
-
payerKey: this.walletPubkey,
|
|
19094
|
-
recentBlockhash: blockhash,
|
|
19095
|
-
instructions: [cuLimit, heapFrame, ...instructions]
|
|
19096
|
-
}).compileToV0Message(lookupTable ? [lookupTable] : []);
|
|
19097
|
-
const vtx = new VersionedTransaction(message);
|
|
19098
|
-
const signers = [this.provider.wallet.payer];
|
|
19099
|
-
if (whitelistedWallet && !whitelistedWallet.publicKey.equals(this.walletPubkey)) {
|
|
19100
|
-
signers.push(whitelistedWallet.payer);
|
|
19101
|
-
}
|
|
19102
|
-
vtx.sign(signers);
|
|
19103
|
-
const sig = await connection.sendRawTransaction(vtx.serialize(), {
|
|
19104
|
-
skipPreflight: false
|
|
19105
|
-
});
|
|
19106
|
-
const result = await connection.confirmTransaction(
|
|
19107
|
-
{ signature: sig, blockhash, lastValidBlockHeight },
|
|
19108
|
-
"confirmed"
|
|
19109
|
-
);
|
|
19110
|
-
if (result.value.err) {
|
|
19111
|
-
const txInfo = await connection.getTransaction(sig, { maxSupportedTransactionVersion: 0 });
|
|
19112
|
-
const logs = txInfo?.meta?.logMessages ?? [];
|
|
19113
|
-
const err = new Error(`Match tx failed: ${JSON.stringify(result.value.err)}
|
|
19114
|
-
${logs.join("\n")}`);
|
|
19115
|
-
err.logs = logs;
|
|
19116
|
-
throw err;
|
|
19117
|
-
}
|
|
19118
|
-
return sig;
|
|
19119
|
-
}
|
|
19120
|
-
configPda() {
|
|
19121
|
-
return PDA.clobConfig(this.programIds)[0];
|
|
19122
|
-
}
|
|
19123
|
-
// ─── Register / Cancel ───────────────────────────────────────────────────────
|
|
19124
|
-
/**
|
|
19125
|
-
* Register a signed order on-chain.
|
|
19126
|
-
* Sends Ed25519 precompile ix + register_order ix in one legacy tx.
|
|
19127
|
-
* Called at match time (engine-triggered), not at order placement.
|
|
19128
|
-
*/
|
|
19129
|
-
async registerOrder(signed) {
|
|
19130
|
-
const nonce = signed.order.nonce;
|
|
19131
|
-
const orderSigner = signed.order.maker;
|
|
19132
|
-
const [orderRecord] = PDA.orderRecord(orderSigner, nonce, this.programIds);
|
|
19133
|
-
const ed25519Ix = buildBatchedEd25519Instruction([signed]);
|
|
19134
|
-
const [orderStatus] = PDA.orderStatus(orderSigner, nonce, this.programIds);
|
|
19135
|
-
const registerIx = await this.program.methods.registerOrder(nonce).accounts({
|
|
19136
|
-
payer: this.walletPubkey,
|
|
19137
|
-
clobConfig: this.configPda(),
|
|
19138
|
-
ixSysvar: IX_SYSVAR,
|
|
19139
|
-
orderSigner,
|
|
19140
|
-
orderRecord,
|
|
19141
|
-
orderStatus,
|
|
19142
|
-
systemProgram: SystemProgram.programId
|
|
19143
|
-
}).instruction();
|
|
19144
|
-
return this._sendLegacyTxSig([ed25519Ix, registerIx]);
|
|
19145
|
-
}
|
|
19146
|
-
/** Register only if the PDA doesn't exist yet (idempotent). */
|
|
19147
|
-
async registerOrderIfNeeded(signed) {
|
|
19148
|
-
const [pda] = PDA.orderRecord(signed.order.maker, signed.order.nonce, this.programIds);
|
|
19149
|
-
const existing = await this.program.account.signedOrderRecord.fetchNullable(pda);
|
|
19150
|
-
if (!existing) {
|
|
19151
|
-
await this.registerOrder(signed);
|
|
19152
|
-
}
|
|
19153
|
-
}
|
|
19154
|
-
// ─── Register CollectFeeOrder ────────────────────────────────────────────────
|
|
19155
|
-
/**
|
|
19156
|
-
* Build a legacy Transaction to register a CollectFeeOrder on-chain.
|
|
19157
|
-
* Must be signed and sent before calling buildBatchCollectRedeemEarlyTx.
|
|
19158
|
-
*
|
|
19159
|
-
* Flow: [Ed25519 ix (1 user sig) + register_collect_fee_order ix]
|
|
19160
|
-
* Caller signs with payer keypair and sends.
|
|
19161
|
-
*/
|
|
19162
|
-
async buildRegisterCollectFeeOrderTx(signedOrder, payer) {
|
|
19163
|
-
const { order } = signedOrder;
|
|
19164
|
-
const [collectFeeOrderRecord] = PDA.collectFeeOrderRecord(order.user, order.nonce, this.programIds);
|
|
19165
|
-
const ed25519Ix = buildBatchedCollectFeeEd25519Instruction([signedOrder]);
|
|
19166
|
-
const registerIx = await this.program.methods.registerCollectFeeOrder(order.nonce).accounts({
|
|
19167
|
-
payer,
|
|
19168
|
-
clobConfig: this.configPda(),
|
|
19169
|
-
ixSysvar: IX_SYSVAR,
|
|
19170
|
-
orderSigner: order.user,
|
|
19171
|
-
collectFeeOrderRecord,
|
|
19172
|
-
systemProgram: SystemProgram.programId
|
|
19173
|
-
}).instruction();
|
|
19174
|
-
const { blockhash } = await this.provider.connection.getLatestBlockhash();
|
|
19175
|
-
const tx = new Transaction();
|
|
19176
|
-
tx.recentBlockhash = blockhash;
|
|
19177
|
-
tx.feePayer = payer;
|
|
19178
|
-
tx.add(ed25519Ix, registerIx);
|
|
19179
|
-
return tx;
|
|
19180
|
-
}
|
|
19181
|
-
/**
|
|
19182
|
-
* Register a CollectFeeOrder on-chain and send immediately (operator-signed flow).
|
|
19183
|
-
* Idempotent — skips if PDA already exists.
|
|
19184
|
-
*/
|
|
19185
|
-
async registerCollectFeeOrderIfNeeded(signedOrder) {
|
|
19186
|
-
const [pda] = PDA.collectFeeOrderRecord(
|
|
19187
|
-
signedOrder.order.user,
|
|
19188
|
-
signedOrder.order.nonce,
|
|
19189
|
-
this.programIds
|
|
19190
|
-
);
|
|
19191
|
-
const existing = await this.program.account.collectFeeOrderRecord?.fetchNullable(pda);
|
|
19192
|
-
if (!existing) {
|
|
19193
|
-
const tx = await this.buildRegisterCollectFeeOrderTx(signedOrder, this.walletPubkey);
|
|
19194
|
-
await this._sendLegacyTx(tx.instructions);
|
|
19195
|
-
}
|
|
19196
|
-
}
|
|
19197
|
-
/** Cancel an order — closes its OrderRecord PDA and returns rent to maker. */
|
|
19198
|
-
async cancelOrder(nonce) {
|
|
19199
|
-
const [orderRecord] = PDA.orderRecord(this.walletPubkey, nonce, this.programIds);
|
|
19200
|
-
const sig = await this.program.methods.cancelOrder(nonce).accounts({
|
|
19201
|
-
maker: this.walletPubkey,
|
|
19202
|
-
orderRecord,
|
|
19203
|
-
systemProgram: SystemProgram.programId
|
|
19204
|
-
}).rpc();
|
|
19205
|
-
return { signature: sig };
|
|
19206
|
-
}
|
|
19207
|
-
// ─── Admin ───────────────────────────────────────────────────────────────────
|
|
19208
|
-
async initialize(operators, feeRecipient, feeRateBps) {
|
|
19209
|
-
const sig = await this.program.methods.initializeClob(
|
|
19210
|
-
operators,
|
|
19211
|
-
feeRecipient,
|
|
19212
|
-
feeRateBps,
|
|
19213
|
-
this.programIds.conditionalTokens
|
|
19214
|
-
).accounts({
|
|
19215
|
-
owner: this.walletPubkey,
|
|
19216
|
-
clobConfig: this.configPda(),
|
|
19217
|
-
systemProgram: SystemProgram.programId
|
|
19218
|
-
}).rpc();
|
|
19219
|
-
return { signature: sig };
|
|
19220
|
-
}
|
|
19221
|
-
async addOperator(operator) {
|
|
19222
|
-
const sig = await this.program.methods.addOperator(operator).accounts({
|
|
19223
|
-
admin: this.walletPubkey,
|
|
19224
|
-
clobConfig: this.configPda()
|
|
19225
|
-
}).rpc();
|
|
19226
|
-
return { signature: sig };
|
|
19227
|
-
}
|
|
19228
|
-
async removeOperator(operator) {
|
|
19229
|
-
const sig = await this.program.methods.removeOperator(operator).accounts({
|
|
19230
|
-
admin: this.walletPubkey,
|
|
19231
|
-
clobConfig: this.configPda()
|
|
19232
|
-
}).rpc();
|
|
19233
|
-
return { signature: sig };
|
|
19234
|
-
}
|
|
19235
|
-
async setPaused(paused) {
|
|
19236
|
-
const sig = await this.program.methods.setPaused(paused).accounts({
|
|
19237
|
-
admin: this.walletPubkey,
|
|
19238
|
-
clobConfig: this.configPda()
|
|
19239
|
-
}).rpc();
|
|
19240
|
-
return { signature: sig };
|
|
19241
|
-
}
|
|
19242
|
-
async forceResetClob(programData, newAdmin, newOperators, newFeeRecipient, newFeeRateBps) {
|
|
19243
|
-
const sig = await this.program.methods.forceResetClob(newAdmin, newOperators, newFeeRecipient, newFeeRateBps).accounts({
|
|
19244
|
-
upgradeAuthority: this.walletPubkey,
|
|
19245
|
-
programData,
|
|
19246
|
-
clobConfig: this.configPda()
|
|
19247
|
-
}).rpc();
|
|
19248
|
-
return { signature: sig };
|
|
19249
|
-
}
|
|
19250
|
-
// ─── Match instructions ───────────────────────────────────────────────────────
|
|
19251
|
-
/**
|
|
19252
|
-
* Build match_complementary instruction (no Ed25519 — OrderRecord PDAs used).
|
|
19253
|
-
*
|
|
19254
|
-
* remaining_accounts layout:
|
|
19255
|
-
* [seller, order_record, seller_token, seller_collateral, seller_position, sell_status] × N
|
|
19256
|
-
* [extraAccountMetaList, hookConfig, hookProgram]
|
|
19257
|
-
* [feeManagement, fee_config, mkt_override, company_ata, oracle_vault] (when fee > 0)
|
|
19258
|
-
*/
|
|
19259
|
-
async buildMatchComplementaryIxs(takerSigned, makersSigned, collateralMint, feeRecipient, operator, opts, useTakerPrice = false, skipCrossingCheck = true) {
|
|
19260
|
-
const condition = takerSigned.order.condition;
|
|
19261
|
-
const tokenId = takerSigned.order.tokenId;
|
|
19262
|
-
const taker = takerSigned.order.maker;
|
|
19263
|
-
const takerNonce = takerSigned.order.nonce;
|
|
19264
|
-
const fillAmount = opts?.fillAmount ?? new anchor6.BN("18446744073709551615");
|
|
19265
|
-
const [outcomeMint] = tokenId === 1 ? PDA.yesMint(condition, this.programIds) : PDA.noMint(condition, this.programIds);
|
|
19266
|
-
const [takerOrderRecord] = PDA.orderRecord(taker, takerNonce, this.programIds);
|
|
19267
|
-
const takerCollateral = getAssociatedTokenAddressSync(collateralMint, taker);
|
|
19268
|
-
const takerTokenAccount = getAssociatedTokenAddressSync(outcomeMint, taker, false, TOKEN_2022_PROGRAM_ID);
|
|
19269
|
-
const [takerPosition] = PDA.position(condition, tokenId, taker, this.programIds);
|
|
19270
|
-
const [takerOrderStatus] = PDA.orderStatus(taker, takerNonce, this.programIds);
|
|
19271
|
-
const makerAccounts = [];
|
|
19272
|
-
for (const ms of makersSigned) {
|
|
19273
|
-
const seller = ms.order.maker;
|
|
19274
|
-
const [sellerRecord] = PDA.orderRecord(seller, ms.order.nonce, this.programIds);
|
|
19275
|
-
const sellerToken = getAssociatedTokenAddressSync(outcomeMint, seller, false, TOKEN_2022_PROGRAM_ID);
|
|
19276
|
-
const sellerCollateral = getAssociatedTokenAddressSync(collateralMint, seller);
|
|
19277
|
-
const [sellerPosition] = PDA.position(condition, tokenId, seller, this.programIds);
|
|
19278
|
-
const [sellerStatus] = PDA.orderStatus(seller, ms.order.nonce, this.programIds);
|
|
19279
|
-
makerAccounts.push(
|
|
19280
|
-
{ pubkey: seller, isSigner: false, isWritable: false },
|
|
19281
|
-
{ pubkey: sellerRecord, isSigner: false, isWritable: false },
|
|
19282
|
-
{ pubkey: sellerToken, isSigner: false, isWritable: true },
|
|
19283
|
-
{ pubkey: sellerCollateral, isSigner: false, isWritable: true },
|
|
19284
|
-
{ pubkey: sellerPosition, isSigner: false, isWritable: true },
|
|
19285
|
-
{ pubkey: sellerStatus, isSigner: false, isWritable: true }
|
|
19286
|
-
);
|
|
19287
|
-
}
|
|
19288
|
-
const [extraAccountMetaList] = PDA.extraAccountMetaList(outcomeMint, this.programIds);
|
|
19289
|
-
const [hookConfig] = PDA.hookConfig(this.programIds);
|
|
19290
|
-
const hookAccounts = [
|
|
19291
|
-
{ pubkey: extraAccountMetaList, isSigner: false, isWritable: false },
|
|
19292
|
-
{ pubkey: hookConfig, isSigner: false, isWritable: false },
|
|
19293
|
-
{ pubkey: this.programIds.hook, isSigner: false, isWritable: false }
|
|
19294
|
-
];
|
|
19295
|
-
let feeAccounts = [];
|
|
19296
|
-
if (takerSigned.order.fee.gtn(0) && this.programIds.feeManagement && this.feeConfigOwner) {
|
|
19297
|
-
const companyAddr = await this.companyAddress();
|
|
19298
|
-
const refVault = await this.referralVault();
|
|
19299
|
-
if (companyAddr && refVault) {
|
|
19300
|
-
const feeOverridePda = PDA.marketFeeOverride(condition, this.programIds)[0];
|
|
19301
|
-
const feeOverrideExists = await this.provider.connection.getAccountInfo(feeOverridePda);
|
|
19302
|
-
if (feeOverrideExists) {
|
|
19303
|
-
const oracleVault = opts?.marketOracleVault ?? await this.getMarketOracleVault(condition, collateralMint) ?? this.walletPubkey;
|
|
19304
|
-
feeAccounts = [
|
|
19305
|
-
{ pubkey: this.programIds.feeManagement, isSigner: false, isWritable: false },
|
|
19306
|
-
{ pubkey: PDA.feeConfig(this.feeConfigOwner, this.programIds)[0], isSigner: false, isWritable: false },
|
|
19307
|
-
{ pubkey: feeOverridePda, isSigner: false, isWritable: false },
|
|
19308
|
-
{ pubkey: getAssociatedTokenAddressSync(collateralMint, companyAddr), isSigner: false, isWritable: true },
|
|
19309
|
-
{ pubkey: oracleVault, isSigner: false, isWritable: true },
|
|
19310
|
-
{ pubkey: refVault, isSigner: false, isWritable: true }
|
|
19311
|
-
];
|
|
19312
|
-
}
|
|
19313
|
-
}
|
|
19314
|
-
}
|
|
19315
|
-
const matchIx = await this.program.methods.matchComplementary(takerNonce, fillAmount, useTakerPrice, skipCrossingCheck).accounts({
|
|
19316
|
-
operator,
|
|
19317
|
-
payer: this.walletPubkey,
|
|
19318
|
-
clobConfig: this.configPda(),
|
|
19319
|
-
condition,
|
|
19320
|
-
taker,
|
|
19321
|
-
takerOrderRecord,
|
|
19322
|
-
takerCollateral,
|
|
19323
|
-
takerTokenAccount,
|
|
19324
|
-
takerPosition,
|
|
19325
|
-
takerOrderStatus,
|
|
19326
|
-
feeRecipient,
|
|
19327
|
-
outcomeMint,
|
|
19328
|
-
conditionalTokensProgram: this.programIds.conditionalTokens,
|
|
19329
|
-
tokenProgram: TOKEN_PROGRAM_ID,
|
|
19330
|
-
token2022Program: TOKEN_2022_PROGRAM_ID,
|
|
19331
|
-
systemProgram: SystemProgram.programId
|
|
19332
|
-
}).remainingAccounts([...makerAccounts, ...hookAccounts, ...feeAccounts]).instruction();
|
|
19333
|
-
return [matchIx];
|
|
19334
|
-
}
|
|
19335
|
-
/**
|
|
19336
|
-
* COMPLEMENTARY: 1 taker (BUY) + N makers (SELL), same tokenId.
|
|
19337
|
-
* Phase 1: register taker + all makers in parallel.
|
|
19338
|
-
* Phase 2: 1 atomic match tx.
|
|
19339
|
-
*/
|
|
19340
|
-
async matchComplementary(takerSigned, makersSigned, collateralMint, feeRecipient, operatorWallet, lookupTable, opts) {
|
|
19341
|
-
await Promise.all([
|
|
19342
|
-
this.registerOrderIfNeeded(takerSigned),
|
|
19343
|
-
...makersSigned.map((m) => this.registerOrderIfNeeded(m))
|
|
19344
|
-
]);
|
|
19345
|
-
const ixs = await this.buildMatchComplementaryIxs(
|
|
19346
|
-
takerSigned,
|
|
19347
|
-
makersSigned,
|
|
19348
|
-
collateralMint,
|
|
19349
|
-
feeRecipient,
|
|
19350
|
-
operatorWallet.publicKey,
|
|
19351
|
-
opts
|
|
19352
|
-
);
|
|
19353
|
-
const sig = await this.sendMatchTx(ixs, lookupTable, operatorWallet);
|
|
19354
|
-
return { signature: sig };
|
|
19355
|
-
}
|
|
19356
|
-
/**
|
|
19357
|
-
* 1 SELL taker vs N BUY makers.
|
|
19358
|
-
* Program now supports SELL-as-taker natively → 1 instruction with all BUY makers
|
|
19359
|
-
* in remaining_accounts (same structure as BUY taker case).
|
|
19360
|
-
*/
|
|
19361
|
-
async matchComplementarySellVsMultiBuy(sellTaker, buyMakers, collateralMint, feeRecipient, operatorWallet, lookupTable, opts) {
|
|
19362
|
-
if (buyMakers.length === 0) {
|
|
19363
|
-
throw new InvalidParamError("COMPLEMENTARY: no BUY maker orders provided");
|
|
19364
|
-
}
|
|
19365
|
-
const sell = sellTaker.order;
|
|
19366
|
-
const totalBuyPayment = buyMakers.reduce(
|
|
19367
|
-
(acc, b) => acc + BigInt(b.order.makerAmount.toString()),
|
|
19368
|
-
BigInt(0)
|
|
19369
|
-
);
|
|
19370
|
-
const sellExpected = BigInt(sell.takerAmount.toString());
|
|
19371
|
-
if (totalBuyPayment < sellExpected) {
|
|
19372
|
-
throw new InvalidParamError(
|
|
19373
|
-
`COMPLEMENTARY: total buyer payments ${totalBuyPayment} < seller expected ${sellExpected}`
|
|
19374
|
-
);
|
|
19375
|
-
}
|
|
19376
|
-
await Promise.all([
|
|
19377
|
-
this.registerOrderIfNeeded(sellTaker),
|
|
19378
|
-
...buyMakers.map((m) => this.registerOrderIfNeeded(m))
|
|
19379
|
-
]);
|
|
19380
|
-
const ixs = await this.buildMatchComplementaryIxs(
|
|
19381
|
-
sellTaker,
|
|
19382
|
-
buyMakers,
|
|
19383
|
-
collateralMint,
|
|
19384
|
-
feeRecipient,
|
|
19385
|
-
operatorWallet.publicKey,
|
|
19386
|
-
opts,
|
|
19387
|
-
false
|
|
19388
|
-
);
|
|
19389
|
-
const sig = await this.sendMatchTx(ixs, lookupTable, operatorWallet);
|
|
19390
|
-
return { signature: sig };
|
|
19391
|
-
}
|
|
19392
|
-
/**
|
|
19393
|
-
* MINT: 1 YES buyer (taker) + N NO buyers (makers).
|
|
19394
|
-
* Phase 1: register taker + all NO makers in parallel.
|
|
19395
|
-
* Phase 2: 1 atomic match tx.
|
|
19396
|
-
*
|
|
19397
|
-
* remaining_accounts per NO maker (5):
|
|
19398
|
-
* [order_record, buyer_no_token, buyer_no_collateral, buyer_no_position, no_order_status]
|
|
19399
|
-
*/
|
|
19400
|
-
/** Build the match_mint_orders instruction (no signing, no sending). */
|
|
19401
|
-
async _buildMintIx(yesSigned, noMakers, collateralMint, operator, payer) {
|
|
19402
|
-
const condition = yesSigned.order.condition;
|
|
19403
|
-
const taker = yesSigned.order.maker;
|
|
19404
|
-
const takerNonce = yesSigned.order.nonce;
|
|
19405
|
-
const fillAmount = new anchor6.BN("18446744073709551615");
|
|
19406
|
-
const clobConfig = this.configPda();
|
|
19407
|
-
const [yesMint] = PDA.yesMint(condition, this.programIds);
|
|
19408
|
-
const [noMint] = PDA.noMint(condition, this.programIds);
|
|
19409
|
-
const [mintAuthority] = PDA.mintAuthority(condition, this.programIds);
|
|
19410
|
-
const [collateralVault] = PDA.collateralVault(collateralMint, this.programIds);
|
|
19411
|
-
const [vaultTokenAccount] = PDA.vaultToken(collateralMint, this.programIds);
|
|
19412
|
-
const [takerOrderRecord] = PDA.orderRecord(taker, takerNonce, this.programIds);
|
|
19413
|
-
const takerCollateral = getAssociatedTokenAddressSync(collateralMint, taker);
|
|
19414
|
-
const takerYesToken = getAssociatedTokenAddressSync(yesMint, taker, false, TOKEN_2022_PROGRAM_ID);
|
|
19415
|
-
const [takerYesPosition] = PDA.position(condition, 1, taker, this.programIds);
|
|
19416
|
-
const [takerOrderStatus] = PDA.orderStatus(taker, takerNonce, this.programIds);
|
|
19417
|
-
const clobUsdcAta = getAssociatedTokenAddressSync(collateralMint, clobConfig, true);
|
|
19418
|
-
const clobYesAta = getAssociatedTokenAddressSync(yesMint, clobConfig, true, TOKEN_2022_PROGRAM_ID);
|
|
19419
|
-
const clobNoAta = getAssociatedTokenAddressSync(noMint, clobConfig, true, TOKEN_2022_PROGRAM_ID);
|
|
19420
|
-
const [clobYesPos] = PDA.position(condition, 1, clobConfig, this.programIds);
|
|
19421
|
-
const [clobNoPos] = PDA.position(condition, 0, clobConfig, this.programIds);
|
|
19422
|
-
const [extraMetaYes] = PDA.extraAccountMetaList(yesMint, this.programIds);
|
|
19423
|
-
const [extraMetaNo] = PDA.extraAccountMetaList(noMint, this.programIds);
|
|
19424
|
-
const [hookConfig] = PDA.hookConfig(this.programIds);
|
|
19425
|
-
const hookProgram = this.programIds.hook;
|
|
19426
|
-
const remainingAccounts = [];
|
|
19427
|
-
for (const nm of noMakers) {
|
|
19428
|
-
const noMaker = nm.order.maker;
|
|
19429
|
-
const [noRecord] = PDA.orderRecord(noMaker, nm.order.nonce, this.programIds);
|
|
19430
|
-
const noToken = getAssociatedTokenAddressSync(noMint, noMaker, false, TOKEN_2022_PROGRAM_ID);
|
|
19431
|
-
const noCollateral = getAssociatedTokenAddressSync(collateralMint, noMaker);
|
|
19432
|
-
const [noPosition] = PDA.position(condition, 0, noMaker, this.programIds);
|
|
19433
|
-
const [noStatus] = PDA.orderStatus(noMaker, nm.order.nonce, this.programIds);
|
|
19434
|
-
remainingAccounts.push(
|
|
19435
|
-
{ pubkey: noMaker, isSigner: false, isWritable: false },
|
|
19436
|
-
{ pubkey: noRecord, isSigner: false, isWritable: false },
|
|
19437
|
-
{ pubkey: noToken, isSigner: false, isWritable: true },
|
|
19438
|
-
{ pubkey: noCollateral, isSigner: false, isWritable: true },
|
|
19439
|
-
{ pubkey: noPosition, isSigner: false, isWritable: true },
|
|
19440
|
-
{ pubkey: noStatus, isSigner: false, isWritable: true }
|
|
19441
|
-
);
|
|
19442
|
-
}
|
|
19443
|
-
remainingAccounts.push(
|
|
19444
|
-
{ pubkey: extraMetaYes, isSigner: false, isWritable: false },
|
|
19445
|
-
{ pubkey: extraMetaNo, isSigner: false, isWritable: false },
|
|
19446
|
-
{ pubkey: hookConfig, isSigner: false, isWritable: false },
|
|
19447
|
-
{ pubkey: hookProgram, isSigner: false, isWritable: false }
|
|
19448
|
-
);
|
|
19449
|
-
return this.program.methods.matchMintOrders(takerNonce, fillAmount, true).accounts({
|
|
19450
|
-
operator,
|
|
19451
|
-
payer,
|
|
19452
|
-
clobConfig,
|
|
19453
|
-
condition,
|
|
19454
|
-
taker,
|
|
19455
|
-
takerOrderRecord,
|
|
19456
|
-
takerCollateral,
|
|
19457
|
-
takerYesToken,
|
|
19458
|
-
takerYesPosition,
|
|
19459
|
-
takerOrderStatus,
|
|
19460
|
-
clobUsdcAta,
|
|
19461
|
-
clobYesAta,
|
|
19462
|
-
clobNoAta,
|
|
19463
|
-
clobYesPosition: clobYesPos,
|
|
19464
|
-
clobNoPosition: clobNoPos,
|
|
19465
|
-
collateralVault,
|
|
19466
|
-
vaultTokenAccount,
|
|
19467
|
-
collateralMint,
|
|
19468
|
-
yesMint,
|
|
19469
|
-
noMint,
|
|
19470
|
-
mintAuthority,
|
|
19471
|
-
clobAuthority: clobConfig,
|
|
19472
|
-
conditionalTokensProgram: this.programIds.conditionalTokens,
|
|
19473
|
-
collateralTokenProgram: TOKEN_PROGRAM_ID,
|
|
19474
|
-
token2022Program: TOKEN_2022_PROGRAM_ID,
|
|
19475
|
-
associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID,
|
|
19476
|
-
systemProgram: SystemProgram.programId
|
|
19477
|
-
}).remainingAccounts(remainingAccounts).instruction();
|
|
19478
|
-
}
|
|
19479
|
-
async matchMintOrders(yesSigned, noMakers, collateralMint, _feeRecipient, operatorWallet, lookupTable) {
|
|
19480
|
-
await Promise.all([
|
|
19481
|
-
this.registerOrderIfNeeded(yesSigned),
|
|
19482
|
-
...noMakers.map((m) => this.registerOrderIfNeeded(m))
|
|
19483
|
-
]);
|
|
19484
|
-
const condition = yesSigned.order.condition;
|
|
19485
|
-
const clobConfig = this.configPda();
|
|
19486
|
-
const [yesMint] = PDA.yesMint(condition, this.programIds);
|
|
19487
|
-
const [noMint] = PDA.noMint(condition, this.programIds);
|
|
19488
|
-
const clobYesAta = getAssociatedTokenAddressSync(yesMint, clobConfig, true, TOKEN_2022_PROGRAM_ID);
|
|
19489
|
-
const clobNoAta = getAssociatedTokenAddressSync(noMint, clobConfig, true, TOKEN_2022_PROGRAM_ID);
|
|
19490
|
-
const matchIx = await this._buildMintIx(yesSigned, noMakers, collateralMint, operatorWallet.publicKey, this.walletPubkey);
|
|
19491
|
-
await this._ensureClobOutcomeAtas(yesMint, noMint, clobConfig, clobYesAta, clobNoAta);
|
|
19492
|
-
const sig = await this.sendMatchTx([matchIx], lookupTable, operatorWallet);
|
|
19493
|
-
return { signature: sig };
|
|
19494
|
-
}
|
|
19495
|
-
/**
|
|
19496
|
-
* MERGE: 1 YES seller (taker) + N NO sellers (makers).
|
|
19497
|
-
* Phase 1: register taker + all NO makers in parallel.
|
|
19498
|
-
* Phase 2: 1 atomic match tx.
|
|
19499
|
-
*
|
|
19500
|
-
* remaining_accounts per NO maker (5):
|
|
19501
|
-
* [order_record, seller_no_token, seller_no_collateral, seller_no_position, no_order_status]
|
|
19502
|
-
* After all makers, optional 5 fee accounts.
|
|
19503
|
-
*/
|
|
19504
|
-
/** Build the match_merge_orders instruction (no signing, no sending). */
|
|
19505
|
-
async _buildMergeIx(yesSigned, noMakers, collateralMint, operator, payer, opts) {
|
|
19506
|
-
const condition = yesSigned.order.condition;
|
|
19507
|
-
const sellerYes = yesSigned.order.maker;
|
|
19508
|
-
const takerNonce = yesSigned.order.nonce;
|
|
19509
|
-
const fillAmount = new anchor6.BN("18446744073709551615");
|
|
19510
|
-
const clobConfig = this.configPda();
|
|
19511
|
-
const [yesMint] = PDA.yesMint(condition, this.programIds);
|
|
19512
|
-
const [noMint] = PDA.noMint(condition, this.programIds);
|
|
19513
|
-
const [collateralVault] = PDA.collateralVault(collateralMint, this.programIds);
|
|
19514
|
-
const [vaultTokenAccount] = PDA.vaultToken(collateralMint, this.programIds);
|
|
19515
|
-
const [takerOrderRecord] = PDA.orderRecord(sellerYes, takerNonce, this.programIds);
|
|
19516
|
-
const takerYesToken = getAssociatedTokenAddressSync(yesMint, sellerYes, false, TOKEN_2022_PROGRAM_ID);
|
|
19517
|
-
const [takerYesPosition] = PDA.position(condition, 1, sellerYes, this.programIds);
|
|
19518
|
-
const takerCollateral = getAssociatedTokenAddressSync(collateralMint, sellerYes);
|
|
19519
|
-
const [takerOrderStatus] = PDA.orderStatus(sellerYes, takerNonce, this.programIds);
|
|
19520
|
-
const clobUsdcAta = getAssociatedTokenAddressSync(collateralMint, clobConfig, true);
|
|
19521
|
-
const clobYesAta = getAssociatedTokenAddressSync(yesMint, clobConfig, true, TOKEN_2022_PROGRAM_ID);
|
|
19522
|
-
const clobNoAta = getAssociatedTokenAddressSync(noMint, clobConfig, true, TOKEN_2022_PROGRAM_ID);
|
|
19523
|
-
const [clobYesPos] = PDA.position(condition, 1, clobConfig, this.programIds);
|
|
19524
|
-
const [clobNoPos] = PDA.position(condition, 0, clobConfig, this.programIds);
|
|
19525
|
-
const [extraMetaYes] = PDA.extraAccountMetaList(yesMint, this.programIds);
|
|
19526
|
-
const [extraMetaNo] = PDA.extraAccountMetaList(noMint, this.programIds);
|
|
19527
|
-
const [hookConfig] = PDA.hookConfig(this.programIds);
|
|
19528
|
-
const hookProgram = this.programIds.hook;
|
|
19529
|
-
const remainingAccounts = [];
|
|
19530
|
-
for (const nm of noMakers) {
|
|
19531
|
-
const noMaker = nm.order.maker;
|
|
19532
|
-
const [noRecord] = PDA.orderRecord(noMaker, nm.order.nonce, this.programIds);
|
|
19533
|
-
const noToken = getAssociatedTokenAddressSync(noMint, noMaker, false, TOKEN_2022_PROGRAM_ID);
|
|
19534
|
-
const noCollateral = getAssociatedTokenAddressSync(collateralMint, noMaker);
|
|
19535
|
-
const [noPosition] = PDA.position(condition, 0, noMaker, this.programIds);
|
|
19536
|
-
const [noStatus] = PDA.orderStatus(noMaker, nm.order.nonce, this.programIds);
|
|
19537
|
-
remainingAccounts.push(
|
|
19538
|
-
{ pubkey: noMaker, isSigner: false, isWritable: false },
|
|
19539
|
-
{ pubkey: noRecord, isSigner: false, isWritable: false },
|
|
19540
|
-
{ pubkey: noToken, isSigner: false, isWritable: true },
|
|
19541
|
-
{ pubkey: noCollateral, isSigner: false, isWritable: true },
|
|
19542
|
-
{ pubkey: noPosition, isSigner: false, isWritable: true },
|
|
19543
|
-
{ pubkey: noStatus, isSigner: false, isWritable: true }
|
|
19544
|
-
);
|
|
19545
|
-
}
|
|
19546
|
-
remainingAccounts.push(
|
|
19547
|
-
{ pubkey: extraMetaYes, isSigner: false, isWritable: false },
|
|
19548
|
-
{ pubkey: extraMetaNo, isSigner: false, isWritable: false },
|
|
19549
|
-
{ pubkey: hookConfig, isSigner: false, isWritable: false },
|
|
19550
|
-
{ pubkey: hookProgram, isSigner: false, isWritable: false }
|
|
19551
|
-
);
|
|
19552
|
-
if (yesSigned.order.fee.gtn(0) && this.programIds.feeManagement && this.feeConfigOwner) {
|
|
19553
|
-
const companyAddr = await this.companyAddress();
|
|
19554
|
-
const refVault = await this.referralVault();
|
|
19555
|
-
if (companyAddr && refVault) {
|
|
19556
|
-
const feeOverridePda = PDA.marketFeeOverride(condition, this.programIds)[0];
|
|
19557
|
-
const feeOverrideExists = await this.provider.connection.getAccountInfo(feeOverridePda);
|
|
19558
|
-
if (feeOverrideExists) {
|
|
19559
|
-
const oracleVault = opts?.marketOracleVault ?? await this.getMarketOracleVault(condition, collateralMint) ?? payer;
|
|
19560
|
-
remainingAccounts.push(
|
|
19561
|
-
{ pubkey: this.programIds.feeManagement, isSigner: false, isWritable: false },
|
|
19562
|
-
{ pubkey: PDA.feeConfig(this.feeConfigOwner, this.programIds)[0], isSigner: false, isWritable: false },
|
|
19563
|
-
{ pubkey: feeOverridePda, isSigner: false, isWritable: false },
|
|
19564
|
-
{ pubkey: getAssociatedTokenAddressSync(collateralMint, companyAddr), isSigner: false, isWritable: true },
|
|
19565
|
-
{ pubkey: oracleVault, isSigner: false, isWritable: true },
|
|
19566
|
-
{ pubkey: refVault, isSigner: false, isWritable: true }
|
|
19567
|
-
);
|
|
19568
|
-
}
|
|
19569
|
-
}
|
|
19570
|
-
}
|
|
19571
|
-
return this.program.methods.matchMergeOrders(takerNonce, fillAmount, true).accounts({
|
|
19572
|
-
operator,
|
|
19573
|
-
payer,
|
|
19574
|
-
clobConfig,
|
|
19575
|
-
condition,
|
|
19576
|
-
taker: sellerYes,
|
|
19577
|
-
takerOrderRecord,
|
|
19578
|
-
takerYesToken,
|
|
19579
|
-
takerYesPosition,
|
|
19580
|
-
takerCollateral,
|
|
19581
|
-
takerOrderStatus,
|
|
19582
|
-
clobUsdcAta,
|
|
19583
|
-
clobYesAta,
|
|
19584
|
-
clobNoAta,
|
|
19585
|
-
clobYesPosition: clobYesPos,
|
|
19586
|
-
clobNoPosition: clobNoPos,
|
|
19587
|
-
collateralVault,
|
|
19588
|
-
vaultTokenAccount,
|
|
19589
|
-
collateralMint,
|
|
19590
|
-
yesMint,
|
|
19591
|
-
noMint,
|
|
19592
|
-
clobAuthority: clobConfig,
|
|
19593
|
-
conditionalTokensProgram: this.programIds.conditionalTokens,
|
|
19594
|
-
collateralTokenProgram: TOKEN_PROGRAM_ID,
|
|
19595
|
-
token2022Program: TOKEN_2022_PROGRAM_ID,
|
|
19596
|
-
associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID,
|
|
19597
|
-
systemProgram: SystemProgram.programId
|
|
19598
|
-
}).remainingAccounts(remainingAccounts).instruction();
|
|
19599
|
-
}
|
|
19600
|
-
async matchMergeOrders(yesSigned, noMakers, collateralMint, _feeRecipient, operatorWallet, lookupTable, opts) {
|
|
19601
|
-
await Promise.all([
|
|
19602
|
-
this.registerOrderIfNeeded(yesSigned),
|
|
19603
|
-
...noMakers.map((m) => this.registerOrderIfNeeded(m))
|
|
19604
|
-
]);
|
|
19605
|
-
const condition = yesSigned.order.condition;
|
|
19606
|
-
const clobConfig = this.configPda();
|
|
19607
|
-
const [yesMint] = PDA.yesMint(condition, this.programIds);
|
|
19608
|
-
const [noMint] = PDA.noMint(condition, this.programIds);
|
|
19609
|
-
const clobYesAta = getAssociatedTokenAddressSync(yesMint, clobConfig, true, TOKEN_2022_PROGRAM_ID);
|
|
19610
|
-
const clobNoAta = getAssociatedTokenAddressSync(noMint, clobConfig, true, TOKEN_2022_PROGRAM_ID);
|
|
19611
|
-
const matchIx = await this._buildMergeIx(yesSigned, noMakers, collateralMint, operatorWallet.publicKey, this.walletPubkey, opts);
|
|
19612
|
-
await this._ensureClobOutcomeAtas(yesMint, noMint, clobConfig, clobYesAta, clobNoAta);
|
|
19613
|
-
const sig = await this.sendMatchTx([matchIx], lookupTable, operatorWallet);
|
|
19614
|
-
return { signature: sig };
|
|
19615
|
-
}
|
|
19616
|
-
/**
|
|
19617
|
-
* Auto-detect match type and execute 2-phase:
|
|
19618
|
-
* Phase 1 — register all orders (taker + makers) on-chain in parallel.
|
|
19619
|
-
* Phase 2 — 1 atomic match transaction.
|
|
19620
|
-
*
|
|
19621
|
-
* Detection (pure, no RPC):
|
|
19622
|
-
* taker.tokenId === makers[0].tokenId:
|
|
19623
|
-
* taker BUY + all makers SELL → COMPLEMENTARY
|
|
19624
|
-
* taker.tokenId !== makers[0].tokenId + all BUY → MINT
|
|
19625
|
-
* taker.tokenId !== makers[0].tokenId + all SELL → MERGE
|
|
19626
|
-
*
|
|
19627
|
-
* @param opts.marketOracleVault Oracle vault ATA for presale markets.
|
|
19628
|
-
* Omit for admin markets (payer used as placeholder).
|
|
19629
|
-
*/
|
|
19630
|
-
async matchOrders(taker, makers, opts) {
|
|
19631
|
-
if (makers.length === 0) throw new InvalidParamError("At least 1 maker required");
|
|
19632
|
-
const collateralMint = this.networkConfig.defaultCollateral.mint;
|
|
19633
|
-
const cfg = await this.fetchConfig();
|
|
19634
|
-
if (!cfg) throw new InvalidParamError("CLOB config not found on-chain");
|
|
19635
|
-
const feeRecipient = cfg.feeRecipient;
|
|
19636
|
-
const operatorWallet = opts?.operatorWallet ?? this.provider.wallet;
|
|
19637
|
-
const alt = await this.ensureAlt(
|
|
19638
|
-
taker.order.condition,
|
|
19639
|
-
collateralMint,
|
|
19640
|
-
taker,
|
|
19641
|
-
makers
|
|
19642
|
-
);
|
|
19643
|
-
const t = taker.order;
|
|
19644
|
-
const m0 = makers[0].order;
|
|
19645
|
-
const SIDE_BUY = 0;
|
|
19646
|
-
const SIDE_SELL = 1;
|
|
19647
|
-
if (t.tokenId === m0.tokenId) {
|
|
19648
|
-
let buySignedOrder, sellCandidates;
|
|
19649
|
-
if (t.side === SIDE_BUY && makers.every((m) => m.order.side === SIDE_SELL)) {
|
|
19650
|
-
buySignedOrder = taker;
|
|
19651
|
-
sellCandidates = makers;
|
|
19652
|
-
} else if (t.side === SIDE_SELL && makers.every((m) => m.order.side === SIDE_BUY)) {
|
|
19653
|
-
return this.matchComplementarySellVsMultiBuy(taker, makers, collateralMint, feeRecipient, operatorWallet, alt, opts);
|
|
19654
|
-
} else {
|
|
19655
|
-
throw new InvalidParamError("COMPLEMENTARY requires one BUY and one or more SELLs on same tokenId");
|
|
19656
|
-
}
|
|
19657
|
-
const finalSells = sellCandidates;
|
|
19658
|
-
return this.matchComplementary(buySignedOrder, finalSells, collateralMint, feeRecipient, operatorWallet, alt, opts);
|
|
19659
|
-
}
|
|
19660
|
-
const allBuy = t.side === SIDE_BUY && makers.every((m) => m.order.side === SIDE_BUY);
|
|
19661
|
-
const allSell = t.side === SIDE_SELL && makers.every((m) => m.order.side === SIDE_SELL);
|
|
19662
|
-
if (!allBuy && !allSell) throw new InvalidParamError("MINT/MERGE: all orders must be same side");
|
|
19663
|
-
const takerIsYes = t.tokenId === 1 && makers.every((m) => m.order.tokenId === 0);
|
|
19664
|
-
const takerIsNo = t.tokenId === 0 && makers.every((m) => m.order.tokenId === 1);
|
|
19665
|
-
if (!takerIsYes && !takerIsNo) throw new InvalidParamError("MINT/MERGE: orders must be complementary YES+NO pair");
|
|
19666
|
-
if (takerIsYes) {
|
|
19667
|
-
if (allBuy) return this.matchMintOrders(taker, makers, collateralMint, feeRecipient, operatorWallet, alt);
|
|
19668
|
-
return this.matchMergeOrders(taker, makers, collateralMint, feeRecipient, operatorWallet, alt, opts);
|
|
19669
|
-
}
|
|
19670
|
-
let lastResult;
|
|
19671
|
-
for (const yesMaker of makers) {
|
|
19672
|
-
if (allBuy) lastResult = await this.matchMintOrders(yesMaker, [taker], collateralMint, feeRecipient, operatorWallet, alt);
|
|
19673
|
-
else lastResult = await this.matchMergeOrders(yesMaker, [taker], collateralMint, feeRecipient, operatorWallet, alt, opts);
|
|
19674
|
-
}
|
|
19675
|
-
return lastResult;
|
|
19676
|
-
}
|
|
19677
|
-
/**
|
|
19678
|
-
* High-level match: caller passes price + quantity + keypair — SDK builds,
|
|
19679
|
-
* signs, and submits in one call. No manual amount calculation needed.
|
|
19680
|
-
*
|
|
19681
|
-
* Amounts are computed from each order's own limit `price` (percentage, e.g. 51 for 51%).
|
|
19682
|
-
* NEVER pass averageMatchedPrice — that is an engine output, not an order input.
|
|
19683
|
-
*
|
|
19684
|
-
* @param taker { keypair, condition, tokenId, side, price, quantity, nonce?, expiry? }
|
|
19685
|
-
* @param makers Array of same shape
|
|
19686
|
-
* @param decimals Collateral decimals (default 9 for USDS)
|
|
19687
|
-
*/
|
|
19688
|
-
async matchOrdersFromPrice(taker, makers, decimals = 9, opts) {
|
|
19689
|
-
const nacl2 = await import('tweetnacl');
|
|
19690
|
-
const buildSigned = (p) => {
|
|
19691
|
-
const order = buildOrderFromPrice({
|
|
19692
|
-
maker: p.keypair.publicKey,
|
|
19693
|
-
condition: p.condition,
|
|
19694
|
-
tokenId: p.tokenId,
|
|
19695
|
-
side: p.side,
|
|
19696
|
-
price: p.price,
|
|
19697
|
-
quantity: p.quantity,
|
|
19698
|
-
decimals,
|
|
19699
|
-
nonce: p.nonce,
|
|
19700
|
-
expiry: p.expiry,
|
|
19701
|
-
fee: p.fee,
|
|
19702
|
-
taker: p.taker
|
|
19703
|
-
});
|
|
19704
|
-
const msg = serializeOrderToBytes(order);
|
|
19705
|
-
const sig = nacl2.default.sign.detached(msg, p.keypair.secretKey);
|
|
19706
|
-
return { order, signature: sig };
|
|
19707
|
-
};
|
|
19708
|
-
const takerSigned = buildSigned(taker);
|
|
19709
|
-
const sortedMakers = [...makers].sort((a, b) => {
|
|
19710
|
-
const sameToken = a.tokenId === taker.tokenId && b.tokenId === taker.tokenId;
|
|
19711
|
-
const isDirectBuy = taker.side === 0 && sameToken;
|
|
19712
|
-
const isDirectSell = taker.side === 1 && sameToken;
|
|
19713
|
-
const isMint = taker.side === 0 && taker.tokenId === 1;
|
|
19714
|
-
const isMerge = taker.side === 1 && taker.tokenId === 1;
|
|
19715
|
-
if (isDirectBuy) return a.price - b.price;
|
|
19716
|
-
if (isDirectSell) return b.price - a.price;
|
|
19717
|
-
if (isMint) return b.price - a.price;
|
|
19718
|
-
if (isMerge) return a.price - b.price;
|
|
19719
|
-
return 0;
|
|
19720
|
-
});
|
|
19721
|
-
const makersSigned = sortedMakers.map(buildSigned);
|
|
19722
|
-
return this.matchOrders(takerSigned, makersSigned, opts);
|
|
19723
|
-
}
|
|
19724
|
-
/**
|
|
19725
|
-
* Build an unsigned VersionedTransaction for a set of match instructions.
|
|
19726
|
-
* Callers sign and send externally — mirrors createQuestionAdmin pattern.
|
|
19727
|
-
*/
|
|
19728
|
-
async _buildUnsignedVtx(instructions, lookupTable, payer) {
|
|
19729
|
-
const { connection } = this.provider;
|
|
19730
|
-
const { blockhash } = await connection.getLatestBlockhash();
|
|
19731
|
-
const cuLimit = ComputeBudgetProgram.setComputeUnitLimit({ units: 14e5 });
|
|
19732
|
-
const heapFrame = ComputeBudgetProgram.requestHeapFrame({ bytes: 262144 });
|
|
19733
|
-
const message = new TransactionMessage({
|
|
19734
|
-
payerKey: payer,
|
|
19735
|
-
recentBlockhash: blockhash,
|
|
19736
|
-
instructions: [cuLimit, heapFrame, ...instructions]
|
|
19737
|
-
}).compileToV0Message(lookupTable ? [lookupTable] : []);
|
|
19738
|
-
return new VersionedTransaction(message);
|
|
19739
|
-
}
|
|
19740
|
-
/**
|
|
19741
|
-
* Build unsigned VersionedTransaction(s) for matching orders.
|
|
19742
|
-
*
|
|
19743
|
-
* Mirrors createQuestionAdmin pattern — SDK registers orders internally but
|
|
19744
|
-
* returns the match tx unsigned. BE signs with both keypairs and sends:
|
|
19745
|
-
*
|
|
19746
|
-
* const [vtx] = await sdk.clob.buildMatchOrdersTx(taker, makers, operatorPk, payerPk);
|
|
19747
|
-
* vtx.sign([feePayerKeypair, operatorKeypair]);
|
|
19748
|
-
* await connection.sendRawTransaction(vtx.serialize());
|
|
19749
|
-
*
|
|
19750
|
-
* All match types pack into a single VersionedTransaction — same as createQuestionAdmin pattern.
|
|
19751
|
-
* NO-taker MINT/MERGE decomposes into N instructions but all packed in 1 tx.
|
|
19752
|
-
*
|
|
19753
|
-
* @param operator - Whitelisted CLOB operator pubkey (must sign)
|
|
19754
|
-
* @param payer - Fee payer pubkey (must sign, pays tx fee + rent)
|
|
19755
|
-
*/
|
|
19756
|
-
async buildMatchOrdersTx(taker, makers, operator, payer, opts) {
|
|
19757
|
-
if (makers.length === 0) throw new InvalidParamError("At least 1 maker required");
|
|
19758
|
-
const collateralMint = this.networkConfig.defaultCollateral.mint;
|
|
19759
|
-
const cfg = await this.fetchConfig();
|
|
19760
|
-
if (!cfg) throw new InvalidParamError("CLOB config not found on-chain");
|
|
19761
|
-
const feeRecipient = cfg.feeRecipient;
|
|
19762
|
-
const alt = await this.ensureAlt(taker.order.condition, collateralMint, taker, makers);
|
|
19763
|
-
const t = taker.order;
|
|
19764
|
-
const m0 = makers[0].order;
|
|
19765
|
-
const SIDE_BUY = 0;
|
|
19766
|
-
const SIDE_SELL = 1;
|
|
19767
|
-
const hookInitIxs = [];
|
|
19768
|
-
if (this.hookClient) {
|
|
19769
|
-
const condition0 = t.condition;
|
|
19770
|
-
const [ym] = PDA.yesMint(condition0, this.programIds);
|
|
19771
|
-
const [nm] = PDA.noMint(condition0, this.programIds);
|
|
19772
|
-
const [yIx, nIx] = await Promise.all([
|
|
19773
|
-
this.hookClient.buildInitHookIxIfNeeded(ym, payer),
|
|
19774
|
-
this.hookClient.buildInitHookIxIfNeeded(nm, payer)
|
|
19775
|
-
]);
|
|
19776
|
-
if (yIx) hookInitIxs.push(yIx);
|
|
19777
|
-
if (nIx) hookInitIxs.push(nIx);
|
|
19778
|
-
}
|
|
19779
|
-
const oracleVaultInitIx = await this.buildInitOracleVaultIfNeeded(
|
|
19780
|
-
t.condition,
|
|
19781
|
-
collateralMint,
|
|
19782
|
-
t.fee,
|
|
19783
|
-
payer
|
|
19784
|
-
);
|
|
19785
|
-
const preIxs = oracleVaultInitIx ? [...hookInitIxs, oracleVaultInitIx] : hookInitIxs;
|
|
19786
|
-
if (t.tokenId === m0.tokenId) {
|
|
19787
|
-
let buySignedOrder, sellCandidates;
|
|
19788
|
-
if (t.side === SIDE_BUY && makers.every((m) => m.order.side === SIDE_SELL)) {
|
|
19789
|
-
buySignedOrder = taker;
|
|
19790
|
-
sellCandidates = makers;
|
|
19791
|
-
} else if (t.side === SIDE_SELL && makers.every((m) => m.order.side === SIDE_BUY)) {
|
|
19792
|
-
await Promise.all([
|
|
19793
|
-
this.registerOrderIfNeeded(taker),
|
|
19794
|
-
...makers.map((m) => this.registerOrderIfNeeded(m))
|
|
19795
|
-
]);
|
|
19796
|
-
const ixs3 = await this.buildMatchComplementaryIxs(
|
|
19797
|
-
taker,
|
|
19798
|
-
makers,
|
|
19799
|
-
collateralMint,
|
|
19800
|
-
feeRecipient,
|
|
19801
|
-
operator,
|
|
19802
|
-
opts,
|
|
19803
|
-
false
|
|
19804
|
-
);
|
|
19805
|
-
return this._buildUnsignedVtx([...preIxs, ...ixs3], alt, payer);
|
|
19806
|
-
} else {
|
|
19807
|
-
throw new InvalidParamError("COMPLEMENTARY requires one BUY and one or more SELLs on same tokenId");
|
|
19808
|
-
}
|
|
19809
|
-
await Promise.all([
|
|
19810
|
-
this.registerOrderIfNeeded(buySignedOrder),
|
|
19811
|
-
...sellCandidates.map((m) => this.registerOrderIfNeeded(m))
|
|
19812
|
-
]);
|
|
19813
|
-
const ixs2 = await this.buildMatchComplementaryIxs(
|
|
19814
|
-
buySignedOrder,
|
|
19815
|
-
sellCandidates,
|
|
19816
|
-
collateralMint,
|
|
19817
|
-
feeRecipient,
|
|
19818
|
-
operator,
|
|
19819
|
-
opts
|
|
19820
|
-
);
|
|
19821
|
-
return this._buildUnsignedVtx([...preIxs, ...ixs2], alt, payer);
|
|
19822
|
-
}
|
|
19823
|
-
const allBuy = t.side === SIDE_BUY && makers.every((m) => m.order.side === SIDE_BUY);
|
|
19824
|
-
const allSell = t.side === SIDE_SELL && makers.every((m) => m.order.side === SIDE_SELL);
|
|
19825
|
-
if (!allBuy && !allSell) throw new InvalidParamError("MINT/MERGE: all orders must be same side");
|
|
19826
|
-
const takerIsYes = t.tokenId === 1 && makers.every((m) => m.order.tokenId === 0);
|
|
19827
|
-
const takerIsNo = t.tokenId === 0 && makers.every((m) => m.order.tokenId === 1);
|
|
19828
|
-
if (!takerIsYes && !takerIsNo) throw new InvalidParamError("MINT/MERGE: orders must be complementary YES+NO pair");
|
|
19829
|
-
const condition = t.condition;
|
|
19830
|
-
const clobConfig = this.configPda();
|
|
19831
|
-
const [yesMint] = PDA.yesMint(condition, this.programIds);
|
|
19832
|
-
const [noMint] = PDA.noMint(condition, this.programIds);
|
|
19833
|
-
const clobYesAta = getAssociatedTokenAddressSync(yesMint, clobConfig, true, TOKEN_2022_PROGRAM_ID);
|
|
19834
|
-
const clobNoAta = getAssociatedTokenAddressSync(noMint, clobConfig, true, TOKEN_2022_PROGRAM_ID);
|
|
19835
|
-
if (takerIsYes) {
|
|
19836
|
-
await Promise.all([
|
|
19837
|
-
this.registerOrderIfNeeded(taker),
|
|
19838
|
-
...makers.map((m) => this.registerOrderIfNeeded(m))
|
|
19839
|
-
]);
|
|
19840
|
-
await this._ensureClobOutcomeAtas(yesMint, noMint, clobConfig, clobYesAta, clobNoAta);
|
|
19841
|
-
const ix = allBuy ? await this._buildMintIx(taker, makers, collateralMint, operator, payer) : await this._buildMergeIx(taker, makers, collateralMint, operator, payer, opts);
|
|
19842
|
-
return this._buildUnsignedVtx([...preIxs, ix], alt, payer);
|
|
19843
|
-
}
|
|
19844
|
-
await Promise.all([
|
|
19845
|
-
this.registerOrderIfNeeded(taker),
|
|
19846
|
-
...makers.map((m) => this.registerOrderIfNeeded(m))
|
|
19847
|
-
]);
|
|
19848
|
-
await this._ensureClobOutcomeAtas(yesMint, noMint, clobConfig, clobYesAta, clobNoAta);
|
|
19849
|
-
const ixs = [];
|
|
19850
|
-
for (const yesMaker of makers) {
|
|
19851
|
-
const ix = allBuy ? await this._buildMintIx(yesMaker, [taker], collateralMint, operator, payer) : await this._buildMergeIx(yesMaker, [taker], collateralMint, operator, payer, opts);
|
|
19852
|
-
ixs.push(ix);
|
|
19853
|
-
}
|
|
19854
|
-
return this._buildUnsignedVtx([...preIxs, ...ixs], alt, payer);
|
|
19855
|
-
}
|
|
19856
|
-
// ─── batchCollectRedeemEarly ─────────────────────────────────────────────────
|
|
19857
|
-
/**
|
|
19858
|
-
* Build VersionedTransaction for batchCollectRedeemEarly.
|
|
19859
|
-
*
|
|
19860
|
-
* Prerequisite: each user's CollectFeeOrder must be registered on-chain via
|
|
19861
|
-
* buildRegisterCollectFeeOrderTx (one tx per user).
|
|
19862
|
-
*
|
|
19863
|
-
* Flow: batchCollectRedeemEarly ix reads CollectFeeOrderRecord PDAs — no Ed25519 inline.
|
|
19864
|
-
* No tx-size limit from signatures, supports 10+ orders in one tx.
|
|
19865
|
-
*
|
|
19866
|
-
* @param signedOrders - Array of { order, signature } (used to derive record PDAs)
|
|
19867
|
-
* @param condition - Market condition PDA
|
|
19868
|
-
* @param outcomeIndex - 0 = NO wins, 1 = YES wins
|
|
19869
|
-
* @param operator - Whitelisted operator pubkey (must sign)
|
|
19870
|
-
* @param payer - Fee payer pubkey (must sign)
|
|
19871
|
-
* @param opts.marketOracleVault - MarketOracle vault for fee distribution
|
|
19872
|
-
*/
|
|
19873
|
-
async buildBatchCollectRedeemEarlyTx(signedOrders, condition, outcomeIndex, operator, payer, opts) {
|
|
19874
|
-
if (signedOrders.length === 0) throw new InvalidParamError("At least 1 order required");
|
|
19875
|
-
const collateralMint = this.networkConfig.defaultCollateral.mint;
|
|
19876
|
-
const cfg = await this.fetchConfig();
|
|
19877
|
-
if (!cfg) throw new InvalidParamError("CLOB config not found on-chain");
|
|
19878
|
-
const clobConfig = this.configPda();
|
|
19879
|
-
const [yesMint] = PDA.yesMint(condition, this.programIds);
|
|
19880
|
-
const [noMint] = PDA.noMint(condition, this.programIds);
|
|
19881
|
-
const [collateralVault] = PDA.collateralVault(collateralMint, this.programIds);
|
|
19882
|
-
const [vaultTokenAccount] = PDA.vaultToken(collateralMint, this.programIds);
|
|
19883
|
-
const clobYesAta = getAssociatedTokenAddressSync(yesMint, clobConfig, true, TOKEN_2022_PROGRAM_ID);
|
|
19884
|
-
const clobNoAta = getAssociatedTokenAddressSync(noMint, clobConfig, true, TOKEN_2022_PROGRAM_ID);
|
|
19885
|
-
const outcomeMint = outcomeIndex === 1 ? yesMint : noMint;
|
|
19886
|
-
const [extraAccountMeta] = PDA.extraAccountMetaList(outcomeMint, this.programIds);
|
|
19887
|
-
const [hookConfig] = PDA.hookConfig(this.programIds);
|
|
19888
|
-
const [clobYesPosition] = PDA.position(condition, 1, clobConfig, this.programIds);
|
|
19889
|
-
const [clobNoPosition] = PDA.position(condition, 0, clobConfig, this.programIds);
|
|
19890
|
-
const userAccounts = [];
|
|
19891
|
-
for (const { order } of signedOrders) {
|
|
19892
|
-
const [collectFeeOrderRecord] = PDA.collectFeeOrderRecord(order.user, order.nonce, this.programIds);
|
|
19893
|
-
const userTokenAta = getAssociatedTokenAddressSync(outcomeMint, order.user, false, TOKEN_2022_PROGRAM_ID);
|
|
19894
|
-
const [userPosition] = PDA.position(condition, outcomeIndex, order.user, this.programIds);
|
|
19895
|
-
userAccounts.push(
|
|
19896
|
-
{ pubkey: collectFeeOrderRecord, isSigner: false, isWritable: true },
|
|
19897
|
-
{ pubkey: order.user, isSigner: false, isWritable: false },
|
|
19898
|
-
{ pubkey: userTokenAta, isSigner: false, isWritable: true },
|
|
19899
|
-
{ pubkey: userPosition, isSigner: false, isWritable: true }
|
|
19900
|
-
);
|
|
19901
|
-
}
|
|
19902
|
-
const hookAccounts = [
|
|
19903
|
-
{ pubkey: extraAccountMeta, isSigner: false, isWritable: false },
|
|
19904
|
-
{ pubkey: hookConfig, isSigner: false, isWritable: false },
|
|
19905
|
-
{ pubkey: this.programIds.hook, isSigner: false, isWritable: false }
|
|
19906
|
-
];
|
|
19907
|
-
let feeAccounts = [];
|
|
19908
|
-
if (this.programIds.feeManagement && this.feeConfigOwner) {
|
|
19909
|
-
const companyAddr = await this.companyAddress();
|
|
19910
|
-
const refVault = await this.referralVault();
|
|
19911
|
-
if (companyAddr && refVault) {
|
|
19912
|
-
const feeOverridePda = PDA.marketFeeOverride(condition, this.programIds)[0];
|
|
19913
|
-
const feeOverrideExists = await this.provider.connection.getAccountInfo(feeOverridePda);
|
|
19914
|
-
if (feeOverrideExists) {
|
|
19915
|
-
const oracleVault = opts?.marketOracleVault ?? await this.getMarketOracleVault(condition, collateralMint) ?? payer;
|
|
19916
|
-
feeAccounts = [
|
|
19917
|
-
{ pubkey: this.programIds.feeManagement, isSigner: false, isWritable: false },
|
|
19918
|
-
{ pubkey: PDA.feeConfig(this.feeConfigOwner, this.programIds)[0], isSigner: false, isWritable: false },
|
|
19919
|
-
{ pubkey: feeOverridePda, isSigner: false, isWritable: false },
|
|
19920
|
-
{ pubkey: getAssociatedTokenAddressSync(collateralMint, companyAddr), isSigner: false, isWritable: true },
|
|
19921
|
-
{ pubkey: oracleVault, isSigner: false, isWritable: true },
|
|
19922
|
-
{ pubkey: refVault, isSigner: false, isWritable: true }
|
|
19923
|
-
];
|
|
19924
|
-
}
|
|
19925
|
-
}
|
|
19926
|
-
}
|
|
19927
|
-
await this._ensureClobOutcomeAtas(yesMint, noMint, clobConfig, clobYesAta, clobNoAta);
|
|
19928
|
-
const hookInitIxs = [];
|
|
19929
|
-
if (this.hookClient) {
|
|
19930
|
-
const ix = await this.hookClient.buildInitHookIxIfNeeded(outcomeMint, payer);
|
|
19931
|
-
if (ix) hookInitIxs.push(ix);
|
|
19932
|
-
}
|
|
19933
|
-
const collectIx = await this.program.methods.batchCollectRedeemEarly(
|
|
19934
|
-
signedOrders.length,
|
|
19935
|
-
outcomeIndex
|
|
19936
|
-
).accounts({
|
|
19937
|
-
operator,
|
|
19938
|
-
payer,
|
|
19939
|
-
clobConfig,
|
|
19940
|
-
condition,
|
|
19941
|
-
collateralVault,
|
|
19942
|
-
vaultTokenAccount,
|
|
19943
|
-
feeRecipient: cfg.feeRecipient,
|
|
19944
|
-
yesMint,
|
|
19945
|
-
noMint,
|
|
19946
|
-
clobYesAta,
|
|
19947
|
-
clobNoAta,
|
|
19948
|
-
clobYesPosition,
|
|
19949
|
-
clobNoPosition,
|
|
19950
|
-
conditionalTokensProgram: this.programIds.conditionalTokens,
|
|
19951
|
-
tokenProgram: TOKEN_PROGRAM_ID,
|
|
19952
|
-
token2022Program: TOKEN_2022_PROGRAM_ID,
|
|
19953
|
-
systemProgram: SystemProgram.programId
|
|
19954
|
-
}).remainingAccounts([...userAccounts, ...hookAccounts, ...feeAccounts]).instruction();
|
|
19955
|
-
const alt = opts?.lookupTable ?? await this.buildAltForCollectBatch(condition, payer, collateralMint, signedOrders, outcomeIndex);
|
|
19956
|
-
return this._buildUnsignedVtx([...hookInitIxs, collectIx], alt, payer);
|
|
19957
|
-
}
|
|
19958
|
-
// ─── Register RedeemFeeOrder ─────────────────────────────────────────────────
|
|
19959
|
-
/**
|
|
19960
|
-
* Build a Transaction to register a RedeemFeeOrder on-chain (Ed25519 verify + PDA).
|
|
19961
|
-
* Must be sent before calling buildBatchRedeemWithFeeTx / buildBatchMergeWithFeeTx.
|
|
19962
|
-
*
|
|
19963
|
-
* ix[0]: batched Ed25519 { pubkey=order.user, sig, msg=128 bytes }
|
|
19964
|
-
* ix[1]: register_redeem_fee_order(nonce)
|
|
19965
|
-
*/
|
|
19966
|
-
async buildRegisterRedeemFeeOrderTx(signedOrder, payer) {
|
|
19967
|
-
const { order } = signedOrder;
|
|
19968
|
-
const [redeemFeeOrderRecord] = PDA.redeemFeeOrderRecord(order.user, order.nonce, this.programIds);
|
|
19969
|
-
const ed25519Ix = buildBatchedRedeemFeeEd25519Instruction([signedOrder]);
|
|
19970
|
-
const registerIx = await this.program.methods.registerRedeemFeeOrder(order.nonce).accounts({
|
|
19971
|
-
payer,
|
|
19972
|
-
clobConfig: this.configPda(),
|
|
19973
|
-
ixSysvar: IX_SYSVAR,
|
|
19974
|
-
orderSigner: order.user,
|
|
19975
|
-
redeemFeeOrderRecord,
|
|
19976
|
-
systemProgram: anchor6.web3.SystemProgram.programId
|
|
19977
|
-
}).instruction();
|
|
19978
|
-
const tx = new anchor6.web3.Transaction();
|
|
19979
|
-
tx.add(ed25519Ix, registerIx);
|
|
19980
|
-
return tx;
|
|
19981
|
-
}
|
|
19982
|
-
// ─── batchRedeemWithFee ───────────────────────────────────────────────────────
|
|
19983
|
-
/**
|
|
19984
|
-
* Build a VersionedTransaction for batchRedeemWithFee.
|
|
19985
|
-
* Each pair has a YES order + NO order for the same user (same signer or different).
|
|
19986
|
-
* After resolution: YES holder taker_amount > 0, NO holder taker_amount = 0 (or vice versa).
|
|
19987
|
-
*
|
|
19988
|
-
* Prerequisite: each order's RedeemFeeOrderRecord must be registered via buildRegisterRedeemFeeOrderTx.
|
|
19989
|
-
*/
|
|
19990
|
-
async buildBatchRedeemWithFeeTx(orderPairs, condition, operator, payer, opts) {
|
|
19991
|
-
if (orderPairs.length === 0) throw new InvalidParamError("At least 1 order pair required");
|
|
19992
|
-
const collateralMint = this.networkConfig.defaultCollateral.mint;
|
|
19993
|
-
const cfg = await this.fetchConfig();
|
|
19994
|
-
if (!cfg) throw new InvalidParamError("CLOB config not found on-chain");
|
|
19995
|
-
const clobConfig = this.configPda();
|
|
19996
|
-
const [yesMint] = PDA.yesMint(condition, this.programIds);
|
|
19997
|
-
const [noMint] = PDA.noMint(condition, this.programIds);
|
|
19998
|
-
const [collateralVault] = PDA.collateralVault(collateralMint, this.programIds);
|
|
19999
|
-
const [vaultTokenAccount] = PDA.vaultToken(collateralMint, this.programIds);
|
|
20000
|
-
const [yesExtraMeta] = PDA.extraAccountMetaList(yesMint, this.programIds);
|
|
20001
|
-
const [noExtraMeta] = PDA.extraAccountMetaList(noMint, this.programIds);
|
|
20002
|
-
const [hookConfig] = PDA.hookConfig(this.programIds);
|
|
20003
|
-
const [clobYesPosition] = PDA.position(condition, 1, clobConfig, this.programIds);
|
|
20004
|
-
const [clobNoPosition] = PDA.position(condition, 0, clobConfig, this.programIds);
|
|
20005
|
-
const clobYesAta = getAssociatedTokenAddressSync(yesMint, clobConfig, true, TOKEN_2022_PROGRAM_ID);
|
|
20006
|
-
const clobNoAta = getAssociatedTokenAddressSync(noMint, clobConfig, true, TOKEN_2022_PROGRAM_ID);
|
|
20007
|
-
const userAccounts = [];
|
|
20008
|
-
for (const { yes, no } of orderPairs) {
|
|
20009
|
-
const [yesRecord] = PDA.redeemFeeOrderRecord(yes.order.user, yes.order.nonce, this.programIds);
|
|
20010
|
-
const [noRecord] = PDA.redeemFeeOrderRecord(no.order.user, no.order.nonce, this.programIds);
|
|
20011
|
-
const userYesAta = getAssociatedTokenAddressSync(yesMint, yes.order.user, false, TOKEN_2022_PROGRAM_ID);
|
|
20012
|
-
const userNoAta = getAssociatedTokenAddressSync(noMint, no.order.user, false, TOKEN_2022_PROGRAM_ID);
|
|
20013
|
-
const [userYesPos] = PDA.position(condition, 1, yes.order.user, this.programIds);
|
|
20014
|
-
const [userNoPos] = PDA.position(condition, 0, no.order.user, this.programIds);
|
|
20015
|
-
const yesCollateral = getAssociatedTokenAddressSync(collateralMint, yes.order.user);
|
|
20016
|
-
const noCollateral = getAssociatedTokenAddressSync(collateralMint, no.order.user);
|
|
20017
|
-
userAccounts.push(
|
|
20018
|
-
{ pubkey: yesRecord, isSigner: false, isWritable: true },
|
|
20019
|
-
{ pubkey: noRecord, isSigner: false, isWritable: true },
|
|
20020
|
-
{ pubkey: yes.order.user, isSigner: false, isWritable: false },
|
|
20021
|
-
{ pubkey: no.order.user, isSigner: false, isWritable: false },
|
|
20022
|
-
{ pubkey: userYesAta, isSigner: false, isWritable: true },
|
|
20023
|
-
{ pubkey: userNoAta, isSigner: false, isWritable: true },
|
|
20024
|
-
{ pubkey: userYesPos, isSigner: false, isWritable: true },
|
|
20025
|
-
{ pubkey: userNoPos, isSigner: false, isWritable: true },
|
|
20026
|
-
{ pubkey: yesCollateral, isSigner: false, isWritable: true },
|
|
20027
|
-
{ pubkey: noCollateral, isSigner: false, isWritable: true }
|
|
20028
|
-
);
|
|
20029
|
-
}
|
|
20030
|
-
const hookAccounts = [
|
|
20031
|
-
{ pubkey: yesExtraMeta, isSigner: false, isWritable: false },
|
|
20032
|
-
{ pubkey: noExtraMeta, isSigner: false, isWritable: false },
|
|
20033
|
-
{ pubkey: hookConfig, isSigner: false, isWritable: false },
|
|
20034
|
-
{ pubkey: this.programIds.hook, isSigner: false, isWritable: false }
|
|
20035
|
-
];
|
|
20036
|
-
let feeAccounts = [];
|
|
20037
|
-
if (this.programIds.feeManagement && this.feeConfigOwner) {
|
|
20038
|
-
const companyAddr = await this.companyAddress();
|
|
20039
|
-
const refVault = await this.referralVault();
|
|
20040
|
-
if (companyAddr && refVault) {
|
|
20041
|
-
const feeOverridePda = PDA.marketFeeOverride(condition, this.programIds)[0];
|
|
20042
|
-
const feeOverrideExists = await this.provider.connection.getAccountInfo(feeOverridePda);
|
|
20043
|
-
if (feeOverrideExists) {
|
|
20044
|
-
const oracleVault = opts?.marketOracleVault ?? await this.getMarketOracleVault(condition, collateralMint) ?? payer;
|
|
20045
|
-
feeAccounts = [
|
|
20046
|
-
{ pubkey: this.programIds.feeManagement, isSigner: false, isWritable: false },
|
|
20047
|
-
{ pubkey: PDA.feeConfig(this.feeConfigOwner, this.programIds)[0], isSigner: false, isWritable: false },
|
|
20048
|
-
{ pubkey: feeOverridePda, isSigner: false, isWritable: false },
|
|
20049
|
-
{ pubkey: getAssociatedTokenAddressSync(collateralMint, companyAddr), isSigner: false, isWritable: true },
|
|
20050
|
-
{ pubkey: oracleVault, isSigner: false, isWritable: true },
|
|
20051
|
-
{ pubkey: refVault, isSigner: false, isWritable: true }
|
|
20052
|
-
];
|
|
20053
|
-
}
|
|
20054
|
-
}
|
|
20055
|
-
}
|
|
20056
|
-
await this._ensureClobOutcomeAtas(yesMint, noMint, clobConfig, clobYesAta, clobNoAta);
|
|
20057
|
-
const hookInitIxs = [];
|
|
20058
|
-
if (this.hookClient) {
|
|
20059
|
-
for (const mint of [yesMint, noMint]) {
|
|
20060
|
-
const ix = await this.hookClient.buildInitHookIxIfNeeded(mint, payer);
|
|
20061
|
-
if (ix) hookInitIxs.push(ix);
|
|
20062
|
-
}
|
|
20063
|
-
}
|
|
20064
|
-
const redeemIx = await this.program.methods.batchRedeemWithFee(orderPairs.length).accounts({
|
|
20065
|
-
operator,
|
|
20066
|
-
payer,
|
|
20067
|
-
clobConfig,
|
|
20068
|
-
condition,
|
|
20069
|
-
collateralVault,
|
|
20070
|
-
vaultTokenAccount,
|
|
20071
|
-
feeRecipient: cfg.feeRecipient,
|
|
20072
|
-
yesMint,
|
|
20073
|
-
noMint,
|
|
20074
|
-
clobYesAta,
|
|
20075
|
-
clobNoAta,
|
|
20076
|
-
clobYesPosition,
|
|
20077
|
-
clobNoPosition,
|
|
20078
|
-
conditionalTokensProgram: this.programIds.conditionalTokens,
|
|
20079
|
-
tokenProgram: TOKEN_PROGRAM_ID,
|
|
20080
|
-
token2022Program: TOKEN_2022_PROGRAM_ID,
|
|
20081
|
-
systemProgram: anchor6.web3.SystemProgram.programId
|
|
20082
|
-
}).remainingAccounts([...userAccounts, ...hookAccounts, ...feeAccounts]).instruction();
|
|
20083
|
-
const alt = opts?.lookupTable ?? await this.buildAltForCondition(condition, payer, collateralMint);
|
|
20084
|
-
return this._buildUnsignedVtx([...hookInitIxs, redeemIx], alt, payer);
|
|
20085
|
-
}
|
|
20086
|
-
// ─── batchMergeWithFee ────────────────────────────────────────────────────────
|
|
20087
|
-
/**
|
|
20088
|
-
* Build a VersionedTransaction for batchMergeWithFee (pre-resolution merge with fee).
|
|
20089
|
-
* Each pair: YES order + NO order with equal amounts for the same user.
|
|
20090
|
-
* Only yes_signer receives net USDS (mirrors EVM _matchMergeOrder).
|
|
20091
|
-
*
|
|
20092
|
-
* Prerequisite: each order's RedeemFeeOrderRecord must be registered via buildRegisterRedeemFeeOrderTx.
|
|
20093
|
-
*/
|
|
20094
|
-
async buildBatchMergeWithFeeTx(orderPairs, condition, operator, payer, opts) {
|
|
20095
|
-
if (orderPairs.length === 0) throw new InvalidParamError("At least 1 order pair required");
|
|
20096
|
-
const collateralMint = this.networkConfig.defaultCollateral.mint;
|
|
20097
|
-
const cfg = await this.fetchConfig();
|
|
20098
|
-
if (!cfg) throw new InvalidParamError("CLOB config not found on-chain");
|
|
20099
|
-
const clobConfig = this.configPda();
|
|
20100
|
-
const [yesMint] = PDA.yesMint(condition, this.programIds);
|
|
20101
|
-
const [noMint] = PDA.noMint(condition, this.programIds);
|
|
20102
|
-
const [collateralVault] = PDA.collateralVault(collateralMint, this.programIds);
|
|
20103
|
-
const [vaultTokenAccount] = PDA.vaultToken(collateralMint, this.programIds);
|
|
20104
|
-
const [yesExtraMeta] = PDA.extraAccountMetaList(yesMint, this.programIds);
|
|
20105
|
-
const [noExtraMeta] = PDA.extraAccountMetaList(noMint, this.programIds);
|
|
20106
|
-
const [hookConfig] = PDA.hookConfig(this.programIds);
|
|
20107
|
-
const [clobYesPosition] = PDA.position(condition, 1, clobConfig, this.programIds);
|
|
20108
|
-
const [clobNoPosition] = PDA.position(condition, 0, clobConfig, this.programIds);
|
|
20109
|
-
const clobYesAta = getAssociatedTokenAddressSync(yesMint, clobConfig, true, TOKEN_2022_PROGRAM_ID);
|
|
20110
|
-
const clobNoAta = getAssociatedTokenAddressSync(noMint, clobConfig, true, TOKEN_2022_PROGRAM_ID);
|
|
20111
|
-
const userAccounts = [];
|
|
20112
|
-
for (const { yes, no } of orderPairs) {
|
|
20113
|
-
const [yesRecord] = PDA.redeemFeeOrderRecord(yes.order.user, yes.order.nonce, this.programIds);
|
|
20114
|
-
const [noRecord] = PDA.redeemFeeOrderRecord(no.order.user, no.order.nonce, this.programIds);
|
|
20115
|
-
const userYesAta = getAssociatedTokenAddressSync(yesMint, yes.order.user, false, TOKEN_2022_PROGRAM_ID);
|
|
20116
|
-
const userNoAta = getAssociatedTokenAddressSync(noMint, no.order.user, false, TOKEN_2022_PROGRAM_ID);
|
|
20117
|
-
const [userYesPos] = PDA.position(condition, 1, yes.order.user, this.programIds);
|
|
20118
|
-
const [userNoPos] = PDA.position(condition, 0, no.order.user, this.programIds);
|
|
20119
|
-
const yesCollateral = getAssociatedTokenAddressSync(collateralMint, yes.order.user);
|
|
20120
|
-
userAccounts.push(
|
|
20121
|
-
{ pubkey: yesRecord, isSigner: false, isWritable: true },
|
|
20122
|
-
{ pubkey: noRecord, isSigner: false, isWritable: true },
|
|
20123
|
-
{ pubkey: yes.order.user, isSigner: false, isWritable: false },
|
|
20124
|
-
{ pubkey: no.order.user, isSigner: false, isWritable: false },
|
|
20125
|
-
{ pubkey: userYesAta, isSigner: false, isWritable: true },
|
|
20126
|
-
{ pubkey: userNoAta, isSigner: false, isWritable: true },
|
|
20127
|
-
{ pubkey: userYesPos, isSigner: false, isWritable: true },
|
|
20128
|
-
{ pubkey: userNoPos, isSigner: false, isWritable: true },
|
|
20129
|
-
{ pubkey: yesCollateral, isSigner: false, isWritable: true }
|
|
20130
|
-
);
|
|
20131
|
-
}
|
|
20132
|
-
const hookAccounts = [
|
|
20133
|
-
{ pubkey: yesExtraMeta, isSigner: false, isWritable: false },
|
|
20134
|
-
{ pubkey: noExtraMeta, isSigner: false, isWritable: false },
|
|
20135
|
-
{ pubkey: hookConfig, isSigner: false, isWritable: false },
|
|
20136
|
-
{ pubkey: this.programIds.hook, isSigner: false, isWritable: false }
|
|
20137
|
-
];
|
|
20138
|
-
let feeAccounts = [];
|
|
20139
|
-
if (this.programIds.feeManagement && this.feeConfigOwner) {
|
|
20140
|
-
const companyAddr = await this.companyAddress();
|
|
20141
|
-
const refVault = await this.referralVault();
|
|
20142
|
-
if (companyAddr && refVault) {
|
|
20143
|
-
const feeOverridePda = PDA.marketFeeOverride(condition, this.programIds)[0];
|
|
20144
|
-
const feeOverrideExists = await this.provider.connection.getAccountInfo(feeOverridePda);
|
|
20145
|
-
if (feeOverrideExists) {
|
|
20146
|
-
const oracleVault = opts?.marketOracleVault ?? await this.getMarketOracleVault(condition, collateralMint) ?? payer;
|
|
20147
|
-
feeAccounts = [
|
|
20148
|
-
{ pubkey: this.programIds.feeManagement, isSigner: false, isWritable: false },
|
|
20149
|
-
{ pubkey: PDA.feeConfig(this.feeConfigOwner, this.programIds)[0], isSigner: false, isWritable: false },
|
|
20150
|
-
{ pubkey: feeOverridePda, isSigner: false, isWritable: false },
|
|
20151
|
-
{ pubkey: getAssociatedTokenAddressSync(collateralMint, companyAddr), isSigner: false, isWritable: true },
|
|
20152
|
-
{ pubkey: oracleVault, isSigner: false, isWritable: true },
|
|
20153
|
-
{ pubkey: refVault, isSigner: false, isWritable: true }
|
|
20154
|
-
];
|
|
20155
|
-
}
|
|
20156
|
-
}
|
|
20157
|
-
}
|
|
20158
|
-
await this._ensureClobOutcomeAtas(yesMint, noMint, clobConfig, clobYesAta, clobNoAta);
|
|
20159
|
-
const hookInitIxs = [];
|
|
20160
|
-
if (this.hookClient) {
|
|
20161
|
-
for (const mint of [yesMint, noMint]) {
|
|
20162
|
-
const ix = await this.hookClient.buildInitHookIxIfNeeded(mint, payer);
|
|
20163
|
-
if (ix) hookInitIxs.push(ix);
|
|
20164
|
-
}
|
|
20165
|
-
}
|
|
20166
|
-
const mergeIx = await this.program.methods.batchMergeWithFee(orderPairs.length).accounts({
|
|
20167
|
-
operator,
|
|
20168
|
-
payer,
|
|
20169
|
-
clobConfig,
|
|
20170
|
-
condition,
|
|
20171
|
-
collateralVault,
|
|
20172
|
-
vaultTokenAccount,
|
|
20173
|
-
feeRecipient: cfg.feeRecipient,
|
|
20174
|
-
yesMint,
|
|
20175
|
-
noMint,
|
|
20176
|
-
clobYesAta,
|
|
20177
|
-
clobNoAta,
|
|
20178
|
-
clobYesPosition,
|
|
20179
|
-
clobNoPosition,
|
|
20180
|
-
conditionalTokensProgram: this.programIds.conditionalTokens,
|
|
20181
|
-
tokenProgram: TOKEN_PROGRAM_ID,
|
|
20182
|
-
token2022Program: TOKEN_2022_PROGRAM_ID,
|
|
20183
|
-
systemProgram: anchor6.web3.SystemProgram.programId
|
|
20184
|
-
}).remainingAccounts([...userAccounts, ...hookAccounts, ...feeAccounts]).instruction();
|
|
20185
|
-
const alt = opts?.lookupTable ?? await this.buildAltForCondition(condition, payer, collateralMint);
|
|
20186
|
-
return this._buildUnsignedVtx([...hookInitIxs, mergeIx], alt, payer);
|
|
20187
|
-
}
|
|
20188
|
-
/**
|
|
20189
|
-
* Build ALT for batchCollectRedeemEarly — includes per-user accounts so all
|
|
20190
|
-
* remaining_accounts fit as 1-byte ALT indices instead of 32-byte inline addresses.
|
|
20191
|
-
*/
|
|
20192
|
-
async buildAltForCollectBatch(condition, payer, collateralMint, signedOrders, outcomeIndex) {
|
|
20193
|
-
const userKeys = signedOrders.map((o) => o.order.user.toBase58()).sort((a, b) => a.localeCompare(b)).join(",");
|
|
20194
|
-
const cacheKey = `${condition.toBase58()}:collect:${userKeys}`;
|
|
20195
|
-
if (this._altCache.has(cacheKey)) return this._altCache.get(cacheKey);
|
|
20196
|
-
const { connection } = this.provider;
|
|
20197
|
-
const clobConfigPda = this.configPda();
|
|
20198
|
-
const [yesMint] = PDA.yesMint(condition, this.programIds);
|
|
20199
|
-
const [noMint] = PDA.noMint(condition, this.programIds);
|
|
20200
|
-
const outcomeMint = outcomeIndex === 1 ? yesMint : noMint;
|
|
20201
|
-
const [extraAccountMeta] = PDA.extraAccountMetaList(outcomeMint, this.programIds);
|
|
20202
|
-
const [hookConfig] = PDA.hookConfig(this.programIds);
|
|
20203
|
-
const [collateralVault] = PDA.collateralVault(collateralMint, this.programIds);
|
|
20204
|
-
const [vaultTokenAccount] = PDA.vaultToken(collateralMint, this.programIds);
|
|
20205
|
-
const clobYesAta = getAssociatedTokenAddressSync(yesMint, clobConfigPda, true, TOKEN_2022_PROGRAM_ID);
|
|
20206
|
-
const clobNoAta = getAssociatedTokenAddressSync(noMint, clobConfigPda, true, TOKEN_2022_PROGRAM_ID);
|
|
20207
|
-
const [clobYesPos] = PDA.position(condition, 1, clobConfigPda, this.programIds);
|
|
20208
|
-
const [clobNoPos] = PDA.position(condition, 0, clobConfigPda, this.programIds);
|
|
20209
|
-
const feeRecipientAddr = (await this.fetchConfig())?.feeRecipient;
|
|
20210
|
-
const addresses = [
|
|
20211
|
-
this.programIds.clobExchange,
|
|
20212
|
-
this.programIds.conditionalTokens,
|
|
20213
|
-
this.programIds.hook,
|
|
20214
|
-
TOKEN_PROGRAM_ID,
|
|
20215
|
-
TOKEN_2022_PROGRAM_ID,
|
|
20216
|
-
SystemProgram.programId,
|
|
20217
|
-
clobConfigPda,
|
|
20218
|
-
hookConfig,
|
|
20219
|
-
condition,
|
|
20220
|
-
yesMint,
|
|
20221
|
-
noMint,
|
|
20222
|
-
extraAccountMeta,
|
|
20223
|
-
collateralVault,
|
|
20224
|
-
vaultTokenAccount,
|
|
20225
|
-
clobYesAta,
|
|
20226
|
-
clobNoAta,
|
|
20227
|
-
clobYesPos,
|
|
20228
|
-
clobNoPos
|
|
20229
|
-
];
|
|
20230
|
-
if (feeRecipientAddr) addresses.push(feeRecipientAddr);
|
|
20231
|
-
if (this.feeConfigOwner && this.programIds.feeManagement) {
|
|
20232
|
-
const companyAddr = await this.companyAddress();
|
|
20233
|
-
const refVault = await this.referralVault();
|
|
20234
|
-
addresses.push(this.programIds.feeManagement);
|
|
20235
|
-
addresses.push(PDA.feeConfig(this.feeConfigOwner, this.programIds)[0]);
|
|
20236
|
-
addresses.push(PDA.marketFeeOverride(condition, this.programIds)[0]);
|
|
20237
|
-
if (companyAddr) addresses.push(getAssociatedTokenAddressSync(collateralMint, companyAddr));
|
|
20238
|
-
if (refVault) addresses.push(refVault);
|
|
20239
|
-
const oracleVault = await this.getMarketOracleVault(condition, collateralMint) ?? payer;
|
|
20240
|
-
addresses.push(oracleVault);
|
|
20241
|
-
}
|
|
20242
|
-
for (const { order } of signedOrders) {
|
|
20243
|
-
const [collectFeeOrderRecord] = PDA.collectFeeOrderRecord(order.user, order.nonce, this.programIds);
|
|
20244
|
-
const userTokenAta = getAssociatedTokenAddressSync(outcomeMint, order.user, false, TOKEN_2022_PROGRAM_ID);
|
|
20245
|
-
const [userPosition] = PDA.position(condition, outcomeIndex, order.user, this.programIds);
|
|
20246
|
-
addresses.push(collectFeeOrderRecord, order.user, userTokenAta, userPosition);
|
|
20247
|
-
}
|
|
20248
|
-
const slot = await connection.getSlot("finalized");
|
|
20249
|
-
const [createIx, altAddress] = AddressLookupTableProgram.createLookupTable(
|
|
20250
|
-
{ authority: payer, payer, recentSlot: slot }
|
|
20251
|
-
);
|
|
20252
|
-
const BATCH = 30;
|
|
20253
|
-
const extendIxs = [];
|
|
20254
|
-
for (let i = 0; i < addresses.length; i += BATCH) {
|
|
20255
|
-
extendIxs.push(AddressLookupTableProgram.extendLookupTable(
|
|
20256
|
-
{ payer, authority: payer, lookupTable: altAddress, addresses: addresses.slice(i, i + BATCH) }
|
|
20257
|
-
));
|
|
20258
|
-
}
|
|
20259
|
-
await this._sendLegacyTx([createIx, extendIxs[0]]);
|
|
20260
|
-
for (let i = 1; i < extendIxs.length; i++) await this._sendLegacyTx([extendIxs[i]]);
|
|
20261
|
-
for (let attempt = 0; attempt < 30; attempt++) {
|
|
20262
|
-
await new Promise((r) => setTimeout(r, 1e3));
|
|
20263
|
-
const res = await connection.getAddressLookupTable(altAddress);
|
|
20264
|
-
if (res.value && res.value.state.addresses.length === addresses.length) {
|
|
20265
|
-
this._altCache.set(cacheKey, res.value);
|
|
20266
|
-
return res.value;
|
|
20267
|
-
}
|
|
20268
|
-
}
|
|
20269
|
-
throw new Error(`ALT ${altAddress.toBase58()} not active after 30s`);
|
|
20270
|
-
}
|
|
20271
|
-
/**
|
|
20272
|
-
* Build ALT with static accounts for a condition — no order-specific PDAs needed.
|
|
20273
|
-
* Use before buildBatchCollectRedeemEarlyTx when no prior buildMatchOrdersTx ran in this session.
|
|
20274
|
-
*/
|
|
20275
|
-
async buildAltForCondition(condition, _payer, collateralMint) {
|
|
20276
|
-
const cacheKey = condition.toBase58();
|
|
20277
|
-
if (this._altCache.has(cacheKey)) return this._altCache.get(cacheKey);
|
|
20278
|
-
const mint = collateralMint ?? this.networkConfig.defaultCollateral.mint;
|
|
20279
|
-
const payer = this.walletPubkey;
|
|
20280
|
-
const { connection } = this.provider;
|
|
20281
|
-
const clobConfigPda = this.configPda();
|
|
20282
|
-
const [yesMint] = PDA.yesMint(condition, this.programIds);
|
|
20283
|
-
const [noMint] = PDA.noMint(condition, this.programIds);
|
|
20284
|
-
const [extraAccountMeta] = PDA.extraAccountMetaList(yesMint, this.programIds);
|
|
20285
|
-
const [hookConfig] = PDA.hookConfig(this.programIds);
|
|
20286
|
-
const [collateralVault] = PDA.collateralVault(mint, this.programIds);
|
|
20287
|
-
const [vaultTokenAccount] = PDA.vaultToken(mint, this.programIds);
|
|
20288
|
-
const clobYesAta = getAssociatedTokenAddressSync(yesMint, clobConfigPda, true, TOKEN_2022_PROGRAM_ID);
|
|
20289
|
-
const clobNoAta = getAssociatedTokenAddressSync(noMint, clobConfigPda, true, TOKEN_2022_PROGRAM_ID);
|
|
20290
|
-
const feeRecipientAddr = (await this.fetchConfig())?.feeRecipient;
|
|
20291
|
-
const addresses = [
|
|
20292
|
-
Ed25519Program.programId,
|
|
20293
|
-
this.programIds.clobExchange,
|
|
20294
|
-
this.programIds.conditionalTokens,
|
|
20295
|
-
this.programIds.hook,
|
|
20296
|
-
TOKEN_PROGRAM_ID,
|
|
20297
|
-
TOKEN_2022_PROGRAM_ID,
|
|
20298
|
-
SystemProgram.programId,
|
|
20299
|
-
SYSVAR_INSTRUCTIONS_PUBKEY,
|
|
20300
|
-
clobConfigPda,
|
|
20301
|
-
hookConfig,
|
|
20302
|
-
condition,
|
|
20303
|
-
yesMint,
|
|
20304
|
-
noMint,
|
|
20305
|
-
extraAccountMeta,
|
|
20306
|
-
collateralVault,
|
|
20307
|
-
vaultTokenAccount,
|
|
20308
|
-
clobYesAta,
|
|
20309
|
-
clobNoAta
|
|
20310
|
-
];
|
|
20311
|
-
if (feeRecipientAddr) addresses.push(feeRecipientAddr);
|
|
20312
|
-
if (this.feeConfigOwner && this.programIds.feeManagement) {
|
|
20313
|
-
const companyAddr = await this.companyAddress();
|
|
20314
|
-
const refVault = await this.referralVault();
|
|
20315
|
-
addresses.push(this.programIds.feeManagement);
|
|
20316
|
-
addresses.push(PDA.feeConfig(this.feeConfigOwner, this.programIds)[0]);
|
|
20317
|
-
addresses.push(PDA.marketFeeOverride(condition, this.programIds)[0]);
|
|
20318
|
-
if (companyAddr) addresses.push(getAssociatedTokenAddressSync(mint, companyAddr));
|
|
20319
|
-
if (refVault) addresses.push(refVault);
|
|
20320
|
-
const oracleVault = await this.getMarketOracleVault(condition, mint) ?? payer;
|
|
20321
|
-
addresses.push(oracleVault);
|
|
20322
|
-
}
|
|
20323
|
-
const slot = await connection.getSlot("finalized");
|
|
20324
|
-
const [createIx, altAddress] = AddressLookupTableProgram.createLookupTable(
|
|
20325
|
-
{ authority: payer, payer, recentSlot: slot }
|
|
20326
|
-
);
|
|
20327
|
-
const BATCH = 30;
|
|
20328
|
-
const extendIxs = [];
|
|
20329
|
-
for (let i = 0; i < addresses.length; i += BATCH) {
|
|
20330
|
-
extendIxs.push(AddressLookupTableProgram.extendLookupTable(
|
|
20331
|
-
{ payer, authority: payer, lookupTable: altAddress, addresses: addresses.slice(i, i + BATCH) }
|
|
20332
|
-
));
|
|
20333
|
-
}
|
|
20334
|
-
await this._sendLegacyTx([createIx, extendIxs[0]]);
|
|
20335
|
-
for (let i = 1; i < extendIxs.length; i++) await this._sendLegacyTx([extendIxs[i]]);
|
|
20336
|
-
for (let attempt = 0; attempt < 30; attempt++) {
|
|
20337
|
-
await new Promise((r) => setTimeout(r, 1e3));
|
|
20338
|
-
const res = await connection.getAddressLookupTable(altAddress);
|
|
20339
|
-
if (res.value && res.value.state.addresses.length === addresses.length) {
|
|
20340
|
-
this._altCache.set(cacheKey, res.value);
|
|
20341
|
-
return res.value;
|
|
20342
|
-
}
|
|
20343
|
-
}
|
|
20344
|
-
throw new Error(`ALT ${altAddress.toBase58()} not active after 30s`);
|
|
20345
|
-
}
|
|
20346
|
-
// ─── Queries ─────────────────────────────────────────────────────────────────
|
|
20347
|
-
async fetchConfig() {
|
|
20348
|
-
try {
|
|
20349
|
-
const acc = await this.program.account.clobConfig.fetch(this.configPda());
|
|
20350
|
-
return {
|
|
20351
|
-
owner: acc.owner,
|
|
20352
|
-
operators: acc.operators,
|
|
20353
|
-
operatorsLen: acc.operatorsLen,
|
|
20354
|
-
feeRecipient: acc.feeRecipient,
|
|
20355
|
-
feeRateBps: acc.feeRateBps,
|
|
20356
|
-
conditionalTokensProgram: acc.conditionalTokensProgram,
|
|
20357
|
-
isPaused: acc.isPaused,
|
|
20358
|
-
bump: acc.bump
|
|
20359
|
-
};
|
|
20360
|
-
} catch {
|
|
20361
|
-
return null;
|
|
20362
|
-
}
|
|
20363
|
-
}
|
|
20364
|
-
async fetchOrderStatus(maker, nonce) {
|
|
20365
|
-
try {
|
|
20366
|
-
const [pda] = PDA.orderStatus(maker, nonce, this.programIds);
|
|
20367
|
-
const acc = await this.program.account.orderStatus.fetch(pda);
|
|
20368
|
-
return {
|
|
20369
|
-
maker: acc.maker,
|
|
20370
|
-
nonce: acc.nonce,
|
|
20371
|
-
filledAmount: acc.filledAmount,
|
|
20372
|
-
bump: acc.bump
|
|
20373
|
-
};
|
|
20374
|
-
} catch {
|
|
20375
|
-
return null;
|
|
20376
|
-
}
|
|
20377
|
-
}
|
|
20378
|
-
async fetchOrderRecord(maker, nonce) {
|
|
20379
|
-
try {
|
|
20380
|
-
const [pda] = PDA.orderRecord(maker, nonce, this.programIds);
|
|
20381
|
-
const acc = await this.program.account.signedOrderRecord.fetch(pda);
|
|
20382
|
-
return acc;
|
|
20383
|
-
} catch {
|
|
20384
|
-
return null;
|
|
20385
|
-
}
|
|
20386
|
-
}
|
|
20387
|
-
};
|
|
20388
|
-
var MAX_APPROVE_AMOUNT = new BN4("18446744073709551615");
|
|
20389
|
-
function buildCreateUserAtasTx(condition, user, payer, programIds) {
|
|
20390
|
-
const [yesMint] = PDA.yesMint(condition, programIds);
|
|
20391
|
-
const [noMint] = PDA.noMint(condition, programIds);
|
|
20392
|
-
const yesAta = getAssociatedTokenAddressSync(yesMint, user, false, TOKEN_PROGRAM_ID);
|
|
20393
|
-
const noAta = getAssociatedTokenAddressSync(noMint, user, false, TOKEN_PROGRAM_ID);
|
|
20394
|
-
const tx = new Transaction();
|
|
20395
|
-
tx.feePayer = payer;
|
|
20396
|
-
tx.add(
|
|
20397
|
-
createAssociatedTokenAccountIdempotentInstruction(
|
|
20398
|
-
payer,
|
|
20399
|
-
yesAta,
|
|
20400
|
-
user,
|
|
20401
|
-
yesMint,
|
|
20402
|
-
TOKEN_PROGRAM_ID,
|
|
20403
|
-
ASSOCIATED_TOKEN_PROGRAM_ID
|
|
20404
|
-
),
|
|
20405
|
-
createAssociatedTokenAccountIdempotentInstruction(
|
|
20406
|
-
payer,
|
|
20407
|
-
noAta,
|
|
20408
|
-
user,
|
|
17985
|
+
TOKEN_PROGRAM_ID,
|
|
17986
|
+
ASSOCIATED_TOKEN_PROGRAM_ID
|
|
17987
|
+
),
|
|
17988
|
+
createAssociatedTokenAccountIdempotentInstruction(
|
|
17989
|
+
payer,
|
|
17990
|
+
noAta,
|
|
17991
|
+
user,
|
|
20409
17992
|
noMint,
|
|
20410
17993
|
TOKEN_PROGRAM_ID,
|
|
20411
17994
|
ASSOCIATED_TOKEN_PROGRAM_ID
|
|
@@ -20434,15 +18017,26 @@ function buildApproveAllOutcomeTokensTx(condition, signer, payer, delegate, prog
|
|
|
20434
18017
|
const yesAta = getAssociatedTokenAddressSync(yesMint, signer, false, TOKEN_PROGRAM_ID);
|
|
20435
18018
|
const noAta = getAssociatedTokenAddressSync(noMint, signer, false, TOKEN_PROGRAM_ID);
|
|
20436
18019
|
const amountBig = BigInt(amount.toString());
|
|
18020
|
+
const approveYesIx = createApproveInstruction(
|
|
18021
|
+
yesAta,
|
|
18022
|
+
delegate,
|
|
18023
|
+
signer,
|
|
18024
|
+
amountBig,
|
|
18025
|
+
[]
|
|
18026
|
+
);
|
|
18027
|
+
const approveNoIx = createApproveInstruction(
|
|
18028
|
+
noAta,
|
|
18029
|
+
delegate,
|
|
18030
|
+
signer,
|
|
18031
|
+
amountBig,
|
|
18032
|
+
[]
|
|
18033
|
+
);
|
|
20437
18034
|
const tx = new Transaction();
|
|
20438
18035
|
tx.feePayer = payer;
|
|
20439
|
-
tx.add(
|
|
20440
|
-
createApproveInstruction(yesAta, delegate, signer, amountBig, [], TOKEN_PROGRAM_ID),
|
|
20441
|
-
createApproveInstruction(noAta, delegate, signer, amountBig, [], TOKEN_PROGRAM_ID)
|
|
20442
|
-
);
|
|
18036
|
+
tx.add(approveYesIx, approveNoIx);
|
|
20443
18037
|
return tx;
|
|
20444
18038
|
}
|
|
20445
18039
|
|
|
20446
|
-
export { AccountNotFoundError, AdminClient, ClobClient,
|
|
18040
|
+
export { AccountNotFoundError, AdminClient, ClobClient, CtfClient, DisputeClient, FEE_DENOMINATOR, FeeManagementClient, 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 };
|
|
20447
18041
|
//# sourceMappingURL=index.mjs.map
|
|
20448
18042
|
//# sourceMappingURL=index.mjs.map
|