Sol.College

Full lesson

solana_prediction_market

What it does

From the project README:

You can use any normal anchor commands. Either move to the `anchor` directory and run the `anchor` command or prefix the command with `npm run`, eg: `npm run anchor`.
Original
chappie1998/solana_prediction_market
SuperStack fork
Blockchains/solana_prediction_market @ 2508aa7
Stars
1
Last push (original)
2024-10-08
Languages
TypeScript, Rust, JavaScript, CSS
Detected stack
AnchorNext.jsweb3.js
Categories
Other
Licence
MIT

Architecture

47 source files. By extension: .ts ×21, .tsx ×20, .js ×5, .rs ×1.

Top-level directorySource files
web38
anchor7
(root)2

On-chain programs: anchor/programs/prediction-market

Dapp: deploying

This fork is queued for its own live dapp on Sol.College, with a Devnet/Mainnet switch. It appears here, at /dapps/solana-prediction-market/, once it is deployed and checked on devnet. Until then, run it locally with the commands below.

Key code, explained

Excerpts chosen automatically where the code uses the most Solana concepts, pinned to the fork's commit.

chappie1998/solana_prediction_market · anchor/programs/prediction-market/src/lib.rs L49–72 @ 2508aa7 · MIT · original
        // let yes_compressed_token_ = create_create_token_pool_instruction(ctx.accounts.owner.key, &pool.yes_token_mint);        // let no_compressed_token_ = create_create_token_pool_instruction(ctx.accounts.owner.key, &pool.yes_token_mint);        // let cpi_program = ctx.accounts.compressed_token_program.to_account_info();        // let seeds = &[        //     pool.to_account_info().key.as_ref(),        //     &[pool.bump],        // ];        // let signer = &[&seeds[..]];        // let cpi_ctx = CpiContext::new_with_signer(cpi_program, yes_compressed_token_.accounts, signer);         Ok(())    }     /// Vote in a prediction pool    /// Users can vote YES or NO by transferring USDT and receiving corresponding tokens    pub fn vote(ctx: Context<Vote>, amount: u64, vote_yes: bool) -> Result<()> {        let pool = &mut ctx.accounts.pool;        let current_timestamp = Clock::get()?.unix_timestamp;        // Check if the pool is active and within the voting timeframe        require!(current_timestamp <= pool.end_time, PredictionMarketError::PoolEnded);        require!(current_timestamp >= pool.start_time, PredictionMarketError::PoolNotStarted);        require!(pool.status == PoolStatus::Active, PredictionMarketError::PoolNotActive);         // Verify the pool signer
  1. Line 52 // let seeds = &[: Declares the PDA seeds. Anchor re-derives the address and rejects the account if it doesn't match.
  2. Line 54 // &[pool.bump],: Uses the bump seed, the extra byte that pushes the derived address off the ed25519 curve.
  3. Line 57 // let cpi_ctx = CpiContext::new_with_signer(cpi_program, yes_compressed_token_.accounts, : Makes a CPI signed by a PDA. The signer seeds prove the program controls that address.
  4. Line 66 let current_timestamp = Clock::get()?.unix_timestamp;: Reads on-chain time from the Clock sysvar.
  5. Line 68 require!(current_timestamp <= pool.end_time, PredictionMarketError::PoolEnded);: An explicit validation that aborts the instruction with an error.
chappie1998/solana_prediction_market · web/app/api/createPool.ts L13–36 @ 2508aa7 · MIT · original
 export const createPool = async (  program: Program<PredictionMarket>,  payer: WalletContextState,  predictionMarketPubkey: PublicKey  // startTime: number,  // endTime: number): Promise<string> => {  const startTime = Math.floor(Date.now() / 1000); // Current time in seconds  const endTime = startTime + 60; // End time 1 hour from now   if (!payer.publicKey) {    throw new Error('Wallet not connected');  }  // Generate a new pool ID  const poolId = Buffer.from(Keypair.generate().publicKey.toBytes()).toJSON()    .data;   // const [poolPubkey] = await findProgramAddress(  //   [Buffer.from('pool'), Buffer.from(poolId)],  //   program.programId  // );   const [poolPubkey, bump] = await findProgramAddress(
  1. Line 31 // const [poolPubkey] = await findProgramAddress(: Derives a PDA from seeds and the program ID and returns the address with its canonical bump.
  2. Line 36 const [poolPubkey, bump] = await findProgramAddress(: Uses the bump seed, the extra byte that pushes the derived address off the ed25519 curve.
chappie1998/solana_prediction_market · web/app/api/vote.ts L25–48 @ 2508aa7 · MIT · original
  );  const poolUsdtAccount = await getAssociatedTokenAddress(    usdtMint,    poolPubkey,    true  );  const userYesTokenAccount = await getAssociatedTokenAddress(    new PublicKey(pool.yesTokenMint),    payer.publicKey  );  const userNoTokenAccount = await getAssociatedTokenAddress(    new PublicKey(pool.noTokenMint),    payer.publicKey  );   const [poolSigner] = await findProgramAddress(    [Buffer.from("pool"), Buffer.from(pool.id)],    PREDICTION_MARKET_PROGRAM_ID  );  // , Buffer.from([pool.bump])   // Check if accounts exist and create them if they don't  const accountsToCheck = [    { address: poolUsdtAccount, mint: usdtMint, owner: poolPubkey },
  1. Line 40 const [poolSigner] = await findProgramAddress(: Derives a PDA from seeds and the program ID and returns the address with its canonical bump.
  2. Line 44 // , Buffer.from([pool.bump]): Uses the bump seed, the extra byte that pushes the derived address off the ed25519 curve.

How to run, build and test

These commands come from the repo's own manifests (package.json scripts, Anchor.toml, Cargo, go.mod, Makefile). Check the README for prerequisites and environment variables.

DirectoryCommandRuns
.npm run devnx serve web
.npm run buildnx build web
anchoranchor buildcompile programs and generate IDLs
anchoranchor testlocal validator + test suite
anchoranchor run test../node_modules/.bin/nx run anchor:jest

What you could build from it

Used in lessons