Real-time prediction markets · Cryptographically verified on Solana
Track the top-performing prediction traders on TxPredict. Rankings are updated in real-time as match resolutions occur.
Our algorithms analyze divergences between aggregate global consensus bookmaker odds from TxLINE and local prediction pool allocations. Higher divergence represents a potential high-value betting edge.
To address the hackathon's track requirements for Custom On-Chain Settlement Engines, this reference architecture demonstrates how a decentralized prediction market uses Cross-Program Invocations (CPIs) into the TxLINE validation program to confirm match outcomes and trustlessly distribute locked escrow funds to winners.
Here is the core Anchor code of the custom Escrow Program executing CPI settlement into TxLINE's validate_stat instruction:
use anchor_lang::prelude::*;
use anchor_lang::solana_program::instruction::Instruction;
declare_id!("PrEd1ct10nMarketEscrow111111111111111111");
#[program]
pub mod prediction_escrow {
use super::*;
pub fn place_prediction(ctx: Context<PlacePrediction>, outcome: u8, amount: u64) -> Result<()> {
let prediction = &mut ctx.accounts.prediction;
prediction.predictor = ctx.accounts.user.key();
prediction.outcome = outcome;
prediction.amount = amount;
prediction.settled = false;
// Transfer funds to the escrow PDA
anchor_lang::system_program::transfer(
CpiContext::new(
ctx.accounts.system_program.to_account_info(),
anchor_lang::system_program::Transfer {
from: ctx.accounts.user.to_account_info(),
to: ctx.accounts.escrow_pda.to_account_info(),
},
),
amount,
)?;
Ok(())
}
pub fn settle_prediction(
ctx: Context<SettlePrediction>,
proof: Vec<[u8; 32]>,
expected_root: [u8; 32],
) -> Result<()> {
let prediction = &mut ctx.accounts.prediction;
require!(!prediction.settled, ErrorCode::AlreadySettled);
// 1. Prepare Cross-Program Invocation (CPI) into TxLINE validation program
// TxLINE Program ID: 6pW64gN1s2uqjHkn1unFeEjAwJkPGHoppGvS715wyP2J
let txline_program_info = ctx.accounts.txline_program.to_account_info();
// CPI accounts required by TxLINE validate_stat instruction
let accounts = vec![
AccountMeta::new_readonly(ctx.accounts.txline_state.key(), false),
AccountMeta::new_readonly(ctx.accounts.txline_proof_registry.key(), false),
];
// 2. Build validate_stat instruction data
// Verify that the match outcome (leaf hash) is present in the verified root
let mut data = vec![];
data.extend_from_slice(&expected_root);
for node in proof {
data.extend_from_slice(&node);
}
let cpi_instruction = Instruction {
program_id: txline_program_info.key(),
accounts,
data,
};
// 3. Invoke TxLINE validation on-chain
anchor_lang::solana_program::program::invoke(
&cpi_instruction,
&[
ctx.accounts.txline_state.to_account_info(),
ctx.accounts.txline_proof_registry.to_account_info(),
],
)?;
// 4. Verification succeeded - Release Escrow
prediction.settled = true;
let payout = prediction.amount * 2; // Example 1:1 odds pool multiplier
let escrow_seeds = &[
b"escrow",
ctx.accounts.escrow_pda.owner.as_ref(),
&[ctx.bumps.escrow_pda],
];
let signer = &[&escrow_seeds[..]];
anchor_lang::system_program::transfer(
CpiContext::new_with_signer(
ctx.accounts.system_program.to_account_info(),
anchor_lang::system_program::Transfer {
from: ctx.accounts.escrow_pda.to_account_info(),
to: ctx.accounts.winner.to_account_info(),
},
signer,
),
payout,
)?;
Ok(())
}
}
#[derive(Accounts)]
pub struct PlacePrediction<'info> {
#[account(mut)]
pub user: Signer<'info>,
#[account(
init,
payer = user,
space = 8 + 32 + 1 + 8 + 1,
seeds = [b"prediction", user.key().as_ref()],
bump
)]
pub prediction: Account<'info, PredictionState>,
#[account(mut, seeds = [b"escrow"], bump)]
pub escrow_pda: SystemAccount<'info>,
pub system_program: Program<'info, System>,
}
#[derive(Accounts)]
pub struct SettlePrediction<'info> {
#[account(mut)]
pub prediction: Account<'info, PredictionState>,
#[account(mut, seeds = [b"escrow"], bump)]
pub escrow_pda: SystemAccount<'info>,
#[account(mut)]
pub winner: SystemAccount<'info>,
/// CHECK: Target TxLINE Solana validation program
pub txline_program: UncheckedAccount<'info>,
/// CHECK: Signed state account containing root
pub txline_state: UncheckedAccount<'info>,
/// CHECK: Merkle Registry account containing valid indices
pub txline_proof_registry: UncheckedAccount<'info>,
pub system_program: Program<'info, System>,
}
#[account]
pub struct PredictionState {
pub predictor: Pubkey,
pub outcome: u8,
pub amount: u64,
pub settled: bool,
}
#[error_code]
pub mod ErrorCode {
#[msg("This prediction has already been settled.")]
AlreadySettled,
}