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