From d2e1567f8d6b323beacd99b343b33e96be4e5d4f Mon Sep 17 00:00:00 2001 From: Hardhat Chad Date: Wed, 15 Oct 2025 12:50:20 -0700 Subject: [PATCH] stake --- api/src/instruction.rs | 12 ------- api/src/sdk.rs | 38 +++------------------- cli/src/main.rs | 5 +++ program/src/deposit.rs | 32 ++++++++++++++++--- program/src/lib.rs | 2 +- program/src/migrate_staker.rs | 59 +++++++++++++++++++++++++++++++++++ program/src/withdraw.rs | 19 ++++++----- 7 files changed, 109 insertions(+), 58 deletions(-) create mode 100644 program/src/migrate_staker.rs diff --git a/api/src/instruction.rs b/api/src/instruction.rs index f4157a7..d3a0a18 100644 --- a/api/src/instruction.rs +++ b/api/src/instruction.rs @@ -28,8 +28,6 @@ pub enum OreInstruction { // Seeker ClaimSeeker = 17, - MigrateTreasury = 18, - MigrateMiner = 19, } #[repr(C)] @@ -152,14 +150,6 @@ pub struct Checkpoint {} #[derive(Clone, Copy, Debug, Pod, Zeroable)] pub struct Close {} -#[repr(C)] -#[derive(Clone, Copy, Debug, Pod, Zeroable)] -pub struct MigrateTreasury {} - -#[repr(C)] -#[derive(Clone, Copy, Debug, Pod, Zeroable)] -pub struct MigrateMiner {} - instruction!(OreInstruction, Automate); instruction!(OreInstruction, Boost); instruction!(OreInstruction, Close); @@ -178,5 +168,3 @@ instruction!(OreInstruction, Deposit); instruction!(OreInstruction, Withdraw); instruction!(OreInstruction, ClaimYield); instruction!(OreInstruction, ClaimSeeker); -instruction!(OreInstruction, MigrateTreasury); -instruction!(OreInstruction, MigrateMiner); diff --git a/api/src/sdk.rs b/api/src/sdk.rs index bd6e868..80e35df 100644 --- a/api/src/sdk.rs +++ b/api/src/sdk.rs @@ -184,35 +184,6 @@ pub fn deploy( } } -pub fn migrate_miner(signer: Pubkey, address: Pubkey) -> Instruction { - let config_address = config_pda().0; - Instruction { - program_id: crate::ID, - accounts: vec![ - AccountMeta::new(signer, true), - AccountMeta::new(config_address, false), - AccountMeta::new(address, false), - AccountMeta::new_readonly(system_program::ID, false), - ], - data: MigrateMiner {}.to_bytes(), - } -} - -pub fn migrate_treasury(signer: Pubkey) -> Instruction { - let config_address = config_pda().0; - // let treasury_address = treasury_pda().0; - Instruction { - program_id: crate::ID, - accounts: vec![ - AccountMeta::new(signer, true), - AccountMeta::new(config_address, false), - // AccountMeta::new(treasury_address, false), - AccountMeta::new_readonly(system_program::ID, false), - ], - data: MigrateTreasury {}.to_bytes(), - } -} - const POOL_ADDRESS: Pubkey = pubkey!("GgaDTFbqdgjoZz3FP7zrtofGwnRS4E6MCzmmD5Ni1Mxj"); const TOKEN_A_MINT: Pubkey = MINT_ADDRESS; // pubkey!("oreoU2P8bN6jkk3jbaiVxYnG1dCXcYxwhwyK9jSybcp"); const TOKEN_B_MINT: Pubkey = SOL_MINT; //pubkey!("So11111111111111111111111111111111111111112"); @@ -429,19 +400,20 @@ pub fn claim_seeker(signer: Pubkey, mint: Pubkey) -> Instruction { pub fn deposit(signer: Pubkey, amount: u64) -> Instruction { let stake_address = stake_pda(signer).0; + let stake_tokens_address = get_associated_token_address(&stake_address, &MINT_ADDRESS); let sender_address = get_associated_token_address(&signer, &MINT_ADDRESS); let treasury_address = TREASURY_ADDRESS; - let treasury_tokens_address = treasury_tokens_address(); Instruction { program_id: crate::ID, accounts: vec![ AccountMeta::new(signer, true), AccountMeta::new(sender_address, false), AccountMeta::new(stake_address, false), + AccountMeta::new(stake_tokens_address, false), AccountMeta::new(treasury_address, false), - AccountMeta::new(treasury_tokens_address, false), AccountMeta::new_readonly(system_program::ID, false), AccountMeta::new_readonly(spl_token::ID, false), + AccountMeta::new_readonly(spl_associated_token_account::ID, false), ], data: Deposit { amount: amount.to_le_bytes(), @@ -454,10 +426,10 @@ pub fn deposit(signer: Pubkey, amount: u64) -> Instruction { pub fn withdraw(signer: Pubkey, amount: u64) -> Instruction { let stake_address = stake_pda(signer).0; + let stake_tokens_address = get_associated_token_address(&stake_address, &MINT_ADDRESS); let mint_address = MINT_ADDRESS; let recipient_address = get_associated_token_address(&signer, &MINT_ADDRESS); let treasury_address = TREASURY_ADDRESS; - let treasury_tokens_address = treasury_tokens_address(); Instruction { program_id: crate::ID, accounts: vec![ @@ -465,8 +437,8 @@ pub fn withdraw(signer: Pubkey, amount: u64) -> Instruction { AccountMeta::new(mint_address, false), AccountMeta::new(recipient_address, false), AccountMeta::new(stake_address, false), + AccountMeta::new(stake_tokens_address, false), AccountMeta::new(treasury_address, false), - AccountMeta::new(treasury_tokens_address, false), AccountMeta::new_readonly(system_program::ID, false), AccountMeta::new_readonly(spl_token::ID, false), AccountMeta::new_readonly(spl_associated_token_account::ID, false), diff --git a/cli/src/main.rs b/cli/src/main.rs index 1574b6f..716c72b 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -117,6 +117,11 @@ async fn main() { }; } +async fn get_stakers(rpc: &RpcClient) -> Result, anyhow::Error> { + let stakers = get_program_accounts(rpc, ore_api::ID, vec![]).await?; + Ok(stakers) +} + async fn participating_miners(rpc: &RpcClient) -> Result<(), anyhow::Error> { let round_id = std::env::var("ID").expect("Missing ID env var"); let round_id = u64::from_str(&round_id).expect("Invalid ID"); diff --git a/program/src/deposit.rs b/program/src/deposit.rs index 9835ef8..f2cbcf0 100644 --- a/program/src/deposit.rs +++ b/program/src/deposit.rs @@ -3,6 +3,8 @@ use solana_program::log::sol_log; use spl_token::amount_to_ui_amount; use steel::*; +use crate::AUTHORIZED_ACCOUNTS; + /// Deposits ORE into the staking contract. pub fn process_deposit(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramResult { // Parse data. @@ -11,22 +13,27 @@ pub fn process_deposit(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramResu // Load accounts. let clock = Clock::get()?; - let [signer_info, sender_info, stake_info, treasury_info, treasury_tokens_info, system_program, token_program] = + let [signer_info, mint_info, sender_info, stake_info, stake_tokens_info, treasury_info, system_program, token_program, associated_token_program] = accounts else { return Err(ProgramError::NotEnoughAccountKeys); }; signer_info.is_signer()?; + mint_info.has_address(&MINT_ADDRESS)?.as_mint()?; let sender = sender_info .is_writable()? .as_associated_token_account(&signer_info.key, &MINT_ADDRESS)?; stake_info.is_writable()?; let treasury = treasury_info.as_account_mut::(&ore_api::ID)?; - treasury_tokens_info - .is_writable()? - .as_associated_token_account(&treasury_info.key, &MINT_ADDRESS)?; system_program.is_program(&system_program::ID)?; token_program.is_program(&spl_token::ID)?; + associated_token_program.is_program(&spl_associated_token_account::ID)?; + + // Whitelist + assert!( + AUTHORIZED_ACCOUNTS.contains(&signer_info.key), + "Signer not whitelisted" + ); // Open stake account. let stake = if stake_info.data_is_empty() { @@ -54,6 +61,21 @@ pub fn process_deposit(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramResu .assert_mut(|s| s.authority == *signer_info.key)? }; + // Create stake tokens account. + if stake_tokens_info.data_is_empty() { + create_associated_token_account( + signer_info, + stake_info, + stake_tokens_info, + mint_info, + system_program, + token_program, + associated_token_program, + )?; + } else { + stake_tokens_info.as_associated_token_account(stake_info.key, mint_info.key)?; + } + // Only allow deposits from seekers. // assert!(stake.is_seeker == 1, "Only seekers can deposit stake"); @@ -64,7 +86,7 @@ pub fn process_deposit(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramResu transfer( signer_info, sender_info, - treasury_tokens_info, + stake_tokens_info, token_program, amount, )?; diff --git a/program/src/lib.rs b/program/src/lib.rs index 869b860..e0822a5 100644 --- a/program/src/lib.rs +++ b/program/src/lib.rs @@ -61,7 +61,7 @@ pub fn process_instruction( // Staker OreInstruction::Deposit => process_deposit(accounts, data)?, OreInstruction::Withdraw => process_withdraw(accounts, data)?, - OreInstruction::ClaimYield => process_claim_yield(accounts, data)?, + // OreInstruction::ClaimYield => process_claim_yield(accounts, data)?, // Admin OreInstruction::Bury => process_bury(accounts, data)?, diff --git a/program/src/migrate_staker.rs b/program/src/migrate_staker.rs new file mode 100644 index 0000000..2c1e1eb --- /dev/null +++ b/program/src/migrate_staker.rs @@ -0,0 +1,59 @@ +use ore_api::prelude::*; +use steel::*; + +/// Sets the admin. +pub fn process_migrate_staker(accounts: &[AccountInfo<'_>], _data: &[u8]) -> ProgramResult { + // Load accounts. + let [signer_info, config_info, mint_info, stake_info, stake_tokens_info, treasury_info, treasury_tokens_info, system_program, token_program, associated_token_program] = + accounts + else { + return Err(ProgramError::NotEnoughAccountKeys); + }; + signer_info.is_signer()?; + config_info.as_account::(&ore_api::ID)?.assert_err( + |c| c.admin == *signer_info.key, + OreError::NotAuthorized.into(), + )?; + mint_info.has_address(&MINT_ADDRESS)?.as_mint()?; + let stake = stake_info.as_account_mut::(&ore_api::ID)?; + stake_tokens_info.is_empty()?.is_writable()?; + treasury_info.as_account_mut::(&ore_api::ID)?; + treasury_tokens_info.as_associated_token_account(&treasury_info.key, &MINT_ADDRESS)?; + system_program.is_program(&system_program::ID)?; + token_program.is_program(&spl_token::ID)?; + associated_token_program.is_program(&spl_associated_token_account::ID)?; + + // Create stake tokens account. + if stake_tokens_info.data_is_empty() { + create_associated_token_account( + signer_info, + stake_info, + stake_tokens_info, + mint_info, + system_program, + token_program, + associated_token_program, + )?; + } + let stake_tokens = + stake_tokens_info.as_associated_token_account(stake_info.key, mint_info.key)?; + + // Move tokens from treasury to stake tokens. + if stake_tokens.amount() == 0 { + transfer_signed( + treasury_info, + treasury_tokens_info, + stake_tokens_info, + token_program, + stake.balance, + &[TREASURY], + )?; + } + + // Safety check. + let stake_tokens = + stake_tokens_info.as_associated_token_account(stake_info.key, mint_info.key)?; + assert_eq!(stake_tokens.amount(), stake.balance); + + Ok(()) +} diff --git a/program/src/withdraw.rs b/program/src/withdraw.rs index 99b7f0d..8e5ea85 100644 --- a/program/src/withdraw.rs +++ b/program/src/withdraw.rs @@ -3,6 +3,8 @@ use solana_program::log::sol_log; use spl_token::amount_to_ui_amount; use steel::*; +use crate::AUTHORIZED_ACCOUNTS; + /// Withdraws ORE from the staking contract. pub fn process_withdraw(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramResult { // Parse data. @@ -11,7 +13,7 @@ pub fn process_withdraw(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramRes // Load accounts. let clock = Clock::get()?; - let [signer_info, mint_info, recipient_info, stake_info, treasury_info, treasury_tokens_info, system_program, token_program, associated_token_program] = + let [signer_info, mint_info, recipient_info, stake_info, stake_tokens_info, treasury_info, system_program, token_program, associated_token_program] = accounts else { return Err(ProgramError::NotEnoughAccountKeys); @@ -24,14 +26,17 @@ pub fn process_withdraw(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramRes let stake = stake_info .as_account_mut::(&ore_api::ID)? .assert_mut(|s| s.authority == *signer_info.key)?; + stake_tokens_info.as_associated_token_account(stake_info.key, mint_info.key)?; let treasury = treasury_info.as_account_mut::(&ore_api::ID)?; - treasury_tokens_info - .is_writable()? - .as_associated_token_account(&treasury_info.key, &mint_info.key)?; system_program.is_program(&system_program::ID)?; token_program.is_program(&spl_token::ID)?; associated_token_program.is_program(&spl_associated_token_account::ID)?; + assert!( + AUTHORIZED_ACCOUNTS.contains(&signer_info.key), + "Signer not whitelisted" + ); + // Open recipient token account. if recipient_info.data_is_empty() { create_associated_token_account( @@ -50,12 +55,12 @@ pub fn process_withdraw(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramRes // Transfer ORE to recipient. transfer_signed( - treasury_info, - treasury_tokens_info, + stake_info, + stake_tokens_info, recipient_info, token_program, amount, - &[TREASURY], + &[STAKE, &stake.authority.to_bytes()], )?; // Log withdraw.