Skip to content

Commit c5ac86f

Browse files
authored
program: make onramp mandatory for deposit/withdraw (#580)
1 parent 5023279 commit c5ac86f

3 files changed

Lines changed: 17 additions & 68 deletions

File tree

program/src/instruction.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ pub enum SinglePoolInstruction {
8383
///
8484
/// 0. `[]` Pool account
8585
/// 1. `[w]` Pool stake account
86-
/// 2. `[]` Pool on-ramp account (not yet enforced)
86+
/// 2. `[]` Pool on-ramp account
8787
/// 3. `[w]` Pool token mint
8888
/// 4. `[]` Pool stake authority
8989
/// 5. `[]` Pool mint authority
@@ -100,7 +100,7 @@ pub enum SinglePoolInstruction {
100100
///
101101
/// 0. `[]` Pool account
102102
/// 1. `[w]` Pool stake account
103-
/// 2. `[]` Pool on-ramp account (not yet enforced)
103+
/// 2. `[]` Pool on-ramp account
104104
/// 3. `[w]` Pool token mint
105105
/// 4. `[]` Pool stake authority
106106
/// 5. `[]` Pool mint authority

program/src/processor.rs

Lines changed: 8 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -932,16 +932,8 @@ impl Processor {
932932
let account_info_iter = &mut accounts.iter();
933933
let pool_info = next_account_info(account_info_iter)?;
934934
let pool_stake_info = next_account_info(account_info_iter)?;
935-
let pool_mint_info = {
936-
let account_info = next_account_info(account_info_iter)?;
937-
// we havent validated pool_info yet, so this doesnt validate onramp, but it doesnt matter
938-
// for now we just need to know whether to skip an account, we dont actually use it
939-
if check_pool_onramp_address(program_id, pool_info.key, account_info.key).is_ok() {
940-
next_account_info(account_info_iter)?
941-
} else {
942-
account_info
943-
}
944-
};
935+
let pool_onramp_info = next_account_info(account_info_iter)?;
936+
let pool_mint_info = next_account_info(account_info_iter)?;
945937
let pool_stake_authority_info = next_account_info(account_info_iter)?;
946938
let pool_mint_authority_info = next_account_info(account_info_iter)?;
947939
let user_stake_info = next_account_info(account_info_iter)?;
@@ -956,6 +948,7 @@ impl Processor {
956948
SinglePool::from_account_info(pool_info, program_id)?;
957949

958950
check_pool_stake_address(program_id, pool_info.key, pool_stake_info.key)?;
951+
check_pool_onramp_address(program_id, pool_info.key, pool_onramp_info.key)?;
959952
check_pool_mint_address(program_id, pool_info.key, pool_mint_info.key)?;
960953
let stake_authority_bump_seed = check_pool_stake_authority_address(
961954
program_id,
@@ -974,8 +967,7 @@ impl Processor {
974967
return Err(SinglePoolError::InvalidPoolStakeAccountUsage.into());
975968
}
976969

977-
let onramp_account_address = crate::find_pool_onramp_address(program_id, pool_info.key);
978-
if onramp_account_address == *user_stake_info.key {
970+
if pool_onramp_info.key == user_stake_info.key {
979971
return Err(SinglePoolError::InvalidPoolStakeAccountUsage.into());
980972
}
981973

@@ -1097,16 +1089,8 @@ impl Processor {
10971089
let account_info_iter = &mut accounts.iter();
10981090
let pool_info = next_account_info(account_info_iter)?;
10991091
let pool_stake_info = next_account_info(account_info_iter)?;
1100-
let pool_mint_info = {
1101-
let account_info = next_account_info(account_info_iter)?;
1102-
// we havent validated pool_info yet, so this doesnt validate onramp, but it doesnt matter
1103-
// for now we just need to know whether to skip an account, we dont actually use it
1104-
if check_pool_onramp_address(program_id, pool_info.key, account_info.key).is_ok() {
1105-
next_account_info(account_info_iter)?
1106-
} else {
1107-
account_info
1108-
}
1109-
};
1092+
let pool_onramp_info = next_account_info(account_info_iter)?;
1093+
let pool_mint_info = next_account_info(account_info_iter)?;
11101094
let pool_stake_authority_info = next_account_info(account_info_iter)?;
11111095
let pool_mint_authority_info = next_account_info(account_info_iter)?;
11121096
let user_stake_info = next_account_info(account_info_iter)?;
@@ -1118,6 +1102,7 @@ impl Processor {
11181102
SinglePool::from_account_info(pool_info, program_id)?;
11191103

11201104
check_pool_stake_address(program_id, pool_info.key, pool_stake_info.key)?;
1105+
check_pool_onramp_address(program_id, pool_info.key, pool_onramp_info.key)?;
11211106
check_pool_mint_address(program_id, pool_info.key, pool_mint_info.key)?;
11221107
let stake_authority_bump_seed = check_pool_stake_authority_address(
11231108
program_id,
@@ -1136,8 +1121,7 @@ impl Processor {
11361121
return Err(SinglePoolError::InvalidPoolStakeAccountUsage.into());
11371122
}
11381123

1139-
let onramp_account_address = crate::find_pool_onramp_address(program_id, pool_info.key);
1140-
if onramp_account_address == *user_stake_info.key {
1124+
if pool_onramp_info.key == user_stake_info.key {
11411125
return Err(SinglePoolError::InvalidPoolStakeAccountUsage.into());
11421126
}
11431127

program/tests/accounts.rs

Lines changed: 7 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use {
1515
solana_system_interface::program as system_program,
1616
spl_single_pool::{
1717
error::SinglePoolError,
18-
find_pool_onramp_address, id,
18+
id,
1919
instruction::{self, SinglePoolInstruction},
2020
},
2121
spl_token_interface as spl_token,
@@ -36,7 +36,6 @@ async fn build_instructions(
3636
context: &mut ProgramTestContext,
3737
accounts: &SinglePoolAccounts,
3838
test_mode: TestMode,
39-
remove_onramp: bool,
4039
) -> (Vec<Instruction>, usize) {
4140
let initialize_instructions = if test_mode == TestMode::Initialize {
4241
let slot = context.genesis_config().epoch_schedule.first_normal_slot + 1;
@@ -86,7 +85,7 @@ async fn build_instructions(
8685
vec![]
8786
};
8887

89-
let mut deposit_instructions = instruction::deposit(
88+
let deposit_instructions = instruction::deposit(
9089
&id(),
9190
&accounts.pool,
9291
&accounts.alice_stake.pubkey(),
@@ -95,7 +94,7 @@ async fn build_instructions(
9594
&accounts.alice.pubkey(),
9695
);
9796

98-
let mut withdraw_instructions = if test_mode == TestMode::Withdraw {
97+
let withdraw_instructions = if test_mode == TestMode::Withdraw {
9998
let transaction = Transaction::new_signed_with_payer(
10099
&deposit_instructions,
101100
Some(&accounts.alice.pubkey()),
@@ -131,17 +130,6 @@ async fn build_instructions(
131130
vec![]
132131
};
133132

134-
if remove_onramp {
135-
let instruction = match test_mode {
136-
TestMode::Deposit => deposit_instructions.last_mut().unwrap(),
137-
TestMode::Withdraw => withdraw_instructions.last_mut().unwrap(),
138-
TestMode::Initialize => unreachable!(),
139-
};
140-
141-
assert_eq!(instruction.accounts[2].pubkey, accounts.onramp_account);
142-
instruction.accounts.remove(2);
143-
}
144-
145133
// ints hardcoded to guard against instructions moving with code changes
146134
// if these asserts fail, update them to match the new multi-instruction builders
147135
let (instructions, index, enum_tag) = match test_mode {
@@ -159,28 +147,17 @@ async fn build_instructions(
159147
// test that account addresses are checked properly
160148
#[test_matrix(
161149
[StakeProgramVersion::Stable, StakeProgramVersion::Beta, StakeProgramVersion::Edge],
162-
[TestMode::Initialize, TestMode::Deposit, TestMode::Withdraw],
163-
[false, true]
150+
[TestMode::Initialize, TestMode::Deposit, TestMode::Withdraw]
164151
)]
165152
#[tokio::test]
166-
async fn fail_account_checks(
167-
stake_version: StakeProgramVersion,
168-
test_mode: TestMode,
169-
remove_onramp: bool,
170-
) {
171-
// initialize does not take the onramp account
172-
if test_mode == TestMode::Initialize && remove_onramp {
173-
return;
174-
}
175-
153+
async fn fail_account_checks(stake_version: StakeProgramVersion, test_mode: TestMode) {
176154
let Some(program_test) = program_test(stake_version) else {
177155
return;
178156
};
179157
let mut context = program_test.start_with_context().await;
180158

181159
let accounts = SinglePoolAccounts::default();
182-
let (instructions, i) =
183-
build_instructions(&mut context, &accounts, test_mode, remove_onramp).await;
160+
let (instructions, i) = build_instructions(&mut context, &accounts, test_mode).await;
184161
let bad_pubkey = pubkey!("BAD1111111111111111111111111111111111111111");
185162

186163
for j in 0..instructions[i].accounts.len() {
@@ -192,18 +169,6 @@ async fn fail_account_checks(
192169
continue;
193170
}
194171

195-
// while onramp is optional, an incorrect onramp misaligns all subsequent accounts
196-
// this is not a problem for the program and causes the mint to fail to validate, but requires tweaking this test
197-
if !remove_onramp && instruction_pubkey == accounts.pool {
198-
if let Some(onramp_account) = instructions[i]
199-
.accounts
200-
.iter_mut()
201-
.find(|account| account.pubkey == accounts.onramp_account)
202-
{
203-
onramp_account.pubkey = find_pool_onramp_address(&id(), &bad_pubkey);
204-
}
205-
}
206-
207172
instructions[i].accounts[j].pubkey = bad_pubkey;
208173

209174
let transaction = Transaction::new_signed_with_payer(
@@ -226,7 +191,7 @@ async fn fail_account_checks(
226191
} else if instruction_pubkey == accounts.stake_account {
227192
check_error(e, SinglePoolError::InvalidPoolStakeAccount)
228193
} else if instruction_pubkey == accounts.onramp_account {
229-
// NOTE add onramp error here when onramp is mandatory
194+
check_error(e, SinglePoolError::InvalidPoolOnRampAccount)
230195
} else if instruction_pubkey == accounts.stake_authority {
231196
check_error(e, SinglePoolError::InvalidPoolStakeAuthority)
232197
} else if instruction_pubkey == accounts.mint_authority {

0 commit comments

Comments
 (0)