From 66619f5d1604052529dff2b543f045ba9a7aebc0 Mon Sep 17 00:00:00 2001 From: James <36777651+jbowa@users.noreply.github.com> Date: Sun, 12 May 2024 19:27:46 +0400 Subject: [PATCH] Transfer funds to escrow (#5) * Transfer bid to escrow --- src/consts.rs | 6 ++++-- src/instruction.rs | 10 +++++++--- src/lib.rs | 2 +- src/processor/bid.rs | 30 +++++++++++++++++++++++++----- src/processor/market.rs | 33 +++++++++++++++++++++++++++------ src/state/bid.rs | 4 +++- src/state/market.rs | 20 +++++++++++++++++--- 7 files changed, 84 insertions(+), 21 deletions(-) diff --git a/src/consts.rs b/src/consts.rs index 6ec881a..7b7d789 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -1,4 +1,6 @@ -// The seed for the market PDA. -pub const MARKET: &[u8] = b"market"; +// Escrow seed for PDA. +pub const ESCROW: &[u8] = b"escrow"; // The seed for the bid PDA. pub const BID: &[u8] = b"bid"; +// The seed for the market PDA. +pub const MARKET: &[u8] = b"market"; diff --git a/src/instruction.rs b/src/instruction.rs index 3ca7ca3..6f2893f 100644 --- a/src/instruction.rs +++ b/src/instruction.rs @@ -8,13 +8,15 @@ use shank::ShankInstruction; pub enum PithInstruction { #[account(0, name = "signer", desc = "Signer", signer)] #[account(1, name = "market", desc = "Pith market account", writable)] - #[account(2, name = "system_program", desc = "Solana System Program")] + #[account(2, name = "escrow", desc = "Escrow account", writable)] + #[account(3, name = "system_program", desc = "Solana System Program")] Market = 0, #[account(0, name = "signer", desc = "Signer", signer)] #[account(1, name = "market", desc = "Pith market account", writable)] - #[account(2, name = "bid", desc = "Bid account", writable)] - #[account(3, name = "system_program", desc = "Solana System Program")] + #[account(2, name = "escrow", desc = "Escrow account", writable)] + #[account(3, name = "bid", desc = "Bid account", writable)] + #[account(4, name = "system_program", desc = "Solana System Program")] Bid = 1, } @@ -24,6 +26,7 @@ pub struct MarketArgs { pub bump: u8, pub id: u64, pub title: String, + pub escrow_bump: u8, } #[repr(C)] @@ -31,5 +34,6 @@ pub struct MarketArgs { pub struct BidArgs { pub bump: u8, pub id: u64, + /// Bid amount in lamports. pub amount: u64, } diff --git a/src/lib.rs b/src/lib.rs index 43a9a48..503a385 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -33,7 +33,7 @@ pub fn process_instruction( .ok_or(ProgramError::InvalidInstructionData)?; match PithInstruction::try_from(*tag).or(Err(ProgramError::InvalidInstructionData))? { - PithInstruction::Market => process_market(program_id, accounts, data)?, + PithInstruction::Market => process_init_market(program_id, accounts, data)?, PithInstruction::Bid => process_bid(program_id, accounts, data)?, } diff --git a/src/processor/bid.rs b/src/processor/bid.rs index a8402d8..3db60df 100644 --- a/src/processor/bid.rs +++ b/src/processor/bid.rs @@ -1,7 +1,13 @@ use borsh::{BorshDeserialize, BorshSerialize}; use solana_program::{ - account_info::AccountInfo, borsh1::try_from_slice_unchecked, entrypoint::ProgramResult, msg, - program_error::ProgramError, pubkey::Pubkey, system_program, + account_info::AccountInfo, + borsh1::try_from_slice_unchecked, + entrypoint::ProgramResult, + program::invoke, + program_error::ProgramError, + pubkey::Pubkey, + system_instruction::{self}, + system_program, }; use crate::{ @@ -22,12 +28,25 @@ pub fn process_bid<'a, 'info>( let args = BidArgs::try_from_slice(data)?; // Load account data - let [signer, market_info, bid_info, system_program] = accounts else { + #[rustfmt::skip] + let [ + signer, + market_info, + escrow_info, + bid_info, + system_program + ] = accounts else { return Err(ProgramError::NotEnoughAccountKeys); }; let mut market_data = try_from_slice_unchecked::(&market_info.data.borrow())?; + // Transfer bid amount to escrow. + invoke( + &system_instruction::transfer(signer.key, escrow_info.key, args.amount), + &[signer.clone(), escrow_info.clone()], + )?; + load_signer(signer)?; load_uninitialized_pda( bid_info, @@ -42,7 +61,7 @@ pub fn process_bid<'a, 'info>( )?; load_program(system_program, system_program::id())?; - // create bid Program Derived Address. + // create bid account. create_pda( bid_info, &crate::id(), @@ -58,12 +77,13 @@ pub fn process_bid<'a, 'info>( signer, )?; - let mut bid_data = try_from_slice_unchecked::(&bid_info.data.borrow()).unwrap(); + let mut bid_data = try_from_slice_unchecked::(&bid_info.data.borrow())?; bid_data.discriminator = Bid::DISCRIMINATOR.to_string(); bid_data.market = *market_info.key; bid_data.amount = args.amount; bid_data.authority = *signer.key; + bid_data.id = args.id; bid_data.serialize(&mut &mut bid_info.data.borrow_mut()[..])?; market_data.counter += 1; diff --git a/src/processor/market.rs b/src/processor/market.rs index 55efb46..ba1d859 100644 --- a/src/processor/market.rs +++ b/src/processor/market.rs @@ -3,11 +3,17 @@ use solana_program::{ program_error::ProgramError, pubkey::Pubkey, system_program, }; -use crate::{instruction::MarketArgs, loaders::*, state::Market, utils::*, MARKET}; +use crate::{ + instruction::MarketArgs, + loaders::*, + state::{Escrow, Market}, + utils::*, + ESCROW, MARKET, +}; use borsh::{BorshDeserialize, BorshSerialize}; -// process_market creates a new tradable market. -pub fn process_market<'a, 'info>( +// process_init_market creates a new tradable market. +pub fn process_init_market<'a, 'info>( _program_id: &Pubkey, accounts: &'a [AccountInfo<'info>], data: &[u8], @@ -16,7 +22,7 @@ pub fn process_market<'a, 'info>( let args = MarketArgs::try_from_slice(data)?; // Load account data - let [signer, market_info, system_program] = accounts else { + let [signer, market_info, escrow_info, system_program] = accounts else { return Err(ProgramError::NotEnoughAccountKeys); }; @@ -27,9 +33,15 @@ pub fn process_market<'a, 'info>( args.bump, &crate::id(), )?; + load_uninitialized_pda( + escrow_info, + &[ESCROW, market_info.key.as_ref()], + args.escrow_bump, + &crate::id(), + )?; load_program(system_program, system_program::id())?; - // Create the market + // Create market account create_pda( market_info, &crate::id(), @@ -44,9 +56,18 @@ pub fn process_market<'a, 'info>( signer, )?; + // Create escrow account + create_pda( + escrow_info, + &crate::id(), + Escrow::get_account_size(&Market::DISCRIMINATOR.to_string()), + &[ESCROW, market_info.key.as_ref(), &[args.escrow_bump]], + system_program, + signer, + )?; + let mut market_data = try_from_slice_unchecked::(&market_info.data.borrow()).unwrap(); market_data.discriminator = Market::DISCRIMINATOR.to_string(); - market_data.bump = args.bump; market_data.authority = *signer.key; market_data.id = args.id; market_data.title = args.title; diff --git a/src/state/bid.rs b/src/state/bid.rs index 4fa415c..fc2a1e1 100644 --- a/src/state/bid.rs +++ b/src/state/bid.rs @@ -13,9 +13,11 @@ pub struct Bid { pub amount: u64, /// The account that placed this bid. pub authority: Pubkey, + /// The unique bid ID. + pub id: u64, } impl Bid { pub const DISCRIMINATOR: &'static str = "bid"; - pub const SIZE: usize = (4 + Bid::DISCRIMINATOR.len()) + 32 + 8 + 32; + pub const SIZE: usize = (4 + Bid::DISCRIMINATOR.len()) + 32 + 8 + 32 + 8; } diff --git a/src/state/market.rs b/src/state/market.rs index c114b13..7ade19a 100644 --- a/src/state/market.rs +++ b/src/state/market.rs @@ -2,6 +2,22 @@ use borsh::{BorshDeserialize, BorshSerialize}; use shank::ShankAccount; use solana_program::pubkey::Pubkey; +/// Market is the parent account that stores a tradable asset and keeps track of +/// the bids placed on the specific market via a counter. +#[repr(C)] +#[derive(Debug, Clone, BorshSerialize, BorshDeserialize, ShankAccount)] +pub struct Escrow { + pub discriminator: String, +} + +impl Escrow { + pub const DISCRIMINATOR: &'static str = "escrow"; + + pub fn get_account_size(discriminator: &String) -> usize { + return 4 + discriminator.len(); + } +} + /// Market is the parent account that stores a tradable asset and keeps track of /// the bids placed on the specific market via a counter. #[repr(C)] @@ -9,8 +25,6 @@ use solana_program::pubkey::Pubkey; pub struct Market { /// Account discriminator pub discriminator: String, - /// The market account PDA. - pub bump: u8, /// The accounts authority. pub authority: Pubkey, /// The unique market ID. @@ -28,6 +42,6 @@ impl Market { pub const DISCRIMINATOR: &'static str = "market"; pub fn get_account_size(title: &String, discriminator: &String) -> usize { - return (4 + discriminator.len()) + 1 + 32 + 8 + (4 + title.len()) + 2 + 32; + return (4 + discriminator.len()) + 32 + 8 + (4 + title.len()) + 2 + 32; } }