@vercora-protocol/sdk 0.4.2 → 0.5.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/CHANGELOG.md CHANGED
@@ -5,6 +5,13 @@ All notable changes to `@vercora-protocol/sdk` are documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
7
 
8
+ ## [0.5.0](https://github.com/vercora/vercora-anchor/compare/v0.4.2...v0.5.0) (2026-05-01)
9
+
10
+
11
+ ### Features
12
+
13
+ * **all:** update brand position and landing page ([4e6f1a9](https://github.com/vercora/vercora-anchor/commit/4e6f1a9a351f5de532d2414190969575b5345850))
14
+
8
15
  ### [0.4.2](https://github.com/vercora/vercora-anchor/compare/v0.4.1...v0.4.2) (2026-04-24)
9
16
 
10
17
 
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @vercora-protocol/sdk
2
2
 
3
- TypeScript SDK for the [Vercora](https://vercora.xyz) prediction market protocol on Solana (Anchor).
3
+ TypeScript SDK for **[Vercora Protocol](https://vercora.xyz)** on Solana (Anchor). **Vercora** is **token utility infrastructure** for LST and utility-token programs; **this package** documents the **outcome markets** program today (`PredictionMarketClient`, bundled IDL). A second product lane (issuer upside and diversification into broader assets) is on the **roadmap** and is **not** exposed in this SDK yet.
4
4
 
5
5
  ## Install
6
6
 
@@ -10,7 +10,7 @@ npm install @vercora-protocol/sdk
10
10
  yarn add @vercora-protocol/sdk
11
11
  ```
12
12
 
13
- **Peer dependencies** (install alongside keep versions aligned; see [IDL, account metas, and peer deps](#idl-account-metas-and-peer-deps-browser--raw-anchor) for SendTransactionError notes):
13
+ **Peer dependencies** (install alongside, keep versions aligned; see [IDL, account metas, and peer deps](#idl-account-metas-and-peer-deps-browser--raw-anchor) for SendTransactionError notes):
14
14
 
15
15
  ```bash
16
16
  npm install @coral-xyz/anchor @solana/web3.js @solana/spl-token bn.js
@@ -30,7 +30,7 @@ const connection = new Connection(clusterApiUrl("devnet"));
30
30
  const provider = new anchor.AnchorProvider(connection, wallet, {});
31
31
  anchor.setProvider(provider);
32
32
 
33
- // Bundled IDL program id is embedded in `IDL.address` (`PROGRAM_ID` matches it)
33
+ // Bundled IDL, program id is embedded in `IDL.address` (`PROGRAM_ID` matches it)
34
34
  const program = new anchor.Program<Vercora>(IDL, provider);
35
35
  const client = new PredictionMarketClient(program);
36
36
  ```
@@ -63,19 +63,19 @@ For **`claim_resolver_stake`** and **`resolve_refute`**, the program may transfe
63
63
 
64
64
  ### Served IDL vs package IDL (drift and disputerCollateral not provided)
65
65
 
66
- If the app loads IDL from **`fetchIdl()`**, a static **`public/idl/vercora.json`**, or a CDN URL, it can **drift** from `node_modules/@vercora-protocol/sdk/dist/idl/vercora.json`. Anchor then builds **wrong or incomplete account lists** while `PredictionMarketClient` assumes the bundled layout e.g. **`Account 'disputerCollateral' not provided`** when metas omit accounts present in the current IDL.
66
+ If the app loads IDL from **`fetchIdl()`**, a static **`public/idl/vercora.json`**, or a CDN URL, it can **drift** from `node_modules/@vercora-protocol/sdk/dist/idl/vercora.json`. Anchor then builds **wrong or incomplete account lists** while `PredictionMarketClient` assumes the bundled layout, e.g. **`Account 'disputerCollateral' not provided`** when metas omit accounts present in the current IDL.
67
67
 
68
68
  **Recommendation:** Prefer **`import { IDL } from '@vercora-protocol/sdk'`** (or copy **`dist/idl/vercora.json`** from the exact npm version) so the Program client and high-level client agree. If you must hot-reload IDL from HTTP, **version and cache-bust** the URL to match the deployed program + SDK release.
69
69
 
70
70
  ### Disputer collateral on resolve_refute
71
71
 
72
- **`disputer_collateral`** is the **refuter’s collateral SPL ATA** for the market mint the same role as **`refuter_collateral`** on **`open_refute`**. It is **always** in the **`resolve_refute`** account list: on **dismiss** the handler does not transfer the refute bond into it, but the account must still be present and valid (mint + **owner = `ResolutionState.disputer`**). On **accept**, the bond is refunded into this ATA.
72
+ **`disputer_collateral`** is the **refuter’s collateral SPL ATA** for the market mint, the same role as **`refuter_collateral`** on **`open_refute`**. It is **always** in the **`resolve_refute`** account list: on **dismiss** the handler does not transfer the refute bond into it, but the account must still be present and valid (mint + **owner = `ResolutionState.disputer`**). On **accept**, the bond is refunded into this ATA.
73
73
 
74
74
  It is **not** the market trading vault, pari pool vault, or treasury ATA.
75
75
 
76
76
  ### Who may sign resolve_refute (vs market resolvers)
77
77
 
78
- **Signers:** **`GlobalConfig`** **primary** or **secondary** authority, **or** **`PlatformRegistry.profile_authority`** (platform operator). These are **config / registry** keys **not** the per-market **`voteResolution`** resolver wallets.
78
+ **Signers:** **`GlobalConfig`** **primary** or **secondary** authority, **or** **`PlatformRegistry.profile_authority`** (platform operator). These are **config / registry** keys, **not** the per-market **`voteResolution`** resolver wallets.
79
79
 
80
80
  **`GlobalConfig.dispute_resolution_authority`** (if still present in older docs) is **legacy / unused** for **`resolve_refute`** authorization; do not assume market resolver PDAs can sign it.
81
81
 
@@ -120,11 +120,11 @@ Public properties: **`program`**, **`connection`**, **`globalConfig`** (PDA).
120
120
  | `createMarketFull(creator, collateralMint, creatorFeeAccount, resolverPubkeys, params)` | Runs create → outcomes → resolvers (+ mints **or** pari state in one flow). |
121
121
  | `updateParimutuelState(marketPda, params)` | Creator updates penalty split, **`isEarlyWithdrawAllowed`**, **`maxWalletOutcomeInvestment`**, and **`isWalletOutcomeStakeExact`** (open pari pool). |
122
122
 
123
- **`CreateMarketParams`:** requires **`platformId`** (**`> 0`**, BN) with a registered platform + **`upsertPlatformProfile`** (global config authority; resolver stake, challenge window, and refute bond are set on the profile not per market). **`CreateMarketParams` (pari-mutuel):** optional **`isEarlyWithdrawAllowed`** (default **`true`**). Optional **`maxWalletOutcomeInvestment`** (`BN`, **`0`** = unlimited per-wallet per-outcome net stake cap in collateral base units). Optional **`isWalletOutcomeStakeExact`**: when **`true`** (parimutuel only), each stake must bring the wallet’s net on that outcome to **exactly** `maxWalletOutcomeInvestment`; requires **`maxWalletOutcomeInvestment > 0`**. Setting exact mode on a complete-set market fails with **`InvalidWalletOutcomeStakeExactConfig`**. Ignored for complete-set markets otherwise.
123
+ **`CreateMarketParams`:** requires **`platformId`** (**`> 0`**, BN) with a registered platform + **`upsertPlatformProfile`** (global config authority; resolver stake, challenge window, and refute bond are set on the profile, not per market). **`CreateMarketParams` (pari-mutuel):** optional **`isEarlyWithdrawAllowed`** (default **`true`**). Optional **`maxWalletOutcomeInvestment`** (`BN`, **`0`** = unlimited per-wallet per-outcome net stake cap in collateral base units). Optional **`isWalletOutcomeStakeExact`**: when **`true`** (parimutuel only), each stake must bring the wallet’s net on that outcome to **exactly** `maxWalletOutcomeInvestment`; requires **`maxWalletOutcomeInvestment > 0`**. Setting exact mode on a complete-set market fails with **`InvalidWalletOutcomeStakeExactConfig`**. Ignored for complete-set markets otherwise.
124
124
 
125
- **`UpdateParimutuelStateParams`:** every call writes **all** fields pass **current** values from **`fetchMarket`** / **`fetchParimutuelState`** for anything you are not changing. Includes **`earlyWithdrawPenaltyBps`**, **`penaltyKeptInPoolBps`**, **`isEarlyWithdrawAllowed`**, **`maxWalletOutcomeInvestment`**, **`isWalletOutcomeStakeExact`**. If **`isWalletOutcomeStakeExact`** is **`true`**, **`maxWalletOutcomeInvestment`** must be **> 0** (same rule as create). Use this to tighten or relax per-wallet caps and to toggle exact vs ceiling mode **after** launch (market must still be open and not resolved/voided).
125
+ **`UpdateParimutuelStateParams`:** every call writes **all** fields, pass **current** values from **`fetchMarket`** / **`fetchParimutuelState`** for anything you are not changing. Includes **`earlyWithdrawPenaltyBps`**, **`penaltyKeptInPoolBps`**, **`isEarlyWithdrawAllowed`**, **`maxWalletOutcomeInvestment`**, **`isWalletOutcomeStakeExact`**. If **`isWalletOutcomeStakeExact`** is **`true`**, **`maxWalletOutcomeInvestment`** must be **> 0** (same rule as create). Use this to tighten or relax per-wallet caps and to toggle exact vs ceiling mode **after** launch (market must still be open and not resolved/voided).
126
126
 
127
- When **`isEarlyWithdrawAllowed`** is **`false`**, early **`parimutuelWithdraw`** fails with **`EarlyWithdrawNotAllowed`** until close or resolution **(voided markets are exempt full net-stake refunds, no penalty fees).** Read **`fetchMarket(marketPda)`** for **`isEarlyWithdrawAllowed`**, **`maxWalletOutcomeInvestment`**, **`isWalletOutcomeStakeExact`**.
127
+ When **`isEarlyWithdrawAllowed`** is **`false`**, early **`parimutuelWithdraw`** fails with **`EarlyWithdrawNotAllowed`** until close or resolution **(voided markets are exempt, full net-stake refunds, no penalty fees).** Read **`fetchMarket(marketPda)`** for **`isEarlyWithdrawAllowed`**, **`maxWalletOutcomeInvestment`**, **`isWalletOutcomeStakeExact`**.
128
128
 
129
129
  ### Complete-set trading
130
130
 
@@ -148,18 +148,18 @@ When **`isEarlyWithdrawAllowed`** is **`false`**, early **`parimutuelWithdraw`**
148
148
  | ----------------------------------------- | --------------------------------------------- |
149
149
  | `voteResolution(marketPda, params)` | Resolver vote; may escrow **resolver stake** to the market’s resolver stake vault (see platform policy). |
150
150
  | `revokeResolutionVote(marketPda, params)` | Clear vote before changing (blocked once a proposal exists). |
151
- | `finalizeResolution(marketPda, params)` | When M-of-N agree on one outcome, **proposes** that outcome sets `ResolutionState.proposed_outcome` + `proposal_ts`; does **not** set `Market.winning_outcome_index` yet. |
151
+ | `finalizeResolution(marketPda, params)` | When M-of-N agree on one outcome, **proposes** that outcome, sets `ResolutionState.proposed_outcome` + `proposal_ts`; does **not** set `Market.winning_outcome_index` yet. |
152
152
  | `confirmResolution(marketPda, params)` | After the **challenge window** elapses with **no open dispute**, anyone can call this to set **`Market.winning_outcome_index`** (final approval / settlement). |
153
153
  | `openRefute(marketPda, params)` | During the challenge window: post a **refute bond** and name an alternative winning outcome (dispute). |
154
154
  | `resolveRefute(marketPda, params)` | `params.accept === false`: slash refute bond to treasury. `accept === true`: refund bond to refuter and set **`winning_outcome_index`** to disputed outcome (no **`confirmResolution`**). **Signer (not market resolvers):** global **primary or secondary** authority, or platform **`profileAuthority`**. Optional **`params.disputerCollateral`** defaults to the refuter’s ATA derived from **`ResolutionState.disputer`**. |
155
155
  | `claimResolverStake(marketPda, params)` | After resolution: matching vote → stake returned to resolver; otherwise stake **slashed** to platform treasury. |
156
156
  | `fetchResolutionState(marketPda)` | Read proposal, dispute, refute bond locked (`ResolutionState`). Challenge length and resolver stake size come from **`fetchPlatformProfile`**. |
157
157
  | `closeMarketEarly(marketPda, params)` | Creator / config authority before `close_at`. |
158
- | `voidMarket(marketPda, params)` | Void market. **Creator** cannot void while pari **outcome pools** (active stakes) or complete-set outstanding is non-zero use a **global config** authority to cancel live markets. **Cannot void while a refute dispute is open.** Parimutuel: then **`parimutuelWithdraw`** for full net refunds. |
158
+ | `voidMarket(marketPda, params)` | Void market. **Creator** cannot void while pari **outcome pools** (active stakes) or complete-set outstanding is non-zero, use a **global config** authority to cancel live markets. **Cannot void while a refute dispute is open.** Parimutuel: then **`parimutuelWithdraw`** for full net refunds. |
159
159
  | `claimVoidedParimutuelSurplus(marketPda, params)` | **Global config authority only.** After void, if pari **outcome pools** are zero but **`total_pool`** still holds early-exit **pool-keep** (no stakers left), sweeps that amount from the vault to the platform treasury. |
160
160
  | `abandonMarket(marketPda, params)` | Creator abandons empty market (reclaim rent). |
161
161
 
162
- **`resolveRefute` account meta `disputerCollateral` (common pitfall):** Anchor’s JS client expects **camelCase** keys in `.accounts()` / `.accountsStrict()`, matching the camelCase IDL. The JSON IDL field is `disputer_collateral`; if you pass **`disputer_collateral`** in the accounts object, Anchor ignores it and you get **`Account 'disputerCollateral' not provided`**. Use **`disputerCollateral`**. The account is **always required** for the instruction (see **Disputer collateral on resolve_refute** under [IDL, account metas, and peer deps](#idl-account-metas-and-peer-deps-browser--raw-anchor) dismiss does not fund it, but it must be present). For raw `program.methods`, supply every remaining account explicitly; **`as never`** on the accounts object is only to satisfy stale generated TypeScript the chain still needs the meta. **IDL drift** (served JSON vs npm bundle) also produces “not provided”; prefer **`import { IDL } from '@vercora-protocol/sdk'`** or the same **`dist/idl/vercora.json`** as your installed package version.
162
+ **`resolveRefute`, account meta `disputerCollateral` (common pitfall):** Anchor’s JS client expects **camelCase** keys in `.accounts()` / `.accountsStrict()`, matching the camelCase IDL. The JSON IDL field is `disputer_collateral`; if you pass **`disputer_collateral`** in the accounts object, Anchor ignores it and you get **`Account 'disputerCollateral' not provided`**. Use **`disputerCollateral`**. The account is **always required** for the instruction (see **Disputer collateral on resolve_refute** under [IDL, account metas, and peer deps](#idl-account-metas-and-peer-deps-browser--raw-anchor), dismiss does not fund it, but it must be present). For raw `program.methods`, supply every remaining account explicitly; **`as never`** on the accounts object is only to satisfy stale generated TypeScript, the chain still needs the meta. **IDL drift** (served JSON vs npm bundle) also produces “not provided”; prefer **`import { IDL } from '@vercora-protocol/sdk'`** or the same **`dist/idl/vercora.json`** as your installed package version.
163
163
 
164
164
  #### `resolveRefute` examples
165
165
 
@@ -214,7 +214,7 @@ await program.methods
214
214
  resolutionState: resolutionStatePk,
215
215
  resolverStakeVault: deriveResolverStakeVault(program.programId, marketPda),
216
216
  collateralMint,
217
- disputerCollateral, // required camelCase key (`disputer_collateral` in JSON IDL is ignored)
217
+ disputerCollateral, // required, camelCase key (`disputer_collateral` in JSON IDL is ignored)
218
218
  globalConfig: deriveGlobalConfig(program.programId),
219
219
  platformRegistry: derivePlatformRegistry(program.programId, marketAccount.platformId),
220
220
  platformTreasuryWallet,
@@ -281,7 +281,7 @@ import { PublicKey } from "@solana/web3.js";
281
281
  import BN from "bn.js";
282
282
 
283
283
  await client.initializeConfig({
284
- // System program / “none” placeholder use a real secondary authority pubkey in production
284
+ // System program / “none” placeholder, use a real secondary authority pubkey in production
285
285
  secondaryAuthority: new PublicKey("11111111111111111111111111111111"),
286
286
  depositPlatformFeeBps: 100,
287
287
  platformTreasuryWallet: treasuryPubkey,
@@ -324,7 +324,7 @@ const { marketPda } = await client.createMarket(
324
324
  maxOutcomeInvestment: new BN(0),
325
325
  title: "Will it rain tomorrow?",
326
326
  marketType: "completeSet",
327
- platformId: new BN(1), // must be > 0 register_platform + upsert_platform_profile first
327
+ platformId: new BN(1), // must be > 0, register_platform + upsert_platform_profile first
328
328
  categoryId: new BN(0),
329
329
  },
330
330
  );
@@ -390,7 +390,7 @@ const marketPda = await client.createMarketFull(
390
390
  outcomeLabels: ["A", "B"],
391
391
  platformId: new BN(1),
392
392
  categoryId: new BN(0),
393
- // Optional default true. Set false to lock stakes until close/resolution (no early parimutuelWithdraw).
393
+ // Optional, default true. Set false to lock stakes until close/resolution (no early parimutuelWithdraw).
394
394
  isEarlyWithdrawAllowed: true,
395
395
  parimutuelInit: {
396
396
  earlyWithdrawPenaltyBps: 500,
@@ -451,7 +451,7 @@ await client.parimutuelWithdraw(marketPda, {
451
451
  outcomeIndex: 0,
452
452
  amount: new BN(500_000),
453
453
  });
454
- // If Market.isEarlyWithdrawAllowed is false (from create or updateParimutuelState), parimutuelWithdraw throws EarlyWithdrawNotAllowed unless the market is voided (then full net stake back, no fees).
454
+ // If Market.isEarlyWithdrawAllowed is false (from create or updateParimutuelState), parimutuelWithdraw throws EarlyWithdrawNotAllowed, unless the market is voided (then full net stake back, no fees).
455
455
 
456
456
  // After voidMarket on a pari pool, recover stakes (repeat per outcome / until active stake is 0):
457
457
  // await client.voidMarket(marketPda, { marketId });
@@ -533,7 +533,7 @@ const all = await client.fetchAllMarkets();
533
533
  // By platform (memcmp)
534
534
  const byPlatform = await client.fetchAllMarkets(new BN(1));
535
535
 
536
- // Markets created by a wallet full rows with labels + filters
536
+ // Markets created by a wallet, full rows with labels + filters
537
537
  const mine = await client.getUsersMarkets(creatorPubkey, {
538
538
  platformId: new BN(1), // optional RPC filter
539
539
  categoryId: 2, // optional; applied after decode
@@ -558,25 +558,25 @@ const profile = await client.fetchUserProfile(wallet.publicKey);
558
558
 
559
559
  ## Resolution approval flow (propose → challenge → confirm or refute-accept)
560
560
 
561
- Settlement is **two-phase**: first a **proposal** is recorded on `ResolutionState`, then after an optional **challenge window** the market is **approved** into a final winner on the `Market` account.
561
+ Settlement is **two-phase**: first a **proposal** is recorded on `ResolutionState`, then, after an optional **challenge window**, the market is **approved** into a final winner on the `Market` account.
562
562
 
563
- 1. **Platform prerequisite** `create_market` requires **`platform_id > 0`**: a registered **`PlatformRegistry`**, an initialized **`PlatformProfile`** (single **`resolver_stake`**, **`challenge_window_secs`**, **`refute_bond`** for that platform), and PDAs for **`resolution_state`** and **`resolver_stake_vault`**.
563
+ 1. **Platform prerequisite**, `create_market` requires **`platform_id > 0`**: a registered **`PlatformRegistry`**, an initialized **`PlatformProfile`** (single **`resolver_stake`**, **`challenge_window_secs`**, **`refute_bond`** for that platform), and PDAs for **`resolution_state`** and **`resolver_stake_vault`**.
564
564
 
565
- 2. **Votes** Each assigned resolver calls **`voteResolution`** with their outcome. Votes update per-outcome tallies; resolver **stake** (from **`PlatformProfile.resolver_stake`**) transfers into the market’s **resolver stake vault**.
565
+ 2. **Votes**, Each assigned resolver calls **`voteResolution`** with their outcome. Votes update per-outcome tallies; resolver **stake** (from **`PlatformProfile.resolver_stake`**) transfers into the market’s **resolver stake vault**.
566
566
 
567
- 3. **Propose (`finalizeResolution`)** When at least **`resolution_threshold`** resolvers agree on the **same** outcome, anyone may call **`finalizeResolution`**. On-chain this **does not** immediately set `Market.winning_outcome_index`. It sets **`ResolutionState.proposed_outcome`**, **`proposal_ts`**, and starts the **challenge window** (duration from **`PlatformProfile.challenge_window_secs`**).
567
+ 3. **Propose (`finalizeResolution`)**, When at least **`resolution_threshold`** resolvers agree on the **same** outcome, anyone may call **`finalizeResolution`**. On-chain this **does not** immediately set `Market.winning_outcome_index`. It sets **`ResolutionState.proposed_outcome`**, **`proposal_ts`**, and starts the **challenge window** (duration from **`PlatformProfile.challenge_window_secs`**).
568
568
 
569
- 4. **Challenge window** Until **`proposal_ts + challenge_window_secs`** elapses, a participant may **`openRefute`** with **exactly** **`platform_profile.refute_bond`**: lock that collateral and assert a **different** winning outcome. An authorized party (global **primary or secondary** authority, or platform **`profileAuthority`**) may **`resolveRefute`**: **`accept: false`** dismisses (bond → treasury), **`accept: true`** accepts (bond refunded, **`winning_outcome_index`** set immediately). While a dispute is active, **`confirmResolution`** is rejected. **`voidMarket`** is rejected while a dispute is open.
569
+ 4. **Challenge window**, Until **`proposal_ts + challenge_window_secs`** elapses, a participant may **`openRefute`** with **exactly** **`platform_profile.refute_bond`**: lock that collateral and assert a **different** winning outcome. An authorized party (global **primary or secondary** authority, or platform **`profileAuthority`**) may **`resolveRefute`**: **`accept: false`** dismisses (bond → treasury), **`accept: true`** accepts (bond refunded, **`winning_outcome_index`** set immediately). While a dispute is active, **`confirmResolution`** is rejected. **`voidMarket`** is rejected while a dispute is open.
570
570
 
571
- 5. **Confirm (final approval)** After **`proposal_ts + challenge_window`**, if there is **no** blocking dispute and the market was not already finalized by **`resolveRefute(accept: true)`**, anyone calls **`confirmResolution`**. This writes **`Market.winning_outcome_index`** the outcome is now final for **`redeemWinning`** / **`parimutuelClaim`**.
571
+ 5. **Confirm (final approval)**, After **`proposal_ts + challenge_window`**, if there is **no** blocking dispute and the market was not already finalized by **`resolveRefute(accept: true)`**, anyone calls **`confirmResolution`**. This writes **`Market.winning_outcome_index`**, the outcome is now final for **`redeemWinning`** / **`parimutuelClaim`**.
572
572
 
573
- 6. **Resolver stake** After settlement, resolvers use **`claimResolverStake`**: stake returns to the resolver if their vote matched the final winner; otherwise it is transferred to the platform treasury.
573
+ 6. **Resolver stake**, After settlement, resolvers use **`claimResolverStake`**: stake returns to the resolver if their vote matched the final winner; otherwise it is transferred to the platform treasury.
574
574
 
575
575
  **Reads**
576
576
 
577
- - **`fetchResolutionState(marketPda)`** `proposed_outcome`, `proposal_ts`, `dispute_active`, `refute_bond_amount`, etc.
578
- - **`fetchPlatformProfile(platformId)`** `challenge_window_secs`, `resolver_stake`, `refute_bond` (challenge length and stake are not stored on `ResolutionState`).
579
- - **`fetchMarket(marketPda)`** `winningOutcomeIndex` is **`null`** until **`confirmResolution`** or **`resolveRefute({ accept: true })`** succeeds.
577
+ - **`fetchResolutionState(marketPda)`**, `proposed_outcome`, `proposal_ts`, `dispute_active`, `refute_bond_amount`, etc.
578
+ - **`fetchPlatformProfile(platformId)`**, `challenge_window_secs`, `resolver_stake`, `refute_bond` (challenge length and stake are not stored on `ResolutionState`).
579
+ - **`fetchMarket(marketPda)`**, `winningOutcomeIndex` is **`null`** until **`confirmResolution`** or **`resolveRefute({ accept: true })`** succeeds.
580
580
 
581
581
  **UI / agent logic**
582
582
 
@@ -587,10 +587,10 @@ Settlement is **two-phase**: first a **proposal** is recorded on `ResolutionStat
587
587
 
588
588
  On-chain, **`platform_id`** is **`u32`** and **`category_id`** is **`u8`** in `CreateMarketArgs` (not pubkeys).
589
589
 
590
- 1. **`register_platform`** assigns the next id from `GlobalConfig.next_platform_id` (starts at **1**); PDA `["platform", platform_id le u32]`.
591
- 2. **`upsert_platform_profile`** metadata + **resolution policy** (`resolver_stake`, `challenge_window_secs`, `refute_bond`); signed by **global config** primary or secondary authority.
592
- 3. **`create_market_category`** `category_id` must equal `PlatformRegistry.next_category_id`; PDA `["market-category", platform_id, category_id]`.
593
- 4. **`create_market`** requires **`platform_id > 0`**, **`platform_registry`**, **`platform_profile`**, **`resolution_state`**, **`resolver_stake_vault`**. Use **`category_id == 0`** for uncategorized markets (omit **`market_category`** account). Non-zero **`category_id`** requires an active **`market_category`** PDA for that platform.
590
+ 1. **`register_platform`**, assigns the next id from `GlobalConfig.next_platform_id` (starts at **1**); PDA `["platform", platform_id le u32]`.
591
+ 2. **`upsert_platform_profile`**, metadata + **resolution policy** (`resolver_stake`, `challenge_window_secs`, `refute_bond`); signed by **global config** primary or secondary authority.
592
+ 3. **`create_market_category`**, `category_id` must equal `PlatformRegistry.next_category_id`; PDA `["market-category", platform_id, category_id]`.
593
+ 4. **`create_market`**, requires **`platform_id > 0`**, **`platform_registry`**, **`platform_profile`**, **`resolution_state`**, **`resolver_stake_vault`**. Use **`category_id == 0`** for uncategorized markets (omit **`market_category`** account). Non-zero **`category_id`** requires an active **`market_category`** PDA for that platform.
594
594
 
595
595
  Use **`derivePlatformRegistry`**, **`derivePlatformProfile`**, **`deriveMarketCategory`**, **`deriveResolutionState`**, **`deriveResolverStakeVault`** when building instructions manually.
596
596
 
@@ -598,8 +598,8 @@ Use **`derivePlatformRegistry`**, **`derivePlatformProfile`**, **`deriveMarketCa
598
598
 
599
599
  Use `marketType: 'parimutuel'` or `'completeSet'` at creation; the choice is permanent.
600
600
 
601
- - **Parimutuel** pooled stakes, no outcome SPLs; good default for prediction apps. **`isEarlyWithdrawAllowed`** is set at create (default **allowed**) and can be changed by the creator via **`updateParimutuelState`**; when disabled, early **`parimutuelWithdraw`** is blocked until close or resolution. **`maxWalletOutcomeInvestment`** and **`isWalletOutcomeStakeExact`** are set at create and can be updated via **`updateParimutuelState`** (same instruction as penalty / early-withdraw edits). After **`voidMarket`**, participants **`parimutuelWithdraw`** full net stakes (no penalty / withdraw fees).
602
- - **Complete-set** outcome SPL tokens; you still need external liquidity for single-leg trading.
601
+ - **Parimutuel**, pooled stakes, no outcome SPLs; good default for prediction apps. **`isEarlyWithdrawAllowed`** is set at create (default **allowed**) and can be changed by the creator via **`updateParimutuelState`**; when disabled, early **`parimutuelWithdraw`** is blocked until close or resolution. **`maxWalletOutcomeInvestment`** and **`isWalletOutcomeStakeExact`** are set at create and can be updated via **`updateParimutuelState`** (same instruction as penalty / early-withdraw edits). After **`voidMarket`**, participants **`parimutuelWithdraw`** full net stakes (no penalty / withdraw fees).
602
+ - **Complete-set**, outcome SPL tokens; you still need external liquidity for single-leg trading.
603
603
 
604
604
  ## PDA helpers
605
605
 
package/agents/skill.md CHANGED
@@ -1,18 +1,20 @@
1
- # Vercora Protocol agent skill entry (`@vercora-protocol/sdk`)
1
+ # Vercora Protocol: agent skill entry (`@vercora-protocol/sdk`)
2
2
 
3
3
  This file ships **inside** the npm package (`agents/skill.md`) so AI agents, clawbots, and operator scripts can load instructions without depending on a particular website.
4
4
 
5
+ **Scope:** Vercora Protocol is **multi-product issuer infrastructure** over time. **This skill and the bundled SDK** target the **outcome markets** program only (markets, resolution, settlement). Do not assume other product lanes (e.g. issuer diversification) are available in `PredictionMarketClient` until documented in this package.
6
+
5
7
  ## Public production deployment (Vercora)
6
8
 
7
- The canonical HTTPS deployment—use this when you **do not** have the monorepois **[vercora.xyz](https://vercora.xyz)**. Fetch these over TLS; use a Solana `Connection` and cluster that match the deployment you operate against (see this package’s `README.md`).
9
+ When you **do not** have the monorepo, the canonical HTTPS deployment is **[vercora.xyz](https://vercora.xyz)**. Fetch these over TLS; use a Solana `Connection` and cluster that match the deployment you operate against (see this package’s `README.md`).
8
10
 
9
11
  | Resource | URL |
10
12
  |----------|-----|
11
13
  | Full AI playbook (markdown) | `https://vercora.xyz/agents/playbook.md` |
12
14
  | This skill entry (markdown) | `https://vercora.xyz/agents/skill.md` |
13
15
  | Pointer manifest (JSON) | `https://vercora.xyz/.well-known/vercora-agents.json` |
14
- | Developer docs (human) | `https://vercora.xyz/docs` (includes **Resolution flow** same narrative as agents) |
15
- | AI / agents playbook (human + markdown) | `https://vercora.xyz/docs/agents` full playbook + **resolution at a glance** |
16
+ | Developer docs (human) | `https://vercora.xyz/docs` (includes **Resolution flow**, same narrative as agents) |
17
+ | AI / agents playbook (human + markdown) | `https://vercora.xyz/docs/agents`, full playbook + **resolution at a glance** |
16
18
 
17
19
  Example:
18
20
 
@@ -26,8 +28,8 @@ For self-hosted or staging sites, use the same path suffixes with your origin: `
26
28
 
27
29
  ## What to read first
28
30
 
29
- 1. **This package’s `README.md`** install, exports, `PredictionMarketClient` API, and the **AI agent integration** section (workflow map).
30
- 2. **Human playbook UI** **`https://vercora.xyz/docs/agents`**: same playbook as below, plus a **Resolution at a glance** block (vote → propose → challenge → **confirm or refute-accept**), aligned with **`https://vercora.xyz/docs#resolution-flow`**.
31
+ 1. **This package’s `README.md`**: install, exports, `PredictionMarketClient` API, and the **AI agent integration** section (workflow map).
32
+ 2. **Human playbook UI** at **`https://vercora.xyz/docs/agents`**: same playbook as below, plus a **Resolution at a glance** block (vote → propose → challenge → **confirm or refute-accept**), aligned with **`https://vercora.xyz/docs#resolution-flow`**.
31
33
  3. **Full playbook** (skills, pitfalls, decision trees):
32
34
  - **Production:** `https://vercora.xyz/agents/playbook.md`
33
35
  - **Monorepo (contributors):** `prediction_market/docs/AI-AGENT-SDK-PLAYBOOK.md` (content matches the production mirror).
@@ -70,20 +72,20 @@ Paths are under `node_modules/@vercora-protocol/sdk/` after install.
70
72
  ## Quick guardrails (parimutuel)
71
73
 
72
74
  - **`updateConfig`:** `params.secondaryAuthority` is written to chain on **every** call. When only adjusting fees/treasury, pass the **existing** secondary pubkey to keep (from `fetchGlobalConfig()`). Passing the primary key there removes the backup authority.
73
- - After `fetchMarket(marketPda)`, read **`isEarlyWithdrawAllowed`**. If `false`, do not propose early-exit **`parimutuelWithdraw`** until close/resolution (**`EarlyWithdrawNotAllowed`**), **unless `isVoided`** — then **`parimutuelWithdraw`** refunds full net stakes (no penalty / withdraw fees).
75
+ - After `fetchMarket(marketPda)`, read **`isEarlyWithdrawAllowed`**. If `false`, do not propose early-exit **`parimutuelWithdraw`** until close or resolution (you hit **`EarlyWithdrawNotAllowed`**). If **`isVoided`**, **`parimutuelWithdraw`** still refunds full net stakes (no penalty / withdraw fees).
74
76
  - Also read **`maxWalletOutcomeInvestment`** (`BN`, `0` = unlimited) and **`isWalletOutcomeStakeExact`**. When proposing **`parimutuelStake`**, enforce per-wallet caps and exact-stake rules (**`WalletOutcomeInvestmentCapExceeded`**, **`WalletOutcomeExactStakeMismatch`**).
75
- - **Creators** (open pari market, not resolved/voided): **`updateParimutuelState`** updates penalty bps, **`isEarlyWithdrawAllowed`**, **`maxWalletOutcomeInvestment`**, and **`isWalletOutcomeStakeExact`** in one instruction pass **full** params (current values from **`fetchMarket`** + **`fetchParimutuelState`** for fields you keep unchanged). If **`isWalletOutcomeStakeExact`** is `true`, **`maxWalletOutcomeInvestment`** must be **> 0** (**`InvalidWalletOutcomeStakeExactConfig`** otherwise).
77
+ - **Creators** (open pari market, not resolved/voided): **`updateParimutuelState`** updates penalty bps, **`isEarlyWithdrawAllowed`**, **`maxWalletOutcomeInvestment`**, and **`isWalletOutcomeStakeExact`** in one instruction. Always pass **full** params (current values from **`fetchMarket`** + **`fetchParimutuelState`** for fields you keep unchanged). If **`isWalletOutcomeStakeExact`** is `true`, **`maxWalletOutcomeInvestment`** must be **> 0** (**`InvalidWalletOutcomeStakeExactConfig`** otherwise).
76
78
  - **`voidMarket`:** the **creator** cannot void while pari **outcome pools** (active stakes) or complete-set outstanding is non-zero (**`CreatorCannotVoidWithActiveLiquidity`**). **Cannot void while an `openRefute` dispute is active** (**`CannotVoidWithOpenDispute`**). Propose a **global config authority** wallet to cancel live markets; SDK passes **`resolutionState`** and **`parimutuelState`** (pari) or `null` (complete-set).
77
- - **`claimVoidedParimutuelSurplus`:** **global authority only** if a voided pari market has **zero outcome stakes** but **`total_pool` > 0** (early-exit pool-keep left in the vault), sweep that surplus to the platform treasury. Call after users have finished void refunds.
78
- - Use **`isClosedEarly`**, **`isVoided`**, **`winningOutcomeIndex`** for lifecycle not legacy `closed` / `voided` / `resolvedOutcomeIndex` names.
79
+ - **`claimVoidedParimutuelSurplus`:** **global authority only**. If a voided pari market has **zero outcome stakes** but **`total_pool` > 0** (early-exit pool-keep left in the vault), sweep that surplus to the platform treasury. Call after users have finished void refunds.
80
+ - Use **`isClosedEarly`**, **`isVoided`**, **`winningOutcomeIndex`** for lifecycle, not legacy `closed` / `voided` / `resolvedOutcomeIndex` names.
79
81
 
80
82
  ## Quick guardrails (resolution)
81
83
 
82
84
  - **`create_market`** requires **`platform_id > 0`**: register a platform, **`upsert_platform_profile`** (global config primary or secondary authority signs), and pass **`platform_registry`**, **`platform_profile`**, **`resolution_state`**, **`resolver_stake_vault`** (SDK methods wire PDAs when you use `PredictionMarketClient`).
83
85
  - Settlement is **two-phase**: **`finalizeResolution`** records a **proposal** on **`fetchResolutionState`** (`proposed_outcome`, `proposal_ts`). It does **not** set **`winningOutcomeIndex`** on the market.
84
86
  - After **`challenge_window_secs`** from **`fetchPlatformProfile(platformId)`** (same value used on-chain for the challenge window), call **`confirmResolution`** to finalize **`Market.winningOutcomeIndex`**. Until then, traders cannot **`redeemWinning`** / **`parimutuelClaim`** as “resolved.”
85
- - Optional dispute: **`openRefute`** during the window; **`resolveRefute`** with **`accept: false`** slashes the bond to treasury, **`accept: true`** refunds the refuter and sets **`winningOutcomeIndex`** immediately. **Who signs `resolveRefute`:** global **primary/secondary** (`GlobalConfig`) or platform **`profileAuthority`** on **`PlatformRegistry`** **not** the per-market **`voteResolution`** resolver wallets. Legacy **`dispute_resolution_authority`** on config does **not** gate this instruction. **`confirmResolution`** fails while a dispute blocks it; skip **`confirmResolution`** if accept already finalized the market.
86
- - **`disputer_collateral`** on **`resolve_refute`**: the refuter’s collateral ATA (same role as **`refuter_collateral`** on **`open_refute`**). **Always** in the account list **dismiss** does not transfer the bond into it, but the account must still be present and valid. Raw Anchor: use camelCase **`disputerCollateral`** in `.accounts()` or Anchor reports **Account disputerCollateral not provided**. Prefer the **IDL from `@vercora-protocol/sdk`** (`import { IDL } …` or `dist/idl/vercora.json`); a separately hosted / `fetchIdl` JSON that drifts from the package causes the same error.
87
- - **`claim_resolver_stake`** / **`resolve_refute`**: if **`platform_fee_lamports` > 0**, the program transfers SOL to **`platform_treasury_wallet`** the IDL must mark that wallet **writable** or you can hit **PrivilegeEscalation** (“writable privilege escalated”). Use the published package IDL; do not strip `writable` when forking JSON.
87
+ - Optional dispute: **`openRefute`** during the window; **`resolveRefute`** with **`accept: false`** slashes the bond to treasury, **`accept: true`** refunds the refuter and sets **`winningOutcomeIndex`** immediately. **Who signs `resolveRefute`:** global **primary/secondary** (`GlobalConfig`) or platform **`profileAuthority`** on **`PlatformRegistry`**, **not** the per-market **`voteResolution`** resolver wallets. Legacy **`dispute_resolution_authority`** on config does **not** gate this instruction. **`confirmResolution`** fails while a dispute blocks it; skip **`confirmResolution`** if accept already finalized the market.
88
+ - **`disputer_collateral`** on **`resolve_refute`**: the refuter’s collateral ATA (same role as **`refuter_collateral`** on **`open_refute`**). **Always** in the account list. **Dismiss** does not transfer the bond into it, but the account must still be present and valid. Raw Anchor: use camelCase **`disputerCollateral`** in `.accounts()` or Anchor reports **Account disputerCollateral not provided**. Prefer the **IDL from `@vercora-protocol/sdk`** (`import { IDL } …` or `dist/idl/vercora.json`); a separately hosted / `fetchIdl` JSON that drifts from the package causes the same error.
89
+ - **`claim_resolver_stake`** / **`resolve_refute`**: if **`platform_fee_lamports` > 0**, the program transfers SOL to **`platform_treasury_wallet`**. The IDL must mark that wallet **writable** or you can hit **PrivilegeEscalation** (“writable privilege escalated”). Use the published package IDL; do not strip `writable` when forking JSON.
88
90
  - After final winner is set, resolvers may **`claimResolverStake`** (wrong outcome → slash to treasury). Read **`fetchResolutionState`** + **`fetchMarket`** together for UI (proposal vs final).
89
91
  - **Tooling:** **`SendTransactionError: Unknown action 'undefined'`** can appear with some **`@coral-xyz/anchor`** + **`@solana/web3.js`** pairs (error ctor mismatch). Stay on the SDK **`package.json`** peer ranges or align **`@solana/web3.js`** with Anchor’s guidance for your Anchor minor.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@vercora-protocol/sdk",
3
- "version": "0.4.2",
4
- "description": "TypeScript SDK for the Vercora protocol on Solana",
3
+ "version": "0.5.0",
4
+ "description": "TypeScript SDK for Vercora Protocol on Solana — client for the outcome-markets Anchor program (issuer utility infra; more product lanes on the roadmap).",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "files": [