@vercora-protocol/sdk 0.0.10 → 0.0.12
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/README.md +331 -104
- package/dist/client.d.ts +23 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +90 -27
- package/dist/client.js.map +1 -1
- package/dist/generated/vercora.d.ts +28 -3
- package/dist/generated/vercora.d.ts.map +1 -1
- package/dist/idl/vercora.json +28 -3
- package/dist/marketUi.d.ts +3 -3
- package/dist/marketUi.d.ts.map +1 -1
- package/dist/marketUi.js +4 -3
- package/dist/marketUi.js.map +1 -1
- package/dist/types.d.ts +35 -6
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -14,97 +14,207 @@ yarn add @vercora-protocol/sdk
|
|
|
14
14
|
|
|
15
15
|
```bash
|
|
16
16
|
npm install @coral-xyz/anchor @solana/web3.js @solana/spl-token bn.js
|
|
17
|
+
# or
|
|
18
|
+
yarn add @coral-xyz/anchor @solana/web3.js @solana/spl-token bn.js
|
|
17
19
|
```
|
|
18
20
|
|
|
19
21
|
## Quick start
|
|
20
22
|
|
|
21
23
|
```ts
|
|
22
24
|
import * as anchor from "@coral-xyz/anchor";
|
|
23
|
-
import { Program } from "@coral-xyz/anchor";
|
|
24
25
|
import { Connection, clusterApiUrl } from "@solana/web3.js";
|
|
25
|
-
import {
|
|
26
|
-
IDL,
|
|
27
|
-
PROGRAM_ID,
|
|
28
|
-
PredictionMarketClient,
|
|
29
|
-
} from "@vercora-protocol/sdk";
|
|
26
|
+
import { IDL, PROGRAM_ID, PredictionMarketClient } from "@vercora-protocol/sdk";
|
|
30
27
|
import type { Vercora } from "@vercora-protocol/sdk";
|
|
31
|
-
import { BN } from "bn.js";
|
|
32
28
|
|
|
33
|
-
// 1. Set up an Anchor provider (browser wallet / NodeWallet)
|
|
34
29
|
const connection = new Connection(clusterApiUrl("devnet"));
|
|
35
30
|
const provider = new anchor.AnchorProvider(connection, wallet, {});
|
|
36
31
|
anchor.setProvider(provider);
|
|
37
32
|
|
|
38
|
-
//
|
|
33
|
+
// Bundled IDL — program id is embedded in `IDL.address` (`PROGRAM_ID` matches it)
|
|
39
34
|
const program = new anchor.Program<Vercora>(IDL, provider);
|
|
40
|
-
|
|
41
|
-
// 3. Create the client
|
|
42
35
|
const client = new PredictionMarketClient(program);
|
|
43
36
|
```
|
|
44
37
|
|
|
45
|
-
|
|
38
|
+
Most transaction methods use **`provider.wallet.publicKey`** as the signer (`user`, `authority`, `creator`, etc.). Pass a wallet that can sign; read-only flows can use a read-only provider for fetch helpers only.
|
|
46
39
|
|
|
47
|
-
|
|
40
|
+
## Package exports
|
|
48
41
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
42
|
+
| Export | Description |
|
|
43
|
+
| ------------------------ | -------------------------------------------------------------------------------------------- |
|
|
44
|
+
| `PredictionMarketClient` | High-level program wrapper (see below). |
|
|
45
|
+
| `IDL`, `PROGRAM_ID` | Anchor IDL JSON and `PublicKey` for the deployed program. |
|
|
46
|
+
| `pda` helpers | `deriveMarket`, `deriveVault`, `deriveParimutuelState`, … (see [PDA helpers](#pda-helpers)). |
|
|
47
|
+
| `types` | Params and account shapes (`CreateMarketParams`, `ListedMarket`, …). |
|
|
48
|
+
| `marketUi` | Pure UI helpers (`getMarketLifecycleStatus`, `formatTimeLeft`, …). |
|
|
49
|
+
| `Vercora` (type) | Anchor `Program` generic for `Program<Vercora>`. |
|
|
52
50
|
|
|
53
|
-
|
|
51
|
+
---
|
|
54
52
|
|
|
55
|
-
##
|
|
53
|
+
## `PredictionMarketClient` API
|
|
56
54
|
|
|
57
|
-
|
|
55
|
+
Public properties: **`program`**, **`connection`**, **`globalConfig`** (PDA).
|
|
58
56
|
|
|
59
|
-
###
|
|
57
|
+
### Global config (authority)
|
|
60
58
|
|
|
61
|
-
|
|
59
|
+
| Method | Purpose |
|
|
60
|
+
| ----------------------------------- | ---------------------------------------------- |
|
|
61
|
+
| `initializeConfig(params)` | One-time init; `authority` = connected wallet. |
|
|
62
|
+
| `updateConfig(params)` | Update fees, treasury, authorities. |
|
|
63
|
+
| `addAllowedCollateralMint(mint)` | Allowlist a collateral mint. |
|
|
64
|
+
| `removeAllowedCollateralMint(mint)` | Remove from allowlist. |
|
|
62
65
|
|
|
63
|
-
|
|
64
|
-
- **Minimal integration** — stake, withdraw, claim; no outcome-token listings to maintain.
|
|
65
|
-
- Positions are ledger entries, not transferable tokens. Early withdrawal may use a configurable penalty.
|
|
66
|
-
- **Best for:** most prediction-style apps and teams that want live odds and settlement without operating liquidity infrastructure.
|
|
66
|
+
### Platforms & categories
|
|
67
67
|
|
|
68
|
-
|
|
68
|
+
| Method | Purpose |
|
|
69
|
+
| ------------------------------ | ------------------------------------------------------------------------ |
|
|
70
|
+
| `registerPlatform(params)` | Next `platform_id` from `GlobalConfig`; returns `{ platformId, sig }`. |
|
|
71
|
+
| `createMarketCategory(params)` | Next category id per `PlatformRegistry` (must match `next_category_id`). |
|
|
72
|
+
| `updateMarketCategory(params)` | Rename / toggle active. |
|
|
69
73
|
|
|
70
|
-
|
|
74
|
+
### Market creation
|
|
75
|
+
|
|
76
|
+
| Method | Purpose |
|
|
77
|
+
| --------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- |
|
|
78
|
+
| `createMarket(creator, collateralMint, creatorFeeAccount, params)` | Step 1: market + vault. |
|
|
79
|
+
| `initializeMarketResolverSlots(marketPda, params, opts?, parimutuelStateParams?)` | Resolver PDAs; optional `parimutuelStateParams` appends `initializeParimutuelState` in the same tx. |
|
|
80
|
+
| `initializeMarketOutcomeSlots(marketPda, params)` | `MarketOutcome` labels (complete-set & pari). |
|
|
81
|
+
| `initializeMarketMints(marketPda, marketId)` | Mint 8 outcome SPLs (complete-set only). |
|
|
82
|
+
| `initializeParimutuelState(marketPda, params)` | Standalone pari pool + penalty params (if not bundled with resolvers). |
|
|
83
|
+
| `createMarketFull(creator, collateralMint, creatorFeeAccount, resolverPubkeys, params)` | Runs create → outcomes → resolvers (+ mints **or** pari state in one flow). |
|
|
84
|
+
| `updateParimutuelState(marketPda, params)` | Creator updates early-exit penalty (open pari pool). |
|
|
85
|
+
|
|
86
|
+
**`CreateMarketParams` (pari-mutuel):** optional **`isEarlyWithdrawAllowed`** (default **`true`**). When **`false`**, the program rejects **`parimutuelWithdraw`** with **`EarlyWithdrawNotAllowed`** until close or resolution. Ignored for complete-set markets. Read back on **`fetchMarket(marketPda).isEarlyWithdrawAllowed`**.
|
|
87
|
+
|
|
88
|
+
### Complete-set trading
|
|
89
|
+
|
|
90
|
+
| Method | Purpose |
|
|
91
|
+
| ---------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------ |
|
|
92
|
+
| `mintCompleteSet(user, marketPda, collateralMint, userCollateralAta, platformTreasury, creatorFeeAccount, params, opts?, tokenProgram?)` | Mint full set; creates missing outcome ATAs. |
|
|
93
|
+
| `redeemCompleteSet(user, marketPda, collateralMint, userCollateralAta, params)` | Burn full set for collateral. |
|
|
94
|
+
| `redeemWinning(user, marketPda, collateralMint, userCollateralAta, params)` | After resolution, redeem winning outcome tokens. |
|
|
95
|
+
|
|
96
|
+
### Parimutuel trading
|
|
71
97
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
98
|
+
| Method | Purpose |
|
|
99
|
+
| --------------------------------------- | ------------------------------------------------------- |
|
|
100
|
+
| `parimutuelStake(marketPda, params)` | Stake; signer is **provider wallet** (`user` on-chain). |
|
|
101
|
+
| `parimutuelWithdraw(marketPda, params)` | Early exit (penalty may apply). Errors if `Market.isEarlyWithdrawAllowed` is false. |
|
|
102
|
+
| `parimutuelClaim(marketPda, params)` | Claim after resolution. |
|
|
103
|
+
|
|
104
|
+
### Resolution & lifecycle
|
|
105
|
+
|
|
106
|
+
| Method | Purpose |
|
|
107
|
+
| ----------------------------------------- | --------------------------------------------- |
|
|
108
|
+
| `voteResolution(marketPda, params)` | Resolver vote. |
|
|
109
|
+
| `revokeResolutionVote(marketPda, params)` | Clear vote before changing. |
|
|
110
|
+
| `finalizeResolution(marketPda, params)` | Anyone, once threshold met. |
|
|
111
|
+
| `closeMarketEarly(marketPda, params)` | Creator / config authority before `close_at`. |
|
|
112
|
+
| `voidMarket(marketPda, params)` | Void market. |
|
|
113
|
+
| `abandonMarket(marketPda, params)` | Creator abandons empty market (reclaim rent). |
|
|
114
|
+
|
|
115
|
+
### Discovery & reads
|
|
116
|
+
|
|
117
|
+
| Method | Purpose |
|
|
118
|
+
| ----------------------------------------------------------------- | --------------------------------------------------------------------------------------------- |
|
|
119
|
+
| `fetchGlobalConfig()` | Global config account. |
|
|
120
|
+
| `fetchMarket(marketPda)` | `Market` account. |
|
|
121
|
+
| `fetchAllMarkets(platformId?)` | All markets (optional `memcmp` on `platform_id`); includes outcome labels. |
|
|
122
|
+
| `fetchMarketsByPlatform(platformId)` | Same as `fetchAllMarkets(platformId)`. |
|
|
123
|
+
| `fetchMarketsByCreator(creator)` | Raw rows `{ pubkey, account }[]`, memcmp on creator. |
|
|
124
|
+
| `getUsersMarkets(creator, filters?)` | **`ListedMarket[]`** for creator; optional `platformId` (RPC) + `categoryId` (client filter). |
|
|
125
|
+
| `fetchMarketOutcomeLabels(marketPda, outcomeCount)` | Outcome labels. |
|
|
126
|
+
| `fetchVaultBalance(marketPda)` | Vault balance (bigint base units). |
|
|
127
|
+
| `fetchOutcomeBalance(marketPda, user, outcomeIndex)` | Single outcome token balance (complete-set). |
|
|
128
|
+
| `fetchAllOutcomeBalances(marketPda, user, outcomeCount)` | All outcome balances for user. |
|
|
129
|
+
| `fetchMarketCategory(categoryPda)` | One category. |
|
|
130
|
+
| `fetchAllMarketCategories()` | All categories (sorted). |
|
|
131
|
+
| `fetchResolutionVote(marketPda, resolverIndex)` | Vote PDA or null. |
|
|
132
|
+
| `fetchMarketOutcomesSnapshot(marketPda, outcomeCount)` | Decoded outcomes + tallies. |
|
|
133
|
+
| `fetchOutcomeTallyCounts(marketPda)` | Quick tally array. |
|
|
134
|
+
| `fetchAllowedCollateralMints()` | Allowlist mints. |
|
|
135
|
+
| `fetchUserProfile(wallet)` | User profile or null. |
|
|
136
|
+
| `fetchPlatformProfile(platformId)` | Platform profile or null. |
|
|
137
|
+
| `fetchParimutuelState(marketPda)` | Pari pool state. |
|
|
138
|
+
| `fetchParimutuelPosition(marketPda, user, outcomeIndex)` | Position or null. |
|
|
139
|
+
| `fetchParimutuelActiveStakesBatch(marketPda, user, outcomeCount)` | Active stakes per outcome. |
|
|
140
|
+
| `computeParimutuelOdds(state, outcomeCount)` | Implied probs + payout multipliers. |
|
|
141
|
+
| `fetchResolver(marketPda, index)` | One resolver account. |
|
|
142
|
+
| `fetchAllResolvers(marketPda, numResolvers)` | Initialized resolver slots. |
|
|
143
|
+
|
|
144
|
+
### Profiles
|
|
145
|
+
|
|
146
|
+
| Method | Purpose |
|
|
147
|
+
| ---------------------------------- | ------------------------------------------- |
|
|
148
|
+
| `upsertUserProfile(params)` | Display name / URL. |
|
|
149
|
+
| `closeUserProfile()` | Close caller’s profile. |
|
|
150
|
+
| `verifyUserProfile(params)` | Verifier marks verified. |
|
|
151
|
+
| `upsertPlatformProfile(params)` | Platform profile (scoped by `platform_id`). |
|
|
152
|
+
| `closePlatformProfile(platformId)` | Close profile. |
|
|
153
|
+
| `verifyPlatformProfile(params)` | Verify platform profile. |
|
|
76
154
|
|
|
77
155
|
---
|
|
78
156
|
|
|
79
|
-
##
|
|
157
|
+
## Examples
|
|
80
158
|
|
|
81
|
-
###
|
|
159
|
+
### Global config (first deploy)
|
|
82
160
|
|
|
83
161
|
```ts
|
|
84
|
-
import {
|
|
162
|
+
import { PublicKey } from "@solana/web3.js";
|
|
163
|
+
import BN from "bn.js";
|
|
164
|
+
|
|
165
|
+
await client.initializeConfig({
|
|
166
|
+
// System program / “none” placeholder — use a real secondary authority pubkey in production
|
|
167
|
+
secondaryAuthority: new PublicKey("11111111111111111111111111111111"),
|
|
168
|
+
depositPlatformFeeBps: 100,
|
|
169
|
+
platformTreasuryWallet: treasuryPubkey,
|
|
170
|
+
platformFeeLamports: new BN(357_000),
|
|
171
|
+
parimutuelWithdrawPlatformFeeBps: 50,
|
|
172
|
+
});
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### Register platform & category
|
|
176
|
+
|
|
177
|
+
```ts
|
|
178
|
+
const { platformId } = await client.registerPlatform({
|
|
179
|
+
profileAuthority: profileSignerPubkey,
|
|
180
|
+
});
|
|
85
181
|
|
|
86
|
-
|
|
182
|
+
await client.createMarketCategory({
|
|
183
|
+
platformId,
|
|
184
|
+
name: "Politics",
|
|
185
|
+
});
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### Create a market (manual steps, complete-set)
|
|
189
|
+
|
|
190
|
+
```ts
|
|
191
|
+
import BN from "bn.js";
|
|
192
|
+
|
|
193
|
+
const marketId = new BN(Date.now());
|
|
87
194
|
const { marketPda } = await client.createMarket(
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
195
|
+
creatorPubkey,
|
|
196
|
+
collateralMint,
|
|
197
|
+
creatorFeeAta,
|
|
91
198
|
{
|
|
92
199
|
marketId,
|
|
93
200
|
outcomeCount: 2,
|
|
94
201
|
resolutionThreshold: 1,
|
|
95
|
-
closeAt: new BN(Math.floor(Date.now() / 1000) + 86400),
|
|
202
|
+
closeAt: new BN(Math.floor(Date.now() / 1000) + 86400),
|
|
96
203
|
creatorFeeBps: 50,
|
|
97
|
-
depositPlatformFeeBps: 0,
|
|
204
|
+
depositPlatformFeeBps: 0,
|
|
98
205
|
numResolvers: 1,
|
|
206
|
+
maxOutcomeInvestment: new BN(0),
|
|
99
207
|
title: "Will it rain tomorrow?",
|
|
100
|
-
marketType: "completeSet",
|
|
101
|
-
// Optional: scoped market (omit or use new BN(0) for unscoped / uncategorized)
|
|
208
|
+
marketType: "completeSet",
|
|
102
209
|
platformId: new BN(0),
|
|
103
210
|
categoryId: new BN(0),
|
|
104
211
|
},
|
|
105
212
|
);
|
|
106
213
|
|
|
107
|
-
|
|
214
|
+
await client.initializeMarketOutcomeSlots(marketPda, {
|
|
215
|
+
marketId,
|
|
216
|
+
labels: ["Yes", "No"],
|
|
217
|
+
});
|
|
108
218
|
await client.initializeMarketResolverSlots(marketPda, {
|
|
109
219
|
marketId,
|
|
110
220
|
resolverPubkeys: [resolverPubkey],
|
|
@@ -112,98 +222,192 @@ await client.initializeMarketResolverSlots(marketPda, {
|
|
|
112
222
|
await client.initializeMarketMints(marketPda, marketId);
|
|
113
223
|
```
|
|
114
224
|
|
|
115
|
-
###
|
|
225
|
+
### Create market in one call (`createMarketFull`)
|
|
226
|
+
|
|
227
|
+
Complete-set (mints outcome tokens):
|
|
116
228
|
|
|
117
229
|
```ts
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
user,
|
|
121
|
-
marketPda,
|
|
230
|
+
const marketPda = await client.createMarketFull(
|
|
231
|
+
creatorPubkey,
|
|
122
232
|
collateralMint,
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
233
|
+
creatorFeeAta,
|
|
234
|
+
[resolverPubkey],
|
|
235
|
+
{
|
|
236
|
+
marketId,
|
|
237
|
+
outcomeCount: 2,
|
|
238
|
+
resolutionThreshold: 1,
|
|
239
|
+
closeAt: new BN(Math.floor(Date.now() / 1000) + 86400),
|
|
240
|
+
creatorFeeBps: 50,
|
|
241
|
+
depositPlatformFeeBps: 0,
|
|
242
|
+
numResolvers: 1,
|
|
243
|
+
maxOutcomeInvestment: new BN(0),
|
|
244
|
+
title: "Two-outcome market",
|
|
245
|
+
marketType: "completeSet",
|
|
246
|
+
outcomeLabels: ["Yes", "No"],
|
|
247
|
+
},
|
|
127
248
|
);
|
|
249
|
+
```
|
|
128
250
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
251
|
+
Parimutuel (resolver tx also initializes pari state; optional `parimutuelInit` overrides defaults):
|
|
252
|
+
|
|
253
|
+
```ts
|
|
254
|
+
const marketPda = await client.createMarketFull(
|
|
255
|
+
creatorPubkey,
|
|
133
256
|
collateralMint,
|
|
134
|
-
|
|
135
|
-
|
|
257
|
+
creatorFeeAta,
|
|
258
|
+
[resolverPubkey],
|
|
259
|
+
{
|
|
260
|
+
marketId,
|
|
261
|
+
outcomeCount: 2,
|
|
262
|
+
resolutionThreshold: 1,
|
|
263
|
+
closeAt: new BN(Math.floor(Date.now() / 1000) + 86400),
|
|
264
|
+
creatorFeeBps: 50,
|
|
265
|
+
depositPlatformFeeBps: 0,
|
|
266
|
+
numResolvers: 1,
|
|
267
|
+
maxOutcomeInvestment: new BN(0),
|
|
268
|
+
title: "Pari pool",
|
|
269
|
+
marketType: "parimutuel",
|
|
270
|
+
outcomeLabels: ["A", "B"],
|
|
271
|
+
// Optional — default true. Set false to lock stakes until close/resolution (no early parimutuelWithdraw).
|
|
272
|
+
isEarlyWithdrawAllowed: true,
|
|
273
|
+
parimutuelInit: {
|
|
274
|
+
earlyWithdrawPenaltyBps: 500,
|
|
275
|
+
penaltyKeptInPoolBps: 8000,
|
|
276
|
+
},
|
|
277
|
+
},
|
|
136
278
|
);
|
|
137
|
-
|
|
138
|
-
// After resolution — redeem the winning outcome tokens
|
|
139
|
-
await client.redeemWinning(user, marketPda, collateralMint, userCollateralAta, {
|
|
140
|
-
marketId,
|
|
141
|
-
amount: winningBalance,
|
|
142
|
-
});
|
|
143
279
|
```
|
|
144
280
|
|
|
145
|
-
###
|
|
281
|
+
### Complete-set trading
|
|
146
282
|
|
|
147
283
|
```ts
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
284
|
+
const treasury = (await client.fetchGlobalConfig()).platformTreasury;
|
|
285
|
+
|
|
286
|
+
await client.mintCompleteSet(
|
|
287
|
+
userPubkey,
|
|
151
288
|
marketPda,
|
|
152
289
|
collateralMint,
|
|
153
290
|
userCollateralAta,
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
{ marketId,
|
|
291
|
+
treasury,
|
|
292
|
+
creatorFeeAta,
|
|
293
|
+
{ marketId, amount: new BN(1_000_000) },
|
|
157
294
|
);
|
|
158
295
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
user,
|
|
296
|
+
await client.redeemCompleteSet(
|
|
297
|
+
userPubkey,
|
|
162
298
|
marketPda,
|
|
163
299
|
collateralMint,
|
|
164
300
|
userCollateralAta,
|
|
165
|
-
{ marketId
|
|
301
|
+
{ marketId },
|
|
166
302
|
);
|
|
167
303
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
user,
|
|
304
|
+
await client.redeemWinning(
|
|
305
|
+
userPubkey,
|
|
171
306
|
marketPda,
|
|
172
307
|
collateralMint,
|
|
173
308
|
userCollateralAta,
|
|
174
|
-
{
|
|
309
|
+
{
|
|
310
|
+
marketId,
|
|
311
|
+
amount: winningAmountBn,
|
|
312
|
+
},
|
|
175
313
|
);
|
|
176
314
|
```
|
|
177
315
|
|
|
316
|
+
### Parimutuel trading
|
|
317
|
+
|
|
318
|
+
Signer is always the **connected wallet** (no `user` first argument):
|
|
319
|
+
|
|
320
|
+
```ts
|
|
321
|
+
await client.parimutuelStake(marketPda, {
|
|
322
|
+
marketId,
|
|
323
|
+
outcomeIndex: 0,
|
|
324
|
+
amount: new BN(500_000),
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
await client.parimutuelWithdraw(marketPda, {
|
|
328
|
+
marketId,
|
|
329
|
+
outcomeIndex: 0,
|
|
330
|
+
amount: new BN(500_000),
|
|
331
|
+
});
|
|
332
|
+
// If create used isEarlyWithdrawAllowed: false, parimutuelWithdraw throws (Anchor: EarlyWithdrawNotAllowed).
|
|
333
|
+
|
|
334
|
+
await client.parimutuelClaim(marketPda, {
|
|
335
|
+
marketId,
|
|
336
|
+
outcomeIndex: 0,
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
const state = await client.fetchParimutuelState(marketPda);
|
|
340
|
+
const odds = client.computeParimutuelOdds(state, 2);
|
|
341
|
+
```
|
|
342
|
+
|
|
178
343
|
### Resolution
|
|
179
344
|
|
|
180
345
|
```ts
|
|
181
|
-
// Resolver votes on the winning outcome
|
|
182
346
|
await client.voteResolution(marketPda, {
|
|
183
347
|
marketId,
|
|
184
348
|
resolverIndex: 0,
|
|
185
|
-
outcomeIndex: 1,
|
|
349
|
+
outcomeIndex: 1,
|
|
186
350
|
});
|
|
187
351
|
|
|
188
|
-
// Once the threshold is met, anyone can finalize
|
|
189
352
|
await client.finalizeResolution(marketPda, { marketId });
|
|
190
353
|
```
|
|
191
354
|
|
|
192
|
-
###
|
|
355
|
+
### Discovery
|
|
356
|
+
|
|
357
|
+
```ts
|
|
358
|
+
// Every market (heavy on RPC)
|
|
359
|
+
const all = await client.fetchAllMarkets();
|
|
360
|
+
|
|
361
|
+
// By platform (memcmp)
|
|
362
|
+
const byPlatform = await client.fetchAllMarkets(new BN(1));
|
|
363
|
+
|
|
364
|
+
// Markets created by a wallet — full rows with labels + filters
|
|
365
|
+
const mine = await client.getUsersMarkets(creatorPubkey, {
|
|
366
|
+
platformId: new BN(1), // optional RPC filter
|
|
367
|
+
categoryId: 2, // optional; applied after decode
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
// Raw accounts only (no labels)
|
|
371
|
+
const raw = await client.fetchMarketsByCreator(creatorPubkey);
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
### User profile
|
|
193
375
|
|
|
194
376
|
```ts
|
|
195
|
-
|
|
196
|
-
|
|
377
|
+
await client.upsertUserProfile({
|
|
378
|
+
displayName: "Alice",
|
|
379
|
+
url: "https://example.com",
|
|
380
|
+
});
|
|
197
381
|
|
|
198
|
-
const
|
|
382
|
+
const profile = await client.fetchUserProfile(wallet.publicKey);
|
|
199
383
|
```
|
|
200
384
|
|
|
385
|
+
---
|
|
386
|
+
|
|
387
|
+
## Platforms and categories
|
|
388
|
+
|
|
389
|
+
On-chain, **`platform_id`** is **`u32`** and **`category_id`** is **`u8`** in `CreateMarketArgs` (not pubkeys).
|
|
390
|
+
|
|
391
|
+
1. **`register_platform`** — assigns the next id from `GlobalConfig.next_platform_id`; PDA `["platform", platform_id le u32]`.
|
|
392
|
+
2. **`create_market_category`** — `category_id` must equal `PlatformRegistry.next_category_id` before bump; PDA `["market-category", platform_id, category_id]`.
|
|
393
|
+
3. **`create_market`** — if `platform_id == 0` then `category_id` must be `0`. If `platform_id > 0`, pass `platform_registry`; if `category_id > 0`, pass `market_category`.
|
|
394
|
+
|
|
395
|
+
Use **`derivePlatformRegistry`**, **`derivePlatformProfile`**, **`deriveMarketCategory`** when building instructions manually.
|
|
396
|
+
|
|
397
|
+
## Market types
|
|
398
|
+
|
|
399
|
+
Use `marketType: 'parimutuel'` or `'completeSet'` at creation; the choice is permanent.
|
|
400
|
+
|
|
401
|
+
- **Parimutuel** — pooled stakes, no outcome SPLs; good default for prediction apps. Optional **`isEarlyWithdrawAllowed`** on create (default **allowed**); when disabled, users cannot call **`parimutuelWithdraw`** early.
|
|
402
|
+
- **Complete-set** — outcome SPL tokens; you still need external liquidity for single-leg trading.
|
|
403
|
+
|
|
201
404
|
## PDA helpers
|
|
202
405
|
|
|
203
|
-
|
|
406
|
+
From `@vercora-protocol/sdk`:
|
|
204
407
|
|
|
205
408
|
```ts
|
|
206
409
|
import {
|
|
410
|
+
PROGRAM_ID,
|
|
207
411
|
deriveGlobalConfig,
|
|
208
412
|
deriveAllowedMint,
|
|
209
413
|
deriveMarket,
|
|
@@ -213,24 +417,49 @@ import {
|
|
|
213
417
|
deriveResolver,
|
|
214
418
|
deriveAllResolvers,
|
|
215
419
|
deriveResolutionVote,
|
|
420
|
+
deriveMarketOutcome,
|
|
421
|
+
deriveAllMarketOutcomes,
|
|
422
|
+
deriveParimutuelState,
|
|
423
|
+
deriveParimutuelPosition,
|
|
216
424
|
deriveUserProfile,
|
|
217
425
|
derivePlatformRegistry,
|
|
218
426
|
derivePlatformProfile,
|
|
219
427
|
deriveMarketCategory,
|
|
428
|
+
bnLike,
|
|
429
|
+
bnToU32,
|
|
430
|
+
bnToU8,
|
|
220
431
|
} from "@vercora-protocol/sdk";
|
|
221
432
|
|
|
222
|
-
const marketPda = deriveMarket(
|
|
223
|
-
const vaultPda = deriveVault(
|
|
224
|
-
const [mint0] = deriveAllOutcomeMints(program.programId, marketPda, 2);
|
|
433
|
+
const marketPda = deriveMarket(PROGRAM_ID, creatorPubkey, marketId);
|
|
434
|
+
const vaultPda = deriveVault(PROGRAM_ID, marketPda);
|
|
225
435
|
```
|
|
226
436
|
|
|
227
|
-
|
|
437
|
+
Offsets **`MARKET_ACCOUNT_CREATOR_MEMCMP_OFFSET`** and **`MARKET_ACCOUNT_PLATFORM_ID_MEMCMP_OFFSET`** are exported for custom `getProgramAccounts` filters.
|
|
438
|
+
|
|
439
|
+
## `marketUi` helpers
|
|
440
|
+
|
|
441
|
+
```ts
|
|
442
|
+
import {
|
|
443
|
+
getMarketLifecycleStatus,
|
|
444
|
+
formatTimeLeft,
|
|
445
|
+
listedMarketFeedTag,
|
|
446
|
+
} from "@vercora-protocol/sdk";
|
|
228
447
|
|
|
229
|
-
|
|
448
|
+
const status = getMarketLifecycleStatus({
|
|
449
|
+
isVoided: false,
|
|
450
|
+
isClosedEarly: false,
|
|
451
|
+
winningOutcomeIndex: null,
|
|
452
|
+
closeAt: ts,
|
|
453
|
+
});
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
## TypeScript types
|
|
230
457
|
|
|
231
458
|
```ts
|
|
232
459
|
import type {
|
|
233
460
|
CreateMarketParams,
|
|
461
|
+
ListedMarket,
|
|
462
|
+
GetUsersMarketsFilters,
|
|
234
463
|
MarketAccount,
|
|
235
464
|
ParimutuelStateAccount,
|
|
236
465
|
ParimutuelOdds,
|
|
@@ -241,20 +470,18 @@ import type {
|
|
|
241
470
|
|
|
242
471
|
## AI agent integration
|
|
243
472
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
-
|
|
250
|
-
-
|
|
251
|
-
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
4. **Safety**: verify signer role, derive PDAs with helpers, handle missing ATAs, return tx signatures.
|
|
473
|
+
1. **Bootstrap**: `Connection` → `AnchorProvider` → `Program<Vercora>` from `IDL` → `PredictionMarketClient`.
|
|
474
|
+
2. **Branch**: `fetchMarket` → `market.marketType` (`completeSet` vs `parimutuel`).
|
|
475
|
+
3. **Flows**:
|
|
476
|
+
- Optional: `registerPlatform` → `createMarketCategory` → `createMarket` with ids.
|
|
477
|
+
- Create: `createMarketFull` **or** `createMarket` + resolver / outcome / mint **or** pari init.
|
|
478
|
+
- Complete-set: `mintCompleteSet` → `redeemCompleteSet` → `redeemWinning`.
|
|
479
|
+
- Parimutuel: `parimutuelStake` → optional `parimutuelWithdraw` (if `isEarlyWithdrawAllowed`) → `parimutuelClaim`.
|
|
480
|
+
- Resolution: `voteResolution` → `finalizeResolution`.
|
|
481
|
+
4. **Discovery**: `fetchAllMarkets`, `getUsersMarkets`, `fetchMarketsByCreator`.
|
|
482
|
+
5. **Safety**: verify signers, PDAs, ATAs, and RPC limits on `getProgramAccounts`.
|
|
255
483
|
|
|
256
484
|
## Links
|
|
257
485
|
|
|
258
|
-
- [GitHub source](https://github.com/vercora/vercora-anchor)
|
|
259
486
|
- [Vercora app](https://vercora.xyz)
|
|
260
487
|
- [npm package](https://www.npmjs.com/package/@vercora-protocol/sdk)
|
package/dist/client.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import * as anchor from '@coral-xyz/anchor';
|
|
|
2
2
|
import { Program, BN } from '@coral-xyz/anchor';
|
|
3
3
|
import { Connection, PublicKey } from '@solana/web3.js';
|
|
4
4
|
import type { Vercora } from './generated/vercora';
|
|
5
|
-
import type { CreateMarketParams, InitializeParimutuelStateParams, ParimutuelStakeParams, ParimutuelWithdrawParams, ParimutuelClaimParams, InitializeConfigParams, UpdateConfigParams, InitializeMarketResolverSlotsParams, InitializeMarketOutcomeSlotsParams, MintCompleteSetParams, RedeemCompleteSetParams, VoteResolutionParams, FinalizeResolutionParams, RevokeResolutionVoteParams, RedeemWinningParams, CloseMarketEarlyParams, VoidMarketParams, AbandonMarketParams, GlobalConfigAccount, MarketAccount, ResolverAccount, UpsertUserProfileParams, VerifyUserProfileParams, UserProfileAccount, UpsertPlatformProfileParams, VerifyPlatformProfileParams, PlatformProfileAccount, ParimutuelStateAccount, ParimutuelPositionAccount, ParimutuelOdds, MarketCategoryAccount, CreateMarketCategoryParams, UpdateMarketCategoryParams, RegisterPlatformParams, UpdateParimutuelStateParams, ResolutionVoteAccount, ListedMarket } from './types';
|
|
5
|
+
import type { CreateMarketParams, InitializeParimutuelStateParams, ParimutuelStakeParams, ParimutuelWithdrawParams, ParimutuelClaimParams, InitializeConfigParams, UpdateConfigParams, InitializeMarketResolverSlotsParams, InitializeMarketOutcomeSlotsParams, MintCompleteSetParams, RedeemCompleteSetParams, VoteResolutionParams, FinalizeResolutionParams, RevokeResolutionVoteParams, RedeemWinningParams, CloseMarketEarlyParams, VoidMarketParams, AbandonMarketParams, GlobalConfigAccount, MarketAccount, ResolverAccount, UpsertUserProfileParams, VerifyUserProfileParams, UserProfileAccount, UpsertPlatformProfileParams, VerifyPlatformProfileParams, PlatformProfileAccount, ParimutuelStateAccount, ParimutuelPositionAccount, ParimutuelOdds, MarketCategoryAccount, CreateMarketCategoryParams, UpdateMarketCategoryParams, RegisterPlatformParams, UpdateParimutuelStateParams, ResolutionVoteAccount, ListedMarket, GetUsersMarketsFilters } from './types';
|
|
6
6
|
export declare class PredictionMarketClient {
|
|
7
7
|
readonly program: Program<Vercora>;
|
|
8
8
|
readonly connection: Connection;
|
|
@@ -56,6 +56,9 @@ export declare class PredictionMarketClient {
|
|
|
56
56
|
/**
|
|
57
57
|
* Step 1 — Create Market + Vault.
|
|
58
58
|
* Returns the market PDA and the transaction signature.
|
|
59
|
+
*
|
|
60
|
+
* For pari-mutuel markets, `params.isEarlyWithdrawAllowed` (default `true`) is stored on-chain.
|
|
61
|
+
* When `false`, `parimutuelWithdraw` fails until close/resolution (see `PredictionMarketError::EarlyWithdrawNotAllowed`).
|
|
59
62
|
*/
|
|
60
63
|
createMarket(creator: PublicKey, collateralMint: PublicKey, creatorFeeAccount: PublicKey, params: CreateMarketParams, opts?: anchor.web3.ConfirmOptions): Promise<{
|
|
61
64
|
marketPda: PublicKey;
|
|
@@ -79,6 +82,8 @@ export declare class PredictionMarketClient {
|
|
|
79
82
|
/**
|
|
80
83
|
* Convenience: run all 3 market creation steps in sequence.
|
|
81
84
|
* Returns the market PDA.
|
|
85
|
+
*
|
|
86
|
+
* Pari-mutuel: passes `params.isEarlyWithdrawAllowed` through `createMarket` (default allows early withdraw).
|
|
82
87
|
*/
|
|
83
88
|
createMarketFull(creator: PublicKey, collateralMint: PublicKey, creatorFeeAccount: PublicKey,
|
|
84
89
|
/** Length must equal `params.numResolvers` (typically the first N of an 8-slot UI). */
|
|
@@ -91,6 +96,11 @@ export declare class PredictionMarketClient {
|
|
|
91
96
|
*/
|
|
92
97
|
updateParimutuelState(marketPda: PublicKey, params: UpdateParimutuelStateParams, opts?: anchor.web3.ConfirmOptions): Promise<string>;
|
|
93
98
|
parimutuelStake(marketPda: PublicKey, params: ParimutuelStakeParams, opts?: anchor.web3.ConfirmOptions): Promise<string>;
|
|
99
|
+
/**
|
|
100
|
+
* Reduce stake before `close_at` / resolution (early exit). Penalties and platform fees may apply.
|
|
101
|
+
* Fails with Anchor error **`EarlyWithdrawNotAllowed`** when `fetchMarket(marketPda).isEarlyWithdrawAllowed === false`
|
|
102
|
+
* (set at `createMarket` / `createMarketFull` via `CreateMarketParams.isEarlyWithdrawAllowed`).
|
|
103
|
+
*/
|
|
94
104
|
parimutuelWithdraw(marketPda: PublicKey, params: ParimutuelWithdrawParams, opts?: anchor.web3.ConfirmOptions): Promise<string>;
|
|
95
105
|
parimutuelClaim(marketPda: PublicKey, params: ParimutuelClaimParams, opts?: anchor.web3.ConfirmOptions): Promise<string>;
|
|
96
106
|
/**
|
|
@@ -143,6 +153,10 @@ export declare class PredictionMarketClient {
|
|
|
143
153
|
fetchGlobalConfig(): Promise<GlobalConfigAccount>;
|
|
144
154
|
fetchMarket(market: PublicKey): Promise<MarketAccount>;
|
|
145
155
|
private bnFieldToListedString;
|
|
156
|
+
/**
|
|
157
|
+
* Map raw `Market` account rows to {@link ListedMarket} (including outcome labels).
|
|
158
|
+
*/
|
|
159
|
+
private buildListedMarketsFromRawRows;
|
|
146
160
|
/**
|
|
147
161
|
* List on-chain `Market` accounts, with outcome labels fetched per market.
|
|
148
162
|
* Uses Anchor `program.account.market.all()`; when `platformId` is set, uses RPC `memcmp` on
|
|
@@ -163,6 +177,14 @@ export declare class PredictionMarketClient {
|
|
|
163
177
|
pubkey: PublicKey;
|
|
164
178
|
account: MarketAccount;
|
|
165
179
|
}[]>;
|
|
180
|
+
/**
|
|
181
|
+
* Markets created by `creator`, as {@link ListedMarket} rows (with outcome labels).
|
|
182
|
+
*
|
|
183
|
+
* Uses RPC `memcmp` on `creator` and optionally on `platform_id` (when `filters.platformId` is set).
|
|
184
|
+
* When `filters.categoryId` is set, results are narrowed after decode (see {@link GetUsersMarketsFilters}).
|
|
185
|
+
* Sorted by `market_id` ascending.
|
|
186
|
+
*/
|
|
187
|
+
getUsersMarkets(creator: PublicKey, filters?: GetUsersMarketsFilters): Promise<ListedMarket[]>;
|
|
166
188
|
/**
|
|
167
189
|
* Read `MarketOutcome.label` for each active outcome index (parallel fetches).
|
|
168
190
|
* Missing accounts yield `Outcome {i+1}` placeholders.
|