A faithful implementation of the Gnosis Conditional Tokens Framework (CTF) on Solana, enabling combinatorial prediction markets through "deep splits."
The Conditional Tokens Framework enables the creation of nested conditional markets where outcome tokens from one prediction market can serve as collateral for another. This allows for sophisticated market structures like:
- "If Trump wins, will he fire the Fed Chair?"
- "If ETH hits $10k, will BTC also be above $100k?"
- "If team A wins the tournament, who will be MVP?"
The Fundamental Rule:
1 Collateral = Ξ£(All Outcome Tokens)
When you split 1 USDC in a YES/NO market:
- You receive 1 YES token + 1 NO token
- You can merge 1 YES + 1 NO back into 1 USDC anytime
Outcome tokens can become collateral for new markets:
USDC
βββ TRUMP_WINS
β βββ FIRES_CHAIR
β βββ KEEPS_CHAIR
βββ TRUMP_LOSES
Works with any oracle system:
- Switchboard Functions
- Pyth Price Feeds
- Multisig DAOs
- Reality.eth Bridge
All operations preserve the CTF invariants:
- No loss property for liquidity providers
- Deterministic position IDs
- Atomic split/merge operations
| Feature | Gnosis (EVM) | This Implementation (Solana) |
|---|---|---|
| Token Standard | ERC-1155 (multi-token) | SPL Token (separate mints) |
| Collateral Storage | Single contract | PDA vault per condition |
| Position IDs | Hash-based uint256 | Separate Mint accounts |
| Mint Authority | N/A | Program-controlled PDA |
| Account Model | Storage slots | Account-based |
pub struct Condition {
pub oracle: Pubkey, // Authorized resolver
pub question_id: [u8; 32], // Unique question identifier
pub outcome_slot_count: u8, // Number of outcomes (2-256)
pub is_resolved: bool, // Resolution status
pub payout_numerators: Vec<u64>, // Payout distribution
pub condition_id: [u8; 32], // Deterministic ID
}Holds collateral for each condition:
Seeds: [b"vault", condition, collateral_mint]
Controls minting of outcome tokens:
Seeds: [b"mint-authority", condition]
# Clone the repository
git clone <your-repo-url>
cd conditional-tokens-solana
# Install dependencies
yarn install
# Build the program
anchor build
# Run tests
anchor testimport { ConditionalTokensClient, PartitionHelper } from "./sdk/client";
import * as anchor from "@coral-xyz/anchor";
const provider = anchor.AnchorProvider.env();
const program = anchor.workspace.ConditionalTokens;
const client = new ConditionalTokensClient(program, provider);
// 1. Prepare a condition
const { conditionPda } = await client.prepareCondition(
oracleKeypair.publicKey,
Buffer.from("Will ETH hit $10k in 2025?".padEnd(32, "\0")),
2 // Binary market
);
// 2. Split USDC into YES/NO tokens
await client.splitPosition({
user: user.publicKey,
condition: conditionPda,
collateralMint: usdcMint,
outcomeMints: [yesMint, noMint],
amount: new BN(1_000_000), // 1 USDC
partition: PartitionHelper.binaryPartition(),
userSigner: userKeypair,
});
// 3. Merge back to collateral
await client.mergePositions({
user: user.publicKey,
condition: conditionPda,
collateralMint: usdcMint,
outcomeMints: [yesMint, noMint],
amount: new BN(500_000), // 0.5 USDC worth
partition: PartitionHelper.binaryPartition(),
userSigner: userKeypair,
});
// 4. Oracle resolves the market
await client.reportPayout(
conditionPda,
[new BN(0), new BN(1)], // YES wins 100%
oracleKeypair
);
// 5. Redeem winning positions
await client.redeemPositions({
user: user.publicKey,
condition: conditionPda,
collateralMint: usdcMint,
outcomeMints: [yesMint],
indexSets: [PartitionHelper.outcomeToIndexSet(1)], // YES = index 1
amount: new BN(1_000_000),
userSigner: userKeypair,
});- Implementation Guide - Deep dive into CTF mechanics, deep splits, and architecture
- API Reference - Complete SDK documentation
- Examples - Working examples including deep splits
See tests/conditional-tokens.ts for a complete example.
See examples/deep_splits.ts for a demonstration of combinatorial markets.
Run it:
ts-node examples/deep_splits.tsimport { PartitionHelper } from "./sdk/client";
// Binary partition
const binary = PartitionHelper.binaryPartition(); // [0b01, 0b10]
// N-outcome partition
const ternary = PartitionHelper.fullPartition(3); // [0b001, 0b010, 0b100]
// Validate partition
const isValid = PartitionHelper.validatePartition([0b01, 0b10], 2); // true
// Convert between formats
const indexSet = PartitionHelper.outcomeToIndexSet(0); // 0b01
const outcomes = PartitionHelper.indexSetToOutcomes(0b101); // [0, 2]- Pending security audit
- Fuzzing tests in progress
- Formal verification planned
- Mint Authority Protection: Program-controlled PDAs prevent unauthorized minting
- Vault Isolation: Each condition has separate vault to prevent cross-contamination
- Integer Overflow Protection: All arithmetic uses checked operations
- Reentrancy Prevention: Anchor's account constraints + burn-before-transfer pattern
- Maximum 256 outcomes per condition (bitmask limit)
- No built-in AMM (integrate with Orca/Raydium separately)
- Resolution is final (no dispute mechanism)
- Binary (YES/NO) questions
- Multiple choice questions
- Continuous variable ranges
- Tournament brackets
- Sequential events
- Correlated outcomes
- Options on prediction positions
- Portfolio insurance
- Structured products
- Use outcome tokens as collateral in lending protocols
- Create liquidity pools for outcome tokens
- Synthetic assets based on predictions
conditional-tokens-solana/
βββ programs/
β βββ conditional-tokens/
β βββ src/
β β βββ lib.rs # Main program
β βββ Cargo.toml
βββ tests/
β βββ conditional-tokens.ts # Integration tests
βββ sdk/
β βββ client.ts # TypeScript SDK
βββ examples/
β βββ deep_splits.ts # Deep splits demo
βββ IMPLEMENTATION_GUIDE.md # Technical documentation
βββ README.md
# Run all tests
anchor test
# Run specific test
anchor test --skip-build -- --grep "splits collateral"
# Run with logs
anchor test -- --show-logs# Build program
anchor build
# Deploy to devnet
anchor deploy --provider.cluster devnet
# Upgrade program
anchor upgrade target/deploy/conditional_tokens.so --program-id <PROGRAM_ID>| Operation | Compute Units | Approx. SOL Cost |
|---|---|---|
| Prepare Condition | ~20,000 | 0.0001 SOL |
| Split Position | ~50,000 | 0.00025 SOL |
| Merge Positions | ~45,000 | 0.000225 SOL |
| Report Payout | ~15,000 | 0.000075 SOL |
| Redeem Positions | ~40,000 | 0.0002 SOL |
Note: Actual costs vary based on network congestion and number of outcomes
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch
- Add tests for new functionality
- Ensure all tests pass
- Submit a pull request
This project is licensed under Apache License 2.0.
- Gnosis for the original Conditional Tokens Framework
- Solana Foundation for Anchor and tooling
- GitHub Issues: Create an issue
- Core CTF mechanics (split/merge)
- Deep splits support
- Oracle-agnostic resolution
- TypeScript SDK
- Security audit
- AMM integration examples
- Liquidation mechanism
- Cross-chain bridges (Wormhole)
- UI/UX dashboard
- Mainnet deployment
Built with β€οΈ on Solana