custodian signs withdraw (#7286)
This commit is contained in:
@ -105,11 +105,13 @@ pub enum StakeInstruction {
|
||||
Split(u64),
|
||||
|
||||
/// Withdraw unstaked lamports from the stake account
|
||||
/// requires Authorized::withdrawer signature
|
||||
/// requires Authorized::withdrawer signature. If withdrawal
|
||||
/// is before lockup has expired, also requires signature
|
||||
/// of the lockup custodian.
|
||||
///
|
||||
/// Expects 4 Accounts:
|
||||
/// 0 - StakeAccount from which to withdraw
|
||||
/// 1 - System account to which the lamports will be transferred,
|
||||
/// 1 - Account to which the lamports will be transferred
|
||||
/// 2 - Syscall Account that carries epoch
|
||||
/// 3 - StakeHistory sysvar that carries stake warmup/cooldown history
|
||||
///
|
||||
@ -256,7 +258,7 @@ pub fn delegate_stake(
|
||||
|
||||
pub fn withdraw(
|
||||
stake_pubkey: &Pubkey,
|
||||
authorized_pubkey: &Pubkey,
|
||||
withdrawer_pubkey: &Pubkey,
|
||||
to_pubkey: &Pubkey,
|
||||
lamports: u64,
|
||||
) -> Instruction {
|
||||
@ -266,7 +268,27 @@ pub fn withdraw(
|
||||
AccountMeta::new_readonly(sysvar::clock::id(), false),
|
||||
AccountMeta::new_readonly(sysvar::stake_history::id(), false),
|
||||
]
|
||||
.with_signer(authorized_pubkey);
|
||||
.with_signer(withdrawer_pubkey);
|
||||
|
||||
Instruction::new(id(), &StakeInstruction::Withdraw(lamports), account_metas)
|
||||
}
|
||||
|
||||
pub fn withdraw_early(
|
||||
stake_pubkey: &Pubkey,
|
||||
withdrawer_pubkey: &Pubkey,
|
||||
to_pubkey: &Pubkey,
|
||||
lamports: u64,
|
||||
custodian_pubkey: &Pubkey,
|
||||
) -> Instruction {
|
||||
let account_metas = vec![
|
||||
AccountMeta::new(*stake_pubkey, false),
|
||||
AccountMeta::new(*to_pubkey, false),
|
||||
AccountMeta::new_readonly(sysvar::clock::id(), false),
|
||||
AccountMeta::new_readonly(sysvar::stake_history::id(), false),
|
||||
]
|
||||
.with_signer(withdrawer_pubkey)
|
||||
.with_signer(custodian_pubkey);
|
||||
|
||||
Instruction::new(id(), &StakeInstruction::Withdraw(lamports), account_metas)
|
||||
}
|
||||
|
||||
|
@ -754,9 +754,9 @@ impl<'a> StakeAccount for KeyedAccount<'a> {
|
||||
_ => return Err(InstructionError::InvalidAccountData),
|
||||
};
|
||||
|
||||
// verify that lockup has expired or that the withdrawal is going back
|
||||
// to the custodian
|
||||
if lockup.epoch > clock.epoch && lockup.custodian != *to.unsigned_key() {
|
||||
// verify that lockup has expired or that the withdrawal is signed by
|
||||
// the custodian
|
||||
if lockup.epoch > clock.epoch && !signers.contains(&lockup.custodian) {
|
||||
return Err(StakeError::LockupInForce.into());
|
||||
}
|
||||
|
||||
@ -1792,20 +1792,20 @@ mod tests {
|
||||
Err(StakeError::LockupInForce.into())
|
||||
);
|
||||
|
||||
// but we *can* send to the custodian
|
||||
let mut custodian_account = Account::new(1, 0, &system_program::id());
|
||||
let mut custodian_keyed_account =
|
||||
KeyedAccount::new(&custodian, false, &mut custodian_account);
|
||||
assert_eq!(
|
||||
stake_keyed_account.withdraw(
|
||||
total_lamports,
|
||||
&mut custodian_keyed_account,
|
||||
&clock,
|
||||
&StakeHistory::default(),
|
||||
&signers,
|
||||
),
|
||||
Ok(())
|
||||
);
|
||||
{
|
||||
let mut signers_with_custodian = signers.clone();
|
||||
signers_with_custodian.insert(custodian);
|
||||
assert_eq!(
|
||||
stake_keyed_account.withdraw(
|
||||
total_lamports,
|
||||
&mut to_keyed_account,
|
||||
&clock,
|
||||
&StakeHistory::default(),
|
||||
&signers_with_custodian,
|
||||
),
|
||||
Ok(())
|
||||
);
|
||||
}
|
||||
// reset balance
|
||||
stake_keyed_account.account.lamports = total_lamports;
|
||||
|
||||
|
Reference in New Issue
Block a user