Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions clients/js/src/instructions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ type DepositStakeInstruction = IInstruction<typeof SINGLE_POOL_PROGRAM_ID> &
[
ReadonlyAccount<PoolAddress>,
WritableAccount<PoolStakeAddress>,
ReadonlyAccount<PoolOnRampAddress>,
WritableAccount<PoolMintAddress>,
ReadonlyAccount<PoolStakeAuthorityAddress>,
ReadonlyAccount<PoolMintAuthorityAddress>,
Expand All @@ -102,6 +103,7 @@ type WithdrawStakeInstruction = IInstruction<typeof SINGLE_POOL_PROGRAM_ID> &
[
ReadonlyAccount<PoolAddress>,
WritableAccount<PoolStakeAddress>,
ReadonlyAccount<PoolOnRampAddress>,
WritableAccount<PoolMintAddress>,
ReadonlyAccount<PoolStakeAuthorityAddress>,
ReadonlyAccount<PoolMintAuthorityAddress>,
Expand Down Expand Up @@ -247,8 +249,9 @@ export async function depositStakeInstruction(
userLamportAccount: Address,
): Promise<DepositStakeInstruction> {
const programAddress = SINGLE_POOL_PROGRAM_ID;
const [stake, mint, stakeAuthority, mintAuthority] = await Promise.all([
const [stake, onramp, mint, stakeAuthority, mintAuthority] = await Promise.all([
findPoolStakeAddress(programAddress, pool),
findPoolOnRampAddress(programAddress, pool),
findPoolMintAddress(programAddress, pool),
findPoolStakeAuthorityAddress(programAddress, pool),
findPoolMintAuthorityAddress(programAddress, pool),
Expand All @@ -261,6 +264,7 @@ export async function depositStakeInstruction(
accounts: [
{ address: pool, role: AccountRole.READONLY },
{ address: stake, role: AccountRole.WRITABLE },
{ address: onramp, role: AccountRole.READONLY },
{ address: mint, role: AccountRole.WRITABLE },
{ address: stakeAuthority, role: AccountRole.READONLY },
{ address: mintAuthority, role: AccountRole.READONLY },
Expand All @@ -284,8 +288,9 @@ export async function withdrawStakeInstruction(
tokenAmount: bigint,
): Promise<WithdrawStakeInstruction> {
const programAddress = SINGLE_POOL_PROGRAM_ID;
const [stake, mint, stakeAuthority, mintAuthority] = await Promise.all([
const [stake, onramp, mint, stakeAuthority, mintAuthority] = await Promise.all([
findPoolStakeAddress(programAddress, pool),
findPoolOnRampAddress(programAddress, pool),
findPoolMintAddress(programAddress, pool),
findPoolStakeAuthorityAddress(programAddress, pool),
findPoolMintAuthorityAddress(programAddress, pool),
Expand All @@ -303,6 +308,7 @@ export async function withdrawStakeInstruction(
accounts: [
{ address: pool, role: AccountRole.READONLY },
{ address: stake, role: AccountRole.WRITABLE },
{ address: onramp, role: AccountRole.READONLY },
{ address: mint, role: AccountRole.WRITABLE },
{ address: stakeAuthority, role: AccountRole.READONLY },
{ address: mintAuthority, role: AccountRole.READONLY },
Expand Down
2 changes: 2 additions & 0 deletions program/src/instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,7 @@ pub fn deposit_stake(
let accounts = vec![
AccountMeta::new_readonly(*pool_address, false),
AccountMeta::new(find_pool_stake_address(program_id, pool_address), false),
AccountMeta::new_readonly(find_pool_onramp_address(program_id, pool_address), false),
AccountMeta::new(find_pool_mint_address(program_id, pool_address), false),
AccountMeta::new_readonly(
find_pool_stake_authority_address(program_id, pool_address),
Expand Down Expand Up @@ -393,6 +394,7 @@ pub fn withdraw_stake(
let accounts = vec![
AccountMeta::new_readonly(*pool_address, false),
AccountMeta::new(find_pool_stake_address(program_id, pool_address), false),
AccountMeta::new_readonly(find_pool_onramp_address(program_id, pool_address), false),
AccountMeta::new(find_pool_mint_address(program_id, pool_address), false),
AccountMeta::new_readonly(
find_pool_stake_authority_address(program_id, pool_address),
Expand Down
38 changes: 11 additions & 27 deletions program/tests/accounts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ mod helpers;

use {
helpers::*,
solana_instruction::AccountMeta,
solana_program_test::*,
solana_pubkey::pubkey,
solana_sdk::{
Expand Down Expand Up @@ -36,7 +35,7 @@ async fn build_instructions(
context: &mut ProgramTestContext,
accounts: &SinglePoolAccounts,
test_mode: TestMode,
include_onramp: bool,
remove_onramp: bool,
) -> (Vec<Instruction>, usize) {
let initialize_instructions = if test_mode == TestMode::Initialize {
let slot = context.genesis_config().epoch_schedule.first_normal_slot + 1;
Expand Down Expand Up @@ -131,29 +130,15 @@ async fn build_instructions(
vec![]
};

if include_onramp {
if remove_onramp {
let instruction = match test_mode {
TestMode::Deposit => deposit_instructions.last_mut().unwrap(),
TestMode::Withdraw => withdraw_instructions.last_mut().unwrap(),
TestMode::Initialize => unreachable!(),
};

if instruction.accounts[2].pubkey == accounts.mint {
instruction.accounts.insert(
2,
AccountMeta {
pubkey: accounts.onramp_account,
is_writable: false,
is_signer: false,
},
);
} else {
panic!(
"this test enforces forwards-compat pre-instruction builder change. \
if you are adding onramp to builders, refactor `include_onramp` to \
be an `exclude_onramp` and test backwards-compat instead"
);
}
assert_eq!(instruction.accounts[2].pubkey, accounts.onramp_account);
instruction.accounts.remove(2);
}

// ints hardcoded to guard against instructions moving with code changes
Expand All @@ -172,16 +157,16 @@ async fn build_instructions(

// test that account addresses are checked properly
#[test_case(TestMode::Initialize, false; "initialize")]
#[test_case(TestMode::Deposit, false; "deposit_legacy")]
#[test_case(TestMode::Withdraw, false; "withdraw_legacy")]
#[test_case(TestMode::Deposit, true; "deposit_onramp")]
#[test_case(TestMode::Withdraw, true; "withdraw_onramp")]
#[test_case(TestMode::Deposit, true; "deposit_legacy")]
#[test_case(TestMode::Withdraw, true; "withdraw_legacy")]
#[test_case(TestMode::Deposit, false; "deposit_onramp")]
#[test_case(TestMode::Withdraw, false; "withdraw_onramp")]
#[tokio::test]
async fn fail_account_checks(test_mode: TestMode, include_onramp: bool) {
async fn fail_account_checks(test_mode: TestMode, remove_onramp: bool) {
let mut context = program_test(false).start_with_context().await;
let accounts = SinglePoolAccounts::default();
let (instructions, i) =
build_instructions(&mut context, &accounts, test_mode, include_onramp).await;
build_instructions(&mut context, &accounts, test_mode, remove_onramp).await;
let bad_pubkey = pubkey!("BAD1111111111111111111111111111111111111111");

for j in 0..instructions[i].accounts.len() {
Expand All @@ -195,8 +180,7 @@ async fn fail_account_checks(test_mode: TestMode, include_onramp: bool) {

// while onramp is optional, an incorrect onramp misaligns all subsequent accounts
// this is not a problem for the program and causes the mint to fail to validate, but requires tweaking this test
// NOTE once deposit/withdraw require onramp, delete this block
if include_onramp && instruction_pubkey == accounts.pool {
if !remove_onramp && instruction_pubkey == accounts.pool {
Comment on lines -198 to +183
Copy link
Member Author

@2501babe 2501babe Nov 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i realized this comment is pointless because once they require onramp we have to get rid of everything involving remove_onramp

if let Some(onramp_account) = instructions[i]
.accounts
.iter_mut()
Expand Down
Loading