The Market Settlement program handles proof submission, verification, market resolution, payout claims, and dispute resolution for the Mentat Protocol. Built using Anchor framework version 0.31.1.
Program ID: mktRU9S5U6cKzX6dvKeyUgm8g8VPRZxuzizfNX18cR1
Location: apps/solana-programs/programs/market-settlement/
Stores submitted proof of market outcomes.
pub struct ProofAccount {
pub market: Pubkey, // Associated market
pub submitter: Pubkey, // Proof submitter
pub proof_id: u64, // Unique proof ID
pub outcome_index: u8, // Proposed outcome
pub proof_data: String, // Proof URI/hash (max 200 chars)
pub status: ProofStatus, // Pending/Verified/Rejected/Disputed
pub verifier: Pubkey, // Who verified it
pub verification_count: u8, // Number of verifications
pub submitted_at: i64, // Submission timestamp
pub verified_at: i64, // Verification timestamp
pub bump: u8, // PDA bump
}PDA Derivation: ["proof", market_pubkey, proof_id]
Account Size: 346 bytes
Tracks market resolution status and payout information.
pub struct ResolutionAccount {
pub market: Pubkey, // Associated market
pub resolver: Pubkey, // Market resolver
pub winning_outcome: u8, // Winning outcome (255 = not resolved)
pub total_proofs: u64, // Total proofs submitted
pub verified_proofs: u64, // Number verified
pub total_payout: u64, // Total payout amount
pub claimed_amount: u64, // Amount claimed so far
pub claim_count: u64, // Number of claims
pub resolved_at: i64, // Resolution timestamp
pub settlement_deadline: i64, // When settlement can occur
pub is_disputed: bool, // Whether under dispute
pub bump: u8, // PDA bump
}PDA Derivation: ["resolution", market_pubkey]
Account Size: 139 bytes
Handles disputes of market resolutions.
pub struct DisputeAccount {
pub market: Pubkey, // Associated market
pub disputer: Pubkey, // Who opened dispute
pub dispute_id: u64, // Unique dispute ID
pub reason: String, // Dispute reason (max 500 chars)
pub original_outcome: u8, // Original outcome being disputed
pub proposed_outcome: u8, // Alternative outcome
pub stake_amount: u64, // Locked stake
pub status: DisputeStatus, // Open/Resolved/Rejected
pub resolver: Pubkey, // Dispute resolver
pub opened_at: i64, // When opened
pub resolved_at: i64, // When resolved
pub bump: u8, // PDA bump
}PDA Derivation: ["dispute", market_pubkey, disputer_pubkey]
Account Size: 650 bytes
Records payout claims for winning positions.
pub struct PayoutClaimAccount {
pub market: Pubkey, // Associated market
pub claimer: Pubkey, // Who claimed
pub position: Pubkey, // Position used for claim
pub amount_claimed: u64, // Amount claimed
pub shares_used: u64, // Shares used
pub claimed_at: i64, // Claim timestamp
pub bump: u8, // PDA bump
}PDA Derivation: ["payout_claim", market_pubkey, claimer_pubkey]
Account Size: 129 bytes
File: instructions/submit_proof.rs
Allows anyone to submit proof of a market outcome.
Parameters:
proof_data: String- Proof URI or hash (max 200 chars)outcome_index: u8- Proposed outcome index
Process:
- Validates proof data length
- Checks concurrent proofs limit (max 100)
- Initializes resolution account if first proof
- Creates proof account with Pending status
- Increments total_proofs counter
- Emits
ProofSubmittedevent
Accounts:
submitter(mut, signer) - Proof submittermarket- Market accountresolution(init_if_needed) - Resolution PDAproof(init) - New proof PDAsystem_program- System program
File: instructions/verify_proof.rs
Allows designated verifiers to verify or reject proofs.
Parameters:
proof_id: u64- ID of proof to verifyis_valid: bool- Whether proof is valid
Process:
- Checks proof is in Pending state
- If valid:
- Sets status to Verified
- Records verifier
- Increments verification_count
- Updates verified_proofs in resolution
- If invalid:
- Sets status to Rejected
- Records verifier
- Sets verified_at timestamp
- Emits
ProofVerifiedevent
Accounts:
verifier(mut, signer) - Proof verifiermarket- Market accountresolution(mut) - Resolution PDAproof(mut) - Proof to verify
File: instructions/resolve_market.rs
Resolves market with winning outcome after proof verification.
Parameters:
winning_outcome: u8- Index of winning outcome
Preconditions:
- Market not already resolved
- Minimum 1 verified proof exists
- Market not under dispute
Process:
- Validates not already resolved
- Checks minimum verifications met
- Sets winning_outcome in resolution
- Sets resolver and resolved_at timestamp
- Calculates settlement_deadline (24 hours for disputes)
- Emits
MarketResolvedevent
Settlement Deadline:
settlement_deadline = current_time + MIN_SETTLEMENT_DELAY (1 hour)Accounts:
resolver(mut, signer) - Market resolvermarket(mut) - Market accountliquidity_pool(mut) - Pool accountresolution(mut) - Resolution PDAsystem_program- System program
File: instructions/claim_payout.rs
Allows winners to claim their payouts after settlement deadline.
Parameters: None (derives from position)
Preconditions:
- Market is resolved (winning_outcome ≠ 255)
- Settlement deadline has passed
- Not already claimed
Payout Calculation:
// Simplified formula (production would read from position account)
payout_gross = (winning_shares * pool_value) / total_winning_shares
settlement_fee = payout_gross * SETTLEMENT_FEE_BPS / BPS_DENOMINATOR
payout_net = payout_gross - settlement_feeProcess:
- Checks settlement deadline passed
- Validates not already claimed
- Reads winning shares from position account
- Calculates proportional payout
- Subtracts 1% settlement fee
- Creates payout claim record
- Transfers lamports from pool to claimer
- Updates resolution stats
- Emits
PayoutClaimedevent
Accounts:
claimer(mut, signer) - Payout claimermarket- Market accountposition(mut) - Position accountliquidity_pool(mut) - Pool accountresolution(mut) - Resolution PDApayout_claim(init_if_needed) - Claim record PDAsystem_program- System program
File: instructions/open_dispute.rs
Opens a dispute on market resolution during dispute period.
Parameters:
reason: String- Dispute reason (max 500 chars)stake_amount: u64- Dispute stake (min 0.001 SOL)
Preconditions:
- Market is resolved
- Within dispute period (before settlement_deadline)
- Stake >= MIN_DISPUTE_STAKE
Process:
- Validates dispute reason length
- Validates stake amount
- Checks dispute period hasn't expired
- Creates dispute account
- Locks stake in dispute vault
- Marks resolution as disputed
- Emits
DisputeOpenedevent
Dispute Stake:
MIN_DISPUTE_STAKE = 1_000_000 lamports (0.001 SOL)Accounts:
disputer(mut, signer) - Dispute openermarket- Market accountresolution(mut) - Resolution PDAdispute(init) - New dispute PDAdispute_vault(mut) - Stake vault PDAsystem_program- System program
File: instructions/resolve_dispute.rs
Resolves an open dispute with final outcome determination.
Parameters:
dispute_id: u64- Dispute to resolveresolution: u8- Resolution type (0=Reject, 1=Accept, 2=Partial)
Resolution Types:
Type 0 - Reject Dispute:
- Keep original outcome
- Slash 50% of stake as penalty
- Return remaining 50% to disputer
Type 1 - Accept Dispute:
- Change to new outcome
- Return full stake + 50% reward
- Update winning_outcome in resolution
Type 2 - Partial Accept:
- Keep original outcome
- Return full stake
Process:
- Validates dispute is Open
- Validates disputer matches
- Applies resolution based on type
- Updates dispute status
- Returns/slashes stake accordingly
- Clears is_disputed flag
- Emits
DisputeResolvedevent
Accounts:
resolver(mut, signer) - Dispute resolvermarket- Market accountmarket_resolution(mut) - Resolution PDAdispute(mut) - Dispute accountdispute_vault(mut) - Stake vaultdisputer(mut) - To return stakesystem_program- System program
// PDA Seeds
pub const PROOF_SEED: &[u8] = b"proof";
pub const RESOLUTION_SEED: &[u8] = b"resolution";
pub const DISPUTE_SEED: &[u8] = b"dispute";
pub const PAYOUT_CLAIM_SEED: &[u8] = b"payout_claim";
// Verification
pub const MIN_VERIFICATIONS: u8 = 1;
pub const MAX_VERIFICATIONS: u8 = 5;
// Timing
pub const MIN_SETTLEMENT_DELAY: i64 = 3600; // 1 hour
pub const MAX_SETTLEMENT_DELAY: i64 = 2592000; // 30 days
pub const DISPUTE_PERIOD: i64 = 86400; // 24 hours
pub const DISPUTE_RESOLUTION_TIMEOUT: i64 = 604800; // 7 days
// Disputes
pub const MIN_DISPUTE_STAKE: u64 = 1_000_000; // 0.001 SOL
pub const DISPUTE_SLASH_PERCENTAGE: u64 = 50; // 50% slash
// Limits
pub const MAX_PROOF_DATA_LENGTH: usize = 200;
pub const MAX_DISPUTE_REASON_LENGTH: usize = 500;
pub const MAX_CONCURRENT_PROOFS: u64 = 100;
// Fees
pub const SETTLEMENT_FEE_BPS: u16 = 100; // 1%
pub const BPS_DENOMINATOR: u16 = 10000;| Code | Error | Description |
|---|---|---|
| 6000 | MarketNotResolved | Market is not in resolved state |
| 6001 | ResolutionDeadlineNotReached | Too early to resolve |
| 6002 | MarketAlreadyResolved | Already resolved |
| 6003 | InvalidOutcome | Invalid outcome index |
| 6004 | ProofDataTooLong | Proof data exceeds 200 chars |
| 6005 | DisputeReasonTooLong | Reason exceeds 500 chars |
| 6006 | InsufficientDisputeStake | Stake below minimum |
| 6007 | DisputePeriodExpired | Too late to dispute |
| 6008 | MarketUnderDispute | Market is disputed |
| 6009 | DisputeNotFound | Dispute doesn't exist |
| 6010 | DisputeAlreadyResolved | Dispute already resolved |
| 6011 | ProofNotVerified | Proof not verified |
| 6012 | ProofAlreadyVerified | Already verified |
| 6013 | ProofAlreadyRejected | Already rejected |
| 6014 | NoWinningShares | No shares for winning outcome |
| 6015 | PayoutAlreadyClaimed | Already claimed |
| 6016 | SettlementDeadlineNotPassed | Too early to claim |
| 6017 | UnauthorizedCreator | Only creator allowed |
| 6018 | UnauthorizedVerifier | Only verifier allowed |
| 6019 | UnauthorizedDisputer | Only disputer allowed |
| 6020 | MathOverflow | Math overflow |
| 6021 | DivisionByZero | Division by zero |
| 6022 | InvalidProofStatusTransition | Invalid status change |
| 6023 | InvalidDisputeStatusTransition | Invalid status change |
| 6024 | TooManyProofs | Exceeded proof limit |
| 6025 | MinVerificationsNotMet | Not enough verifications |
| 6026 | NoSharesForWinningOutcome | No winning shares |
| 6027 | InvalidPayoutCalculation | Payout calculation failed |
pub struct ProofSubmitted {
pub market: Pubkey,
pub proof_id: u64,
pub submitter: Pubkey,
pub outcome_index: u8,
pub proof_data: String,
pub timestamp: i64,
}pub struct ProofVerified {
pub market: Pubkey,
pub proof_id: u64,
pub verifier: Pubkey,
pub is_valid: bool,
pub timestamp: i64,
}pub struct MarketResolved {
pub market: Pubkey,
pub resolver: Pubkey,
pub winning_outcome: u8,
pub total_payout: u64,
pub settlement_deadline: i64,
pub timestamp: i64,
}pub struct PayoutClaimed {
pub market: Pubkey,
pub claimer: Pubkey,
pub position: Pubkey,
pub amount_claimed: u64,
pub shares_used: u64,
pub timestamp: i64,
}pub struct DisputeOpened {
pub market: Pubkey,
pub dispute_id: u64,
pub disputer: Pubkey,
pub original_outcome: u8,
pub proposed_outcome: u8,
pub stake_amount: u64,
pub reason: String,
pub timestamp: i64,
}pub struct DisputeResolved {
pub market: Pubkey,
pub dispute_id: u64,
pub resolver: Pubkey,
pub resolution: String,
pub final_outcome: u8,
pub timestamp: i64,
}1. Market Created (Market Factory)
↓
2. Trading Active (Market Factory)
↓
3. Resolution Deadline Reached
↓
4. Proofs Submitted → submit_proof()
↓
5. Proofs Verified → verify_proof()
↓
6. Market Resolved → resolve_market()
↓
7. Dispute Period (24 hours)
├─→ Dispute Opened? → open_dispute()
│ ├─→ Dispute Resolved → resolve_dispute()
│ └─→ Return to step 8
└─→ No Dispute
↓
8. Settlement Deadline Passed
↓
9. Winners Claim Payouts → claim_payout()
↓
10. Market Closed (Market Factory)
- ✅ Multiple verification support
- ✅ Concurrent proof limits
- ✅ Status transition validation
- ✅ Timestamp tracking
- ✅ Stake-based dispute mechanism
- ✅ Time-limited dispute period
- ✅ Slash penalties for frivolous disputes
- ✅ Rewards for valid disputes
- ✅ Settlement deadline enforcement
- ✅ Double-claim prevention
- ✅ Proportional payout calculation
- ✅ Fee deduction before transfer
- ✅ Minimum dispute stakes
- ✅ Slashing for rejected disputes
- ✅ Settlement fees (1%)
- ✅ Overflow protection
cd apps/solana-programs
cargo build-sbf# Coming soon - test suite to be implemented
anchor testsolana config set --url devnet
solana program deploy target/deploy/market_settlement.so- ✅
lib.rs(62 lines) - Program entry point - ✅
state.rs(200 lines) - State structures - ✅
constants.rs(30 lines) - Constants - ✅
errors.rs(84 lines) - Error types - ✅
events.rs(70 lines) - Event definitions - ✅
instructions/mod.rs(13 lines) - Module exports - ✅
instructions/submit_proof.rs(102 lines) - Submit proof - ✅
instructions/verify_proof.rs(69 lines) - Verify proof - ✅
instructions/resolve_market.rs(89 lines) - Resolve market - ✅
instructions/claim_payout.rs(135 lines) - Claim payout - ✅
instructions/open_dispute.rs(105 lines) - Open dispute - ✅
instructions/resolve_dispute.rs(132 lines) - Resolve dispute
Total: ~1,091 lines of code
✅ COMPLETE - All 6 instructions implemented and compiled
✅ BINARY - 353KB at target/deploy/market_settlement.so
⏭️ NEXT - Integration testing with Market Factory program
The Market Settlement program works in tandem with the Market Factory program:
-
Market Factory handles:
- Market creation
- Trading and liquidity
- Market state management
- Fee collection
-
Market Settlement handles:
- Proof submission and verification
- Market resolution
- Dispute resolution
- Payout distribution
- Cross-Program Invocation (CPI) - Implement CPI calls between programs
- Integration Tests - Test full lifecycle with both programs
- Event Indexer - Build off-chain indexer for events
- Frontend Integration - Connect to web interface
- Devnet Deployment - Deploy and test on Solana devnet