Skip to content
This repository was archived by the owner on Mar 11, 2025. It is now read-only.

Commit 1411d8b

Browse files
authored
stake-pool: Option to use transfer + allocate + assign for PDA (#2920)
1 parent 172e24e commit 1411d8b

File tree

2 files changed

+106
-13
lines changed

2 files changed

+106
-13
lines changed

stake-pool/program/src/processor.rs

Lines changed: 63 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,59 @@ fn create_transient_stake_account<'a>(
160160
)
161161
}
162162

163+
/// Create an account on a program-derived address
164+
fn create_pda_account<'a>(
165+
payer: &AccountInfo<'a>,
166+
required_lamports: u64,
167+
space: usize,
168+
owner: &Pubkey,
169+
system_program: &AccountInfo<'a>,
170+
new_pda_account: &AccountInfo<'a>,
171+
new_pda_signer_seeds: &[&[u8]],
172+
) -> ProgramResult {
173+
if new_pda_account.lamports() > 0 {
174+
let required_lamports = required_lamports.saturating_sub(new_pda_account.lamports());
175+
if required_lamports > 0 {
176+
invoke(
177+
&system_instruction::transfer(payer.key, new_pda_account.key, required_lamports),
178+
&[
179+
payer.clone(),
180+
new_pda_account.clone(),
181+
system_program.clone(),
182+
],
183+
)?;
184+
}
185+
186+
invoke_signed(
187+
&system_instruction::allocate(new_pda_account.key, space as u64),
188+
&[new_pda_account.clone(), system_program.clone()],
189+
&[new_pda_signer_seeds],
190+
)?;
191+
192+
invoke_signed(
193+
&system_instruction::assign(new_pda_account.key, owner),
194+
&[new_pda_account.clone(), system_program.clone()],
195+
&[new_pda_signer_seeds],
196+
)
197+
} else {
198+
invoke_signed(
199+
&system_instruction::create_account(
200+
payer.key,
201+
new_pda_account.key,
202+
required_lamports,
203+
space as u64,
204+
owner,
205+
),
206+
&[
207+
payer.clone(),
208+
new_pda_account.clone(),
209+
system_program.clone(),
210+
],
211+
&[new_pda_signer_seeds],
212+
)
213+
}
214+
}
215+
163216
/// Program state handler.
164217
pub struct Processor {}
165218
impl Processor {
@@ -798,22 +851,19 @@ impl Processor {
798851
];
799852

800853
// Fund the stake account with the minimum + rent-exempt balance
801-
let required_lamports = MINIMUM_ACTIVE_STAKE
802-
+ rent.minimum_balance(std::mem::size_of::<stake::state::StakeState>());
854+
let space = std::mem::size_of::<stake::state::StakeState>();
855+
let required_lamports = MINIMUM_ACTIVE_STAKE + rent.minimum_balance(space);
803856

804857
// Create new stake account
805-
invoke_signed(
806-
&system_instruction::create_account(
807-
funder_info.key,
808-
stake_info.key,
809-
required_lamports,
810-
std::mem::size_of::<stake::state::StakeState>() as u64,
811-
&stake::program::id(),
812-
),
813-
&[funder_info.clone(), stake_info.clone()],
814-
&[stake_account_signer_seeds],
858+
create_pda_account(
859+
funder_info,
860+
required_lamports,
861+
space,
862+
&stake::program::id(),
863+
system_program_info,
864+
stake_info,
865+
stake_account_signer_seeds,
815866
)?;
816-
817867
invoke(
818868
&stake::instruction::initialize(
819869
stake_info.key,

stake-pool/program/tests/vsa_add.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -500,3 +500,46 @@ async fn fail_on_incorrectly_derived_stake_account() {
500500
)
501501
);
502502
}
503+
504+
#[tokio::test]
505+
async fn success_with_lamports_in_account() {
506+
let (mut banks_client, payer, recent_blockhash, stake_pool_accounts, validator_stake) =
507+
setup().await;
508+
509+
transfer(
510+
&mut banks_client,
511+
&payer,
512+
&recent_blockhash,
513+
&validator_stake.stake_account,
514+
1_000_000,
515+
)
516+
.await;
517+
518+
let error = stake_pool_accounts
519+
.add_validator_to_pool(
520+
&mut banks_client,
521+
&payer,
522+
&recent_blockhash,
523+
&validator_stake.stake_account,
524+
&validator_stake.vote.pubkey(),
525+
)
526+
.await;
527+
assert!(error.is_none());
528+
529+
// Check stake account existence and authority
530+
let stake = get_account(&mut banks_client, &validator_stake.stake_account).await;
531+
let stake_state = deserialize::<stake::state::StakeState>(&stake.data).unwrap();
532+
match stake_state {
533+
stake::state::StakeState::Stake(meta, _) => {
534+
assert_eq!(
535+
&meta.authorized.staker,
536+
&stake_pool_accounts.withdraw_authority
537+
);
538+
assert_eq!(
539+
&meta.authorized.withdrawer,
540+
&stake_pool_accounts.withdraw_authority
541+
);
542+
}
543+
_ => panic!(),
544+
}
545+
}

0 commit comments

Comments
 (0)