Skip to content

whoisasx/cinefi-contract

Repository files navigation

Cinefi

A decentralized prediction market protocol on Solana where users bet on media ratings β€” movies, shows, or any scored content. Built with the Anchor framework.

Program ID: GomtSs5546sx4NQFsGaJtwFrDytfqRQPBADkiUr7PcyW


πŸš€ Quick Navigation

Choose based on what you're building:

Goal Resource
Building a frontend/app β†’ See TypeScript SDK section
Understanding the protocol β†’ See How It Works section
Running Rust program locally β†’ See Getting Started section
Deploying to Solana β†’ See Deploy (Localnet) section
Full SDK API Reference β†’ See app/contract/README.md

TypeScript SDK

The easiest way to interact with Cinefi is through the TypeScript SDK. It provides type-safe wrappers for all 8 program instructions, account fetching, validation, and utility functions.

πŸ“ SDK Location

cinefi/
└── app/
    └── contract/          ← TypeScript SDK is here
        β”œβ”€β”€ README.md      ← Full SDK documentation (1600+ lines)
        β”œβ”€β”€ index.ts       ← Main entry point
        β”œβ”€β”€ pdas/
        β”œβ”€β”€ constants/
        β”œβ”€β”€ errors/
        β”œβ”€β”€ types/
        β”œβ”€β”€ utils/
        β”œβ”€β”€ accounts/
        └── instructions/

⚑ Quick Start (SDK)

import CinefiSDK, {
	createMarketAndSend,
	placeBetAndSend,
} from "./app/contract";
import { Connection, Keypair } from "@solana/web3.js";
import { Wallet } from "@coral-xyz/anchor";

// 1. Initialize connection & SDK
const connection = new Connection("https://api.devnet.solana.com");
const wallet = new Wallet(Keypair.generate());
const sdk = new CinefiSDK({ connection, wallet });

// 2. Create a market
const txId = await createMarketAndSend(sdk.program, creator, {
	mediaId: 12345n,
	radius: 5,
	oracleSet: [oracle1, oracle2, oracle3],
	oracleThreshold: 2,
});

// 3. Place a bet
const betTxId = await placeBetAndSend(sdk.program, bettor, {
	mediaId: 12345n,
	bucket: 75,
	amount: 1_000_000_000n, // 1 SOL
});

πŸ“– Full SDK Documentation

For complete API reference, environment setup, oracle management, constraint documentation, error handling, and advanced workflows, see:

πŸ‘‰ app/contract/README.md (1600+ lines, covers everything)

SDK Features:

  • βœ… Type-safe instruction builders (8 instructions)
  • βœ… PDA derivation for all account types (5 PDAs)
  • βœ… Account fetching & parsing (6 methods)
  • βœ… 27 custom error codes with parsing
  • βœ… Validation helpers (bucket, amount, threshold)
  • βœ… State checking (betting open? can claim? etc)
  • βœ… Conversion utilities (SOL ↔ lamports, time multipliers)
  • βœ… Time management (decay multipliers, deadline checks)
  • βœ… Complete constraint documentation

πŸ”§ SDK Usage in Your Project

// ESM import
import CinefiSDK from "./app/contract";

// or CommonJS
const CinefiSDK = require("./app/contract");

// Environment setup required
import dotenv from "dotenv";
dotenv.config();

// Load keys from .env
const walletSecret = process.env.WALLET_SECRET_KEY;
const oracle1Secret = process.env.ORACLE_1_SECRET_KEY;
const oracle2Secret = process.env.ORACLE_2_SECRET_KEY;
const oracle3Secret = process.env.ORACLE_3_SECRET_KEY;

See app/contract/README.md - Environment Configuration for complete setup.


Table of Contents


Program Overview

Cinefi lets anyone create a prediction market tied to a media item (identified by media_id). Participants bet SOL on a score bucket between 1 and 100 β€” representing their prediction of the media's final score. A set of trusted oracles submits the real-world score after the betting window closes. Winners β€” those who bet within a configurable radius of the final score β€” share the prize pool, weighted by how close their bucket is to the outcome and how early they placed their bet.

Key Features:

  • Decentralized Oracle System - 3 oracles provide consensus on outcomes
  • Time-Weighted Betting - Early bettors earn higher multipliers (1.0x β†’ 0.272x over 14 days)
  • Proximity-Based Rewards - Winners closer to the actual outcome earn more
  • Automatic Fee Distribution - 3% protocol fee, customizable creator fees
  • Fallback Mechanism - If no one is in the winning radius, the closest bucket wins
  • Permissionless - Anyone can create markets, place bets, or claim rewards

How It Works

Market Lifecycle

Each market moves through a strict sequential set of phases enforced on-chain:

[Create] β†’ [Betting Open] β†’ [Betting Closed] β†’ [Oracle Window] β†’ [Resolved] β†’ [Claims] β†’ [Reclaimed]
Phase Duration Description
Betting Open 14 days Users place SOL bets on any bucket 1–100
Betting Closed Day 15–21 No new bets; oracle window approaches
Oracle Window 1 hour (at Day 21) Oracles submit their score observations
Resolution After Day 21 Anyone can trigger resolve_market once oracles finalize
Claim Window 14 days after resolution Winners claim their SOL payout
Reclaim After claim deadline Unclaimed SOL is swept to the treasury

A market is created with an optional betting_starts_after delay, allowing the creator to schedule when betting opens.


Scoring & Buckets

The score space is divided into 100 buckets (1–100). Each bucket represents a predicted score. For example:

  • Bucket 74 = predicting a score of 74/100
  • Bucket 50 = predicting a score of 50/100

The radius parameter (set at market creation) defines the winning range. If radius = 5 and the final score is 72, then any bettor in buckets 67–77 is a winner.


Time-Weighted Betting

To incentivize early participation, bets are multiplied by a time-decay multiplier based on when the bet is placed relative to the betting start date.

Day Multiplier (Γ—1000 scale) Effective Weight
1 1000 1.000Γ—
2 904 0.904Γ—
3 818 0.818Γ—
4 740 0.740Γ—
5 670 0.670Γ—
6 606 0.606Γ—
7 548 0.548Γ—
8 496 0.496Γ—
9 449 0.449Γ—
10 406 0.406Γ—
11 367 0.367Γ—
12 332 0.332Γ—
13 301 0.301Γ—
14 272 0.272Γ—

The weighted amount is stored alongside the raw amount in both the Market pool arrays and the user's UserPosition. Prize payouts are computed using weighted amounts, so early bettors earn a proportionally larger share.

Formula:

weighted_amount = (amount Γ— TIME_MULTIPLIERS[day_index]) / 1000

Oracle System

Each market is created with an oracle_set of exactly 3 oracle public keys and an oracle_threshold (must be 2 or 3).

During the oracle window (starting at the settlement timestamp, open for 1 hour):

  1. Each oracle in the set calls submit_score with their observed score (1–100).
  2. After oracle_threshold submissions agree on a score, the report is marked finalized.
  3. If oracles disagree and cannot reach consensus, the report is marked disputed β€” blocking resolution.

The OracleReport PDA tracks all submissions and their agreement state.


Prize Distribution

When resolve_market is called:

  1. A protocol fee of 3% (300 bps) is transferred from the vault to the treasury.
  2. The remaining total_prize_pool is distributed across winning buckets using a two-factor weighting:

Factor 1 β€” Time Weight: Each individual bettor's share within their bucket is proportional to their weighted_amount (early bettors get more).

Factor 2 β€” Closeness Weight: Each winning bucket's share of the total prize pool is proportional to a closeness function:

closeness_weight(bucket) = 1_000_000 / (|bucket - final_outcome| + 1)

This means a bucket exactly at the final score gets the maximum share, buckets one step away get half, and so on.

Total Bucket Weight (TBW):

TBW = Ξ£ (closeness_weight(bucket_i) Γ— weighted_pool[bucket_i])   for all winning buckets i

Bucket Prize:

bucket_prize[i] = (closeness_weight(bucket_i) Γ— weighted_pool[i] Γ— total_prize_pool) / TBW

Individual Payout:

user_payout = (user.weighted_amount / weighted_pool[user.bucket]) Γ— bucket_prize[user.bucket]

Fallback Mechanism

If no bets exist within the radius of the final score, the protocol falls back gracefully:

  • The winner(s) are determined by finding the minimum distance from the final score across all filled buckets.
  • All bettors at that minimum distance are treated as winners.
  • The normal closeness-weighted distribution then applies among those fallback buckets.

This guarantees the prize pool is always distributed rather than locked.


Program Instructions

initialize_treasury

Creates the global treasury PDA. This must be called once before any markets can be resolved.

Accounts:

Account Type Description
authority Signer (mut) Pays for account initialization
treasury UncheckedAccount (init) Global treasury PDA
system_program Program Solana System Program

create_market

Creates a new prediction market for a media item.

Parameters:

Parameter Type Description
betting_starts_after Option<i64> Seconds delay before betting opens (default: 0)
media_id u64 Unique identifier for the media title
radius u8 Number of buckets on each side of the outcome considered a win
oracle_set [Pubkey; 3] Exactly 3 oracle public keys
oracle_threshold u8 Minimum agreeing oracles to finalize (must be 2 or 3)

Accounts:

Account Type Description
creator Signer (mut) Market creator; pays for all PDAs
market Account (init) Market state PDA
vault UncheckedAccount (init) Lamport vault for this market
oracle_report Account (init) Oracle submission tracking PDA
system_program Program Solana System Program

Timeline set at creation:

betting_starts_at  = now + betting_starts_after
betting_closes_at  = betting_starts_at + 14 days
settle_at          = betting_closes_at + 7 days  (day 21 total)
claim_deadline     = settle_at + 14 days

place_bet

Places a SOL bet on a score bucket for a given market.

Parameters:

Parameter Type Description
bucket u8 Score prediction (1–100)
amount u64 Lamports to stake (must be > 0)

Accounts:

Account Type Description
user Signer (mut) Bettor; lamports source
market Account (mut) Target market
user_position Account (init_if_needed) Tracks user's bet for this bucket
vault UncheckedAccount (mut) Receives the lamports
system_program Program Solana System Program

Behavior:

  • Transfers amount lamports from user to the market vault.
  • Calculates weighted_amount using the time-decay multiplier for the current day.
  • Updates market.pool[bucket], market.weighted_pool[bucket], and market.total_pool.
  • Initializes or updates the user's UserPosition for this market+bucket combination.
  • A user can add to an existing position in the same bucket by calling place_bet again; their amount and weighted_amount accumulate.

close_market

Closes the betting window. Can be called by anyone once betting_closes_at has passed.

Accounts:

Account Type Description
caller Signer (mut) Any signer (permissionless)
market Account (mut) Target market

submit_score

Called by each oracle to submit their observed score. Only executable during the 1-hour oracle window starting at settle_at.

Parameters:

Parameter Type Description
score u8 Oracle's observed score (1–100)

Accounts:

Account Type Description
oracle_signer Signer (mut) Must be in the market's oracle_set
market Account Target market
oracle_report Account (mut) Oracle submission state
system_program Program Solana System Program

Finalization logic:

  • If oracle_threshold oracles agree on the same score β†’ finalized = true, agreed_score is set.
  • If all 3 oracles submit but no threshold of agreement is reached β†’ disputed = true.
  • A disputed report blocks market resolution.

resolve_market

Resolves the market using the finalized oracle score, distributes the protocol fee, and computes per-bucket prize amounts. Can be called by anyone once settle_at has passed and the oracle report is finalized.

Accounts:

Account Type Description
caller Signer (mut) Any signer (permissionless)
market Account (mut) Target market
oracle_report Account Must be finalized and not disputed
vault UncheckedAccount (mut) Market lamport vault
treasury UncheckedAccount (mut) Protocol treasury (receives 3% fee)
system_program Program Solana System Program

claim_reward

Allows a winning user to claim their SOL payout. Must be called before claim_deadline. The UserPosition account is closed and rent is returned to the user on claim.

Accounts:

Account Type Description
user Signer (mut) Winner claiming their reward
market Account Resolved market
user_position Account (mut, close=user) User's bet record (closed on success)
vault UncheckedAccount (mut) Source of payout lamports
system_program Program Solana System Program

Validation:

  • Market must be resolved.
  • Claim deadline must not have passed.
  • User's bucket must be within the winning radius (or fallback set).
  • Position must not have been previously claimed.

reclaim_pool

After the claim_deadline has passed, sweeps all remaining lamports in the vault to the treasury. This handles unclaimed winnings and any dust. Can be called by anyone.

Accounts:

Account Type Description
caller Signer (mut) Any signer (permissionless)
market Account (mut) Must be resolved; claim deadline passed
vault UncheckedAccount (mut) Remaining market lamports
treasury UncheckedAccount (mut) Protocol treasury (receives everything)
system_program Program Solana System Program

Account Architecture

Market Account

The core on-chain state for a prediction market. Derived from ["market_seed", media_id_le_bytes].

Field Type Description
media_id u64 Unique ID of the media item
creator Pubkey Market creator's public key
created_at i64 Unix timestamp of creation
betting_starts_at i64 When betting opens
betting_closes_at i64 When betting closes (14 days after open)
settle_at i64 Oracle settlement time (day 21)
claim_deadline i64 Last date to claim rewards
radius u8 Winning bucket radius around final score
protocol_fee_bps u16 Protocol fee in basis points (300 = 3%)
creator_fee_bps u16 Creator fee in basis points (currently 0)
oracle_set [Pubkey; 3] Authorized oracle public keys
oracle_threshold u8 Minimum agreeing oracles for finalization
pool [u64; 101] Raw lamport totals per bucket (index 1–100)
weighted_pool [u64; 101] Time-weighted totals per bucket
total_pool u64 Total raw lamports staked
total_prize_pool u64 Total after protocol fee deduction
final_outcome u8 Resolved score (set after resolution)
bucket_prize [u64; 101] Lamport prize allocated to each winning bucket
fallback_used bool Whether fallback distribution was applied
resolved bool Has the market been resolved
closed bool Has the betting window been closed
reclaimed bool Has unclaimed pool been swept to treasury
bump u8 PDA bump seed

OracleReport Account

Tracks oracle submissions for a market. Derived from ["oracle_report_seed", market_pubkey].

Field Type Description
market Pubkey Parent market public key
submissions [(Pubkey, u8); 3] Each oracle's (pubkey, submitted_score)
submission_count u8 Number of submissions so far
agreed_score u8 Consensus score (set when finalized)
finalized bool Threshold consensus reached
disputed bool Oracles disagree; cannot resolve
bump u8 PDA bump seed

UserPosition Account

Records a single user's bet in a specific bucket for a market. Derived from ["position_seed", user_pubkey, market_pubkey, bucket_byte].

Field Type Description
user Pubkey Bettor's public key
market Pubkey Market public key
bucket u8 The score bucket they bet on
amount u64 Total raw lamports staked in this bucket
weighted_amount u64 Total time-weighted lamports
claimed bool Whether the reward has been claimed
bump u8 PDA bump seed

A user can hold at most one UserPosition per (market, bucket) pair but may have positions across different buckets or different markets simultaneously.


Vault (PDA)

A lamport-only account that holds all SOL staked in a market. Derived from ["vault_seed", market_pubkey]. The program uses PDA signer seeds to authorize transfers out of the vault.


Treasury (PDA)

The global protocol treasury. Derived from ["treasury_seed"]. Receives:

  • 3% protocol fee on every market resolution.
  • All unclaimed funds after the claim deadline via reclaim_pool.

PDA Seeds

Account Seeds
Market b"market_seed" || media_id.to_le_bytes()
Vault b"vault_seed" || market.key()
OracleReport b"oracle_report_seed" || market.key()
UserPosition b"position_seed" || user.key() || market.key() || [bucket]
Treasury b"treasury_seed"

Protocol Constants

Constant Value Description
BETTING_DURATION_DAYS 14 days Length of the betting window
SETTLEMENT_DAY Day 21 Oracle settlement deadline
CLAIM_WINDOW_DAYS 14 days Time after resolution to claim
ORACLE_WINDOWS_START_SECONDS 0 s Oracle window starts at settle_at
ORACLE_WINDOWS_CLOSE_SECONDS 3600 s (1 hr) Oracle window closes 1 hour after settle_at
DEFAULT_PROTOCOL_FEE_BPS 300 (3%) Protocol fee on total pool
DEFAULT_RADIUS 5 Default winning radius
MAX_ORACLE_SIGNER 3 Maximum oracles per market
MAX_BUCKETS 101 Total bucket slots (index 0 unused; 1–100 valid)
MULTIPLIER_SCALE 1000 Denominator for time multiplier division
CLOSENESS_SCALE 1,000,000 Numerator for closeness weight computation

Error Codes

Error Description
MarketAlreadyClosed Market is already in closed state
MarketNotClosed Market has not been closed yet
MarketAlreadyResolved Market resolution already happened
MarketNotResolved Market has not been resolved yet
MarketAlreadyClaimed Vault has already been reclaimed
BettingNotStarted Betting window has not opened yet
BettingClosed The betting window has ended
BettingStillOpen Betting window is still active
SettlementNotReady settle_at timestamp not yet reached
SettlementTimeInvalid Invalid settlement time provided
ClaimDeadlinePassed The claim deadline has passed
ClaimDeadlineNotPassed Claim deadline has not passed yet (for reclaim)
OracleWindowClosed Oracle submission window is not currently open
UnauthorizedOracle Signer is not in the market's oracle set
InvalidOracleThreshold Threshold must be 2 or 3
OracleAlreadyFinalized Oracle report is already finalized
OracleNotFinalized Oracle report has not been finalized
OracleAlreadySubmitted This oracle already submitted a score
OracleDisputed Oracles could not reach consensus
InvalidBucket Bucket must be between 1 and 100
InvalidAmount Bet amount must be greater than zero
AlreadyClaimed User has already claimed their reward
InsufficientClaimAmount Computed payout is zero
NotAWinner User's bucket is outside the winning range
Unauthorized Signer does not own the position account
MathOverflow Arithmetic overflow during calculation

Project Structure

cinefi/
β”œβ”€β”€ Anchor.toml                    # Anchor workspace config
β”œβ”€β”€ Cargo.toml                     # Workspace Cargo manifest
β”œβ”€β”€ package.json                   # Node.js dependencies (tests + SDK)
β”œβ”€β”€ tsconfig.json                  # TypeScript config
β”œβ”€β”€ README.md                       # This file
β”‚
β”œβ”€β”€ app/
β”‚   └── contract/                  # πŸš€ TypeScript SDK (use this for frontend!)
β”‚       β”œβ”€β”€ README.md              # Complete SDK documentation (1600+ lines)
β”‚       β”œβ”€β”€ index.ts               # SDK entry point
β”‚       β”œβ”€β”€ pdas/index.ts          # 5 PDA derivation functions
β”‚       β”œβ”€β”€ constants/index.ts     # Protocol constants
β”‚       β”œβ”€β”€ errors/index.ts        # 27 error codes + parsing
β”‚       β”œβ”€β”€ types/index.ts         # TypeScript type definitions
β”‚       β”œβ”€β”€ utils/index.ts         # Validation, conversion, state functions
β”‚       β”œβ”€β”€ accounts/index.ts      # Account fetching methods
β”‚       └── instructions/          # 8 instruction modules
β”‚           β”œβ”€β”€ initialize-treasury.ts
β”‚           β”œβ”€β”€ create-market.ts
β”‚           β”œβ”€β”€ place-bet.ts
β”‚           β”œβ”€β”€ close-market.ts
β”‚           β”œβ”€β”€ submit-score.ts
β”‚           β”œβ”€β”€ resolve-market.ts
β”‚           β”œβ”€β”€ claim-reward.ts
β”‚           └── reclaim-pool.ts
β”‚
β”œβ”€β”€ programs/
β”‚   └── cinefi/                    # Rust Anchor program
β”‚       β”œβ”€β”€ Cargo.toml
β”‚       └── src/
β”‚           β”œβ”€β”€ lib.rs             # Program entrypoint & instruction dispatch
β”‚           β”œβ”€β”€ errors/
β”‚           β”‚   └── mod.rs         # All custom error codes (27 total)
β”‚           β”œβ”€β”€ instructions/
β”‚           β”‚   β”œβ”€β”€ mod.rs
β”‚           β”‚   β”œβ”€β”€ initialize_treasury.rs
β”‚           β”‚   β”œβ”€β”€ create_market.rs
β”‚           β”‚   β”œβ”€β”€ place_bet.rs
β”‚           β”‚   β”œβ”€β”€ close_market.rs
β”‚           β”‚   β”œβ”€β”€ submit_score.rs
β”‚           β”‚   β”œβ”€β”€ resolve_market.rs
β”‚           β”‚   β”œβ”€β”€ claim_reward.rs
β”‚           β”‚   └── reclaim_pool.rs
β”‚           β”œβ”€β”€ states/
β”‚           β”‚   β”œβ”€β”€ mod.rs
β”‚           β”‚   β”œβ”€β”€ constants.rs   # Protocol-wide constants & seeds
β”‚           β”‚   β”œβ”€β”€ market.rs      # Market account definition
β”‚           β”‚   β”œβ”€β”€ oracle_report.rs
β”‚           β”‚   └── user_position.rs
β”‚           └── utils/
β”‚               β”œβ”€β”€ mod.rs
β”‚               β”œβ”€β”€ validations.rs # is_winner, oracle checks
β”‚               └── weights.rs     # Time multipliers, weights, prize computation
β”‚
β”œβ”€β”€ tests/
β”‚   └── cinefi.ts                  # Integration tests
β”‚
β”œβ”€β”€ migrations/
β”‚   └── deploy.ts
β”‚
└── target/
    β”œβ”€β”€ idl/
    β”‚   └── cinefi.json            # Generated IDL
    └── types/
        └── cinefi.ts              # Generated TypeScript types

Getting Started (Development)

If you want to use Cinefi in your app, use the TypeScript SDK instead (much easier!).

If you want to develop or test the Solana program itself, follow these steps:

Prerequisites

Verify versions:

rustc --version
solana --version
anchor --version
node --version

Note: For SDK usage only (no program development), you only need Node.js.

Install Dependencies

# Install Rust/Solana dependencies
rustup update solana
cargo build -p cinefi

# Install Node dependencies
yarn install
# or
npm install

Build the Program

# Build all programs
anchor build

# Build specific program
cargo build -p cinefi --release

Output:

  • Binaries: target/release/cinefi.so
  • IDL: target/idl/cinefi.json
  • TypeScript types: target/types/cinefi.ts

Run Tests

Start a local validator and run the test suite:

# Start Solana localnet (in one terminal)
solana-test-validator

# In another terminal, run tests
anchor test

# Or run specific test file
anchor test --skip-local-validator

What tests cover:

  • βœ… All 8 program instructions
  • βœ… Market lifecycle (create β†’ bet β†’ resolve β†’ claim)
  • βœ… Oracle consensus logic
  • βœ… Prize distribution calculations
  • βœ… Error cases and validation
  • βœ… Edge cases (fallback, overflow, etc)

Deploy (Localnet)

# Start local validator
solana-test-validator

# Deploy program (in another terminal)
anchor deploy

# Program deployed to:
# GomtSs5546sx4NQFsGaJtwFrDytfqRQPBADkiUr7PcyW

Before creating markets, initialize treasury:

import { Program, AnchorProvider, Wallet } from "@coral-xyz/anchor";
import { Connection, Keypair } from "@solana/web3.js";

const connection = new Connection("http://localhost:8899");
const wallet = new Wallet(Keypair.generate());
const provider = new AnchorProvider(connection, wallet, {});
const program = new Program(IDL, PROGRAM_ID, provider);

await program.methods
	.initializeTreasury()
	.accounts({ authority: wallet.publicKey })
	.rpc();

Development: Program vs SDK

Building a Frontend/App

Use the TypeScript SDK (in /app/contract/):

// Simple!
import CinefiSDK, { placeBetAndSend } from "./app/contract";

const sdk = new CinefiSDK({ connection, wallet });
await placeBetAndSend(sdk.program, user, {
	mediaId: 123n,
	bucket: 75,
	amount: 1_000_000_000n,
});

Why SDK?

  • Type-safe (full TypeScript support)
  • Handles serialization & deserialization
  • Built-in validation & error parsing
  • Utility functions (time multipliers, state checks, etc)
  • Complete documentation in app/contract/README.md
  • No need to understand Anchor internals

Modifying the Program (Advanced)

Edit Rust code (in /programs/cinefi/src/):

// Example: Add new instruction or modify existing
pub fn place_bet(ctx: Context<PlaceBet>, bucket: u8, amount: u64) -> Result<()> {
    // Your logic here
}

Then:

  1. Build: anchor build
  2. Tests: anchor test
  3. Deploy: anchor deploy
  4. SDK automatically regenerates from IDL

Why modify?

  • Changing protocol logic
  • Adding new features
  • Optimizing on-chain calculations
  • Fixing bugs in Rust code

Common Tasks

Task: Create a Web3 Frontend for Cinefi

Solution: Use the SDK

  1. Create Next.js/React app
  2. Import CinefiSDK from ./app/contract
  3. Follow examples in app/contract/README.md
  4. Done!

Example:

import CinefiSDK, { fetchMarket, getMarketState } from "./app/contract";

export default function MarketView({ mediaId }: { mediaId: bigint }) {
	const [market, setMarket] = useState(null);
	const [state, setState] = useState(null);

	useEffect(async () => {
		const m = await fetchMarket(sdk.program, mediaId);
		setMarket(m);
		setState(getMarketState(m!));
	}, []);

	return (
		<div>
			<h2>Market {mediaId}</h2>
			<p>Betting Open: {state?.canBet ? "Yes" : "No"}</p>
			<p>Can Claim: {state?.canClaim ? "Yes" : "No"}</p>
		</div>
	);
}

Task: Run Cinefi Locally for Testing

Solution: Use localnet

# Terminal 1: Start local validator
solana-test-validator

# Terminal 2: Deploy program
anchor deploy

# Terminal 3: Run your tests
anchor test

See Run Tests and Deploy (Localnet) sections.

Task: Understand the Protocol Better

Solution: Read the docs

  1. Quick overview: This file (README.md)
  2. How markets work: Market Lifecycle
  3. Complete details: How It Works
  4. Using in code: app/contract/README.md
  5. Program internals: Program Instructions and Account Architecture

πŸ“š Comprehensive Resource Guide

For SDK Users (Frontend Developers)

Resource Purpose Link
SDK Setup Environment config, oracle keys, cluster connection app/contract/README.md - Setup
API Reference All 8 instructions, 5 PDAs, validation functions app/contract/README.md - API Reference
Complete Workflows Real market lifecycle examples app/contract/README.md - Workflows
Error Handling All 27 error codes, recovery patterns app/contract/README.md - Error Handling
Constraint Docs Time windows, amount limits, bucket rules app/contract/README.md - Constraints
Troubleshooting Connection issues, wallet errors, debugging app/contract/README.md - Troubleshooting

For Program Developers

Resource Purpose Link
Program Overview Instructions, accounts, logic Program Overview section (this file)
Market Lifecycle State transitions, timing Market Lifecycle section (this file)
Instructions Detailed specification of each instruction Program Instructions section (this file)
Accounts Data structures and field descriptions Account Architecture section (this file)
Constants Time values, fees, limits Protocol Constants section (this file)
Error Codes All 27 error codes with descriptions Error Codes section (this file)
Rust Code Implementation details /programs/cinefi/src/ directory

Key Files

File/Folder Purpose
app/contract/ πŸ”₯ Start here for frontend - TypeScript SDK
app/contract/README.md πŸ“– Complete SDK documentation (1600+ lines)
programs/cinefi/src/lib.rs Entry point for Rust program
programs/cinefi/src/instructions/ All 8 instruction implementations
programs/cinefi/src/states/ Account definitions
tests/cinefi.ts Integration tests (shows SDK usage)
target/idl/cinefi.json Generated IDL (shared between Rust & TS)

πŸš€ Getting Started Paths

Path 1: Build a Frontend App (Recommended for most)

1. Read: Quick Navigation β†’ TypeScript SDK section above
2. Setup: app/contract/README.md - Environment Configuration
3. Code: Import CinefiSDK and follow examples
4. Reference: app/contract/README.md - API Reference
5. Deploy: Use TestNet or MainNet

Time: 1-2 hours to basic working app

Path 2: Understand the Protocol

1. Read: Program Overview (this file)
2. Understand: Market Lifecycle & How It Works (this file)
3. Reference: Program Instructions & Account Architecture (this file)
4. Deep dive: Scroll to Error Codes & Constants (this file)
5. Code: Look at tests/cinefi.ts for real examples

Time: 2-3 hours of reading

Path 3: Modify the Program

1. Setup: Run Prerequisites through Deploy sections above
2. Understand: Program Instructions & Account Architecture (this file)
3. Modify: Edit code in programs/cinefi/src/
4. Build: cargo build -p cinefi
5. Test: anchor test (tests/ folder)
6. Deploy: anchor deploy
7. Regenerate: SDK regenerates from new IDL automatically

Time: Varies by change complexity

Path 4: Integrate with Existing App

1. Copy: app/contract/ folder to your project
2. Install: npm install @coral-xyz/anchor @solana/web3.js bn.js
3. Setup: Create .env with WALLET_SECRET_KEY and ORACLE_*_SECRET_KEY
4. Use: import CinefiSDK from "./app/contract"
5. Reference: app/contract/README.md for all possible operations

Time: 30 minutes


πŸ’‘ Architecture Summary

Three Layers

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Your Frontend App (React, Next.js, etc)β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€  ← Use TypeScript SDK here
β”‚  TypeScript SDK (app/contract/)         β”‚     Type-safe, easy to use
β”‚  - Instructions (8)                     β”‚     All examples provided
β”‚  - Account Fetching (6 methods)         β”‚
β”‚  - Validation (15+ helpers)             β”‚
β”‚  - Error Parsing (27 codes)             β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  Solana Blockchain                      β”‚  ← Program runs here
β”‚  Cinefi Program (programs/cinefi/)      β”‚     You don't interact directly
β”‚  - 8 Instructions                       β”‚
β”‚  - 5 Account Types                      β”‚
β”‚  - Oracle Consensus Logic               β”‚
β”‚  - Prize Distribution Math              β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  Solana Network (Devnet/Testnet/Mainnet)β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Data Flow

User Input
    ↓
TypeScript SDK validates
    ↓
SDK calls program instruction
    ↓
Program executes on blockchain
    ↓
Program updates accounts
    ↓
SDK fetches updated accounts
    ↓
Frontend displays results

You only write:

  • Frontend code
  • SDK usage in frontend

You don't write:

  • Blockchain code (already built)
  • Transaction serialization (SDK handles)
  • Account struct definitions (SDK handles)

πŸ“ž Support & References

Documentation Files

  • Main Docs: /README.md (this file) - Protocol overview
  • SDK Docs: /app/contract/README.md - Complete API reference & setup
  • IDL Docs: /target/idl/cinefi.json - Generated from Rust code

External Resources

Files to Study

To learn protocol:

  • programs/cinefi/src/lib.rs - Main logic
  • programs/cinefi/src/states/ - Data structures
  • tests/cinefi.ts - Real usage examples

To build frontend:

  • app/contract/README.md - Complete guide
  • app/contract/instructions/ - How each instruction works
  • app/contract/utils/index.ts - Utility functions

πŸ“‹ Checklist for Building an App


🎯 Next Steps

Immediate (Next 30 minutes)

  1. Read the Quick Navigation section above
  2. Check TypeScript SDK section for your use case
  3. Open app/contract/README.md in your editor

Short Term (Next 2 hours)

  1. Set up environment variables (.env file)
  2. Create a basic script that connects to SDK
  3. Run the Quick Start example
  4. Fetch a market and display its state

Medium Term (This week)

  1. Build core frontend features
  2. Study complete workflows
  3. Test on Devnet with real transactions
  4. Implement error handling

Long Term (Production)

  1. Comprehensive testing
  2. Security audit of your app
  3. Deploy to Testnet
  4. Deploy to Mainnet

πŸ“„ License

MIT


Questions? Check the comprehensive SDK docs: app/contract/README.md (1600+ lines covering everything)

About

movie rating prediction polymarket contract

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors