Add vote/stake checked instructions
This commit is contained in:
parent
100fabf469
commit
ee219ffa47
|
@ -8,7 +8,11 @@ use {
|
||||||
process_instruction::{get_sysvar, InvokeContext},
|
process_instruction::{get_sysvar, InvokeContext},
|
||||||
program_utils::limited_deserialize,
|
program_utils::limited_deserialize,
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
stake::{instruction::StakeInstruction, program::id},
|
stake::{
|
||||||
|
instruction::StakeInstruction,
|
||||||
|
program::id,
|
||||||
|
state::{Authorized, Lockup},
|
||||||
|
},
|
||||||
sysvar::{self, clock::Clock, rent::Rent, stake_history::StakeHistory},
|
sysvar::{self, clock::Clock, rent::Rent, stake_history::StakeHistory},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -56,8 +60,9 @@ pub fn process_instruction(
|
||||||
let clock =
|
let clock =
|
||||||
from_keyed_account::<Clock>(keyed_account_at_index(keyed_accounts, 1)?)?;
|
from_keyed_account::<Clock>(keyed_account_at_index(keyed_accounts, 1)?)?;
|
||||||
let _current_authority = keyed_account_at_index(keyed_accounts, 2)?;
|
let _current_authority = keyed_account_at_index(keyed_accounts, 2)?;
|
||||||
let custodian =
|
let custodian = keyed_account_at_index(keyed_accounts, 3)
|
||||||
keyed_account_at_index(keyed_accounts, 3).map(|ka| ka.unsigned_key());
|
.ok()
|
||||||
|
.map(|ka| ka.unsigned_key());
|
||||||
|
|
||||||
me.authorize(
|
me.authorize(
|
||||||
&signers,
|
&signers,
|
||||||
|
@ -65,7 +70,7 @@ pub fn process_instruction(
|
||||||
stake_authorize,
|
stake_authorize,
|
||||||
require_custodian_for_locked_stake_authorize,
|
require_custodian_for_locked_stake_authorize,
|
||||||
&clock,
|
&clock,
|
||||||
custodian.ok(),
|
custodian,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
me.authorize(
|
me.authorize(
|
||||||
|
@ -87,8 +92,9 @@ pub fn process_instruction(
|
||||||
if require_custodian_for_locked_stake_authorize {
|
if require_custodian_for_locked_stake_authorize {
|
||||||
let clock =
|
let clock =
|
||||||
from_keyed_account::<Clock>(keyed_account_at_index(keyed_accounts, 2)?)?;
|
from_keyed_account::<Clock>(keyed_account_at_index(keyed_accounts, 2)?)?;
|
||||||
let custodian =
|
let custodian = keyed_account_at_index(keyed_accounts, 3)
|
||||||
keyed_account_at_index(keyed_accounts, 3).map(|ka| ka.unsigned_key());
|
.ok()
|
||||||
|
.map(|ka| ka.unsigned_key());
|
||||||
|
|
||||||
me.authorize_with_seed(
|
me.authorize_with_seed(
|
||||||
authority_base,
|
authority_base,
|
||||||
|
@ -98,7 +104,7 @@ pub fn process_instruction(
|
||||||
args.stake_authorize,
|
args.stake_authorize,
|
||||||
require_custodian_for_locked_stake_authorize,
|
require_custodian_for_locked_stake_authorize,
|
||||||
&clock,
|
&clock,
|
||||||
custodian.ok(),
|
custodian,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
me.authorize_with_seed(
|
me.authorize_with_seed(
|
||||||
|
@ -144,7 +150,6 @@ pub fn process_instruction(
|
||||||
can_merge_expired_lockups,
|
can_merge_expired_lockups,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
StakeInstruction::Withdraw(lamports) => {
|
StakeInstruction::Withdraw(lamports) => {
|
||||||
let to = &keyed_account_at_index(keyed_accounts, 1)?;
|
let to = &keyed_account_at_index(keyed_accounts, 1)?;
|
||||||
me.withdraw(
|
me.withdraw(
|
||||||
|
@ -161,7 +166,6 @@ pub fn process_instruction(
|
||||||
&from_keyed_account::<Clock>(keyed_account_at_index(keyed_accounts, 1)?)?,
|
&from_keyed_account::<Clock>(keyed_account_at_index(keyed_accounts, 1)?)?,
|
||||||
&signers,
|
&signers,
|
||||||
),
|
),
|
||||||
|
|
||||||
StakeInstruction::SetLockup(lockup) => {
|
StakeInstruction::SetLockup(lockup) => {
|
||||||
let clock = if invoke_context.is_feature_active(&feature_set::stake_program_v4::id()) {
|
let clock = if invoke_context.is_feature_active(&feature_set::stake_program_v4::id()) {
|
||||||
Some(get_sysvar::<Clock>(invoke_context, &sysvar::clock::id())?)
|
Some(get_sysvar::<Clock>(invoke_context, &sysvar::clock::id())?)
|
||||||
|
@ -170,6 +174,101 @@ pub fn process_instruction(
|
||||||
};
|
};
|
||||||
me.set_lockup(&lockup, &signers, clock.as_ref())
|
me.set_lockup(&lockup, &signers, clock.as_ref())
|
||||||
}
|
}
|
||||||
|
StakeInstruction::InitializeChecked => {
|
||||||
|
if invoke_context.is_feature_active(&feature_set::vote_stake_checked_instructions::id())
|
||||||
|
{
|
||||||
|
let authorized = Authorized {
|
||||||
|
staker: *keyed_account_at_index(keyed_accounts, 2)?.unsigned_key(),
|
||||||
|
withdrawer: *keyed_account_at_index(keyed_accounts, 3)?
|
||||||
|
.signer_key()
|
||||||
|
.ok_or(InstructionError::MissingRequiredSignature)?,
|
||||||
|
};
|
||||||
|
|
||||||
|
me.initialize(
|
||||||
|
&authorized,
|
||||||
|
&Lockup::default(),
|
||||||
|
&from_keyed_account::<Rent>(keyed_account_at_index(keyed_accounts, 1)?)?,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Err(InstructionError::InvalidInstructionData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
StakeInstruction::AuthorizeChecked(stake_authorize) => {
|
||||||
|
if invoke_context.is_feature_active(&feature_set::vote_stake_checked_instructions::id())
|
||||||
|
{
|
||||||
|
let clock =
|
||||||
|
from_keyed_account::<Clock>(keyed_account_at_index(keyed_accounts, 1)?)?;
|
||||||
|
let _current_authority = keyed_account_at_index(keyed_accounts, 2)?;
|
||||||
|
let authorized_pubkey = &keyed_account_at_index(keyed_accounts, 3)?
|
||||||
|
.signer_key()
|
||||||
|
.ok_or(InstructionError::MissingRequiredSignature)?;
|
||||||
|
let custodian = keyed_account_at_index(keyed_accounts, 4)
|
||||||
|
.ok()
|
||||||
|
.map(|ka| ka.unsigned_key());
|
||||||
|
|
||||||
|
me.authorize(
|
||||||
|
&signers,
|
||||||
|
authorized_pubkey,
|
||||||
|
stake_authorize,
|
||||||
|
true,
|
||||||
|
&clock,
|
||||||
|
custodian,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Err(InstructionError::InvalidInstructionData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
StakeInstruction::AuthorizeCheckedWithSeed(args) => {
|
||||||
|
if invoke_context.is_feature_active(&feature_set::vote_stake_checked_instructions::id())
|
||||||
|
{
|
||||||
|
let authority_base = keyed_account_at_index(keyed_accounts, 1)?;
|
||||||
|
let clock =
|
||||||
|
from_keyed_account::<Clock>(keyed_account_at_index(keyed_accounts, 2)?)?;
|
||||||
|
let authorized_pubkey = &keyed_account_at_index(keyed_accounts, 3)?
|
||||||
|
.signer_key()
|
||||||
|
.ok_or(InstructionError::MissingRequiredSignature)?;
|
||||||
|
let custodian = keyed_account_at_index(keyed_accounts, 4)
|
||||||
|
.ok()
|
||||||
|
.map(|ka| ka.unsigned_key());
|
||||||
|
|
||||||
|
me.authorize_with_seed(
|
||||||
|
authority_base,
|
||||||
|
&args.authority_seed,
|
||||||
|
&args.authority_owner,
|
||||||
|
authorized_pubkey,
|
||||||
|
args.stake_authorize,
|
||||||
|
true,
|
||||||
|
&clock,
|
||||||
|
custodian,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Err(InstructionError::InvalidInstructionData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
StakeInstruction::SetLockupChecked(lockup_checked) => {
|
||||||
|
if invoke_context.is_feature_active(&feature_set::vote_stake_checked_instructions::id())
|
||||||
|
{
|
||||||
|
let custodian = if let Ok(custodian) = keyed_account_at_index(keyed_accounts, 4) {
|
||||||
|
Some(
|
||||||
|
*custodian
|
||||||
|
.signer_key()
|
||||||
|
.ok_or(InstructionError::MissingRequiredSignature)?,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
let lockup = LockupArgs {
|
||||||
|
unix_timestamp: lockup_checked.unix_timestamp,
|
||||||
|
epoch: lockup_checked.epoch,
|
||||||
|
custodian,
|
||||||
|
};
|
||||||
|
let clock = Some(get_sysvar::<Clock>(invoke_context, &sysvar::clock::id())?);
|
||||||
|
me.set_lockup(&lockup, &signers, clock.as_ref())
|
||||||
|
} else {
|
||||||
|
Err(InstructionError::InvalidInstructionData)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -111,6 +111,18 @@ pub enum VoteInstruction {
|
||||||
/// 2. [] Clock sysvar
|
/// 2. [] Clock sysvar
|
||||||
/// 3. [SIGNER] Vote authority
|
/// 3. [SIGNER] Vote authority
|
||||||
VoteSwitch(Vote, Hash),
|
VoteSwitch(Vote, Hash),
|
||||||
|
|
||||||
|
/// Authorize a key to send votes or issue a withdrawal
|
||||||
|
///
|
||||||
|
/// This instruction behaves like `Authorize` with the additional requirement that the new vote
|
||||||
|
/// or withdraw authority must also be a signer.
|
||||||
|
///
|
||||||
|
/// # Account references
|
||||||
|
/// 0. [WRITE] Vote account to be updated with the Pubkey for authorization
|
||||||
|
/// 1. [] Clock sysvar
|
||||||
|
/// 2. [SIGNER] Vote or withdraw authority
|
||||||
|
/// 3. [SIGNER] New vote or withdraw authority
|
||||||
|
AuthorizeChecked(VoteAuthorize),
|
||||||
}
|
}
|
||||||
|
|
||||||
fn initialize_account(vote_pubkey: &Pubkey, vote_init: &VoteInit) -> Instruction {
|
fn initialize_account(vote_pubkey: &Pubkey, vote_init: &VoteInit) -> Instruction {
|
||||||
|
@ -182,6 +194,26 @@ pub fn authorize(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn authorize_checked(
|
||||||
|
vote_pubkey: &Pubkey,
|
||||||
|
authorized_pubkey: &Pubkey, // currently authorized
|
||||||
|
new_authorized_pubkey: &Pubkey,
|
||||||
|
vote_authorize: VoteAuthorize,
|
||||||
|
) -> Instruction {
|
||||||
|
let account_metas = vec![
|
||||||
|
AccountMeta::new(*vote_pubkey, false),
|
||||||
|
AccountMeta::new_readonly(sysvar::clock::id(), false),
|
||||||
|
AccountMeta::new_readonly(*authorized_pubkey, true),
|
||||||
|
AccountMeta::new_readonly(*new_authorized_pubkey, true),
|
||||||
|
];
|
||||||
|
|
||||||
|
Instruction::new_with_bincode(
|
||||||
|
id(),
|
||||||
|
&VoteInstruction::AuthorizeChecked(vote_authorize),
|
||||||
|
account_metas,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn update_validator_identity(
|
pub fn update_validator_identity(
|
||||||
vote_pubkey: &Pubkey,
|
vote_pubkey: &Pubkey,
|
||||||
authorized_withdrawer_pubkey: &Pubkey,
|
authorized_withdrawer_pubkey: &Pubkey,
|
||||||
|
@ -335,6 +367,23 @@ pub fn process_instruction(
|
||||||
let to = keyed_account_at_index(keyed_accounts, 1)?;
|
let to = keyed_account_at_index(keyed_accounts, 1)?;
|
||||||
vote_state::withdraw(me, lamports, to, &signers)
|
vote_state::withdraw(me, lamports, to, &signers)
|
||||||
}
|
}
|
||||||
|
VoteInstruction::AuthorizeChecked(vote_authorize) => {
|
||||||
|
if invoke_context.is_feature_active(&feature_set::vote_stake_checked_instructions::id())
|
||||||
|
{
|
||||||
|
let voter_pubkey = &keyed_account_at_index(keyed_accounts, 3)?
|
||||||
|
.signer_key()
|
||||||
|
.ok_or(InstructionError::MissingRequiredSignature)?;
|
||||||
|
vote_state::authorize(
|
||||||
|
me,
|
||||||
|
voter_pubkey,
|
||||||
|
vote_authorize,
|
||||||
|
&signers,
|
||||||
|
&from_keyed_account::<Clock>(keyed_account_at_index(keyed_accounts, 1)?)?,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Err(InstructionError::InvalidInstructionData)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -167,6 +167,61 @@ pub enum StakeInstruction {
|
||||||
/// 3. Optional: [SIGNER] Lockup authority, if updating StakeAuthorize::Withdrawer before
|
/// 3. Optional: [SIGNER] Lockup authority, if updating StakeAuthorize::Withdrawer before
|
||||||
/// lockup expiration
|
/// lockup expiration
|
||||||
AuthorizeWithSeed(AuthorizeWithSeedArgs),
|
AuthorizeWithSeed(AuthorizeWithSeedArgs),
|
||||||
|
|
||||||
|
/// Initialize a stake with authorization information
|
||||||
|
///
|
||||||
|
/// This instruction is similar to `Initialize` except that the withdraw authority
|
||||||
|
/// must be a signer, and no lockup is applied to the account.
|
||||||
|
///
|
||||||
|
/// # Account references
|
||||||
|
/// 0. [WRITE] Uninitialized stake account
|
||||||
|
/// 1. [] Rent sysvar
|
||||||
|
/// 2. [] The stake authority
|
||||||
|
/// 3. [SIGNER] The withdraw authority
|
||||||
|
///
|
||||||
|
InitializeChecked,
|
||||||
|
|
||||||
|
/// Authorize a key to manage stake or withdrawal
|
||||||
|
///
|
||||||
|
/// This instruction behaves like `Authorize` with the additional requirement that the new
|
||||||
|
/// stake or withdraw authority must also be a signer.
|
||||||
|
///
|
||||||
|
/// # Account references
|
||||||
|
/// 0. [WRITE] Stake account to be updated
|
||||||
|
/// 1. [] Clock sysvar
|
||||||
|
/// 2. [SIGNER] The stake or withdraw authority
|
||||||
|
/// 3. [SIGNER] The new stake or withdraw authority
|
||||||
|
/// 4. Optional: [SIGNER] Lockup authority, if updating StakeAuthorize::Withdrawer before
|
||||||
|
/// lockup expiration
|
||||||
|
AuthorizeChecked(StakeAuthorize),
|
||||||
|
|
||||||
|
/// Authorize a key to manage stake or withdrawal with a derived key
|
||||||
|
///
|
||||||
|
/// This instruction behaves like `AuthorizeWithSeed` with the additional requirement that
|
||||||
|
/// the new stake or withdraw authority must also be a signer.
|
||||||
|
///
|
||||||
|
/// # Account references
|
||||||
|
/// 0. [WRITE] Stake account to be updated
|
||||||
|
/// 1. [SIGNER] Base key of stake or withdraw authority
|
||||||
|
/// 2. [] Clock sysvar
|
||||||
|
/// 3. [SIGNER] The new stake or withdraw authority
|
||||||
|
/// 4. Optional: [SIGNER] Lockup authority, if updating StakeAuthorize::Withdrawer before
|
||||||
|
/// lockup expiration
|
||||||
|
AuthorizeCheckedWithSeed(AuthorizeCheckedWithSeedArgs),
|
||||||
|
|
||||||
|
/// Set stake lockup
|
||||||
|
///
|
||||||
|
/// This instruction behaves like `SetLockup` with the additional requirement that
|
||||||
|
/// the new lockup authority also be a signer.
|
||||||
|
///
|
||||||
|
/// If a lockup is not active, the withdraw authority may set a new lockup
|
||||||
|
/// If a lockup is active, the lockup custodian may update the lockup parameters
|
||||||
|
///
|
||||||
|
/// # Account references
|
||||||
|
/// 0. [WRITE] Initialized stake account
|
||||||
|
/// 1. [SIGNER] Lockup authority or withdraw authority
|
||||||
|
/// 2. Optional: [SIGNER] New lockup authority
|
||||||
|
SetLockupChecked(LockupCheckedArgs),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Debug, Serialize, Deserialize, PartialEq, Clone, Copy)]
|
#[derive(Default, Debug, Serialize, Deserialize, PartialEq, Clone, Copy)]
|
||||||
|
@ -176,6 +231,12 @@ pub struct LockupArgs {
|
||||||
pub custodian: Option<Pubkey>,
|
pub custodian: Option<Pubkey>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Debug, Serialize, Deserialize, PartialEq, Clone, Copy)]
|
||||||
|
pub struct LockupCheckedArgs {
|
||||||
|
pub unix_timestamp: Option<UnixTimestamp>,
|
||||||
|
pub epoch: Option<Epoch>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
|
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
|
||||||
pub struct AuthorizeWithSeedArgs {
|
pub struct AuthorizeWithSeedArgs {
|
||||||
pub new_authorized_pubkey: Pubkey,
|
pub new_authorized_pubkey: Pubkey,
|
||||||
|
@ -184,6 +245,13 @@ pub struct AuthorizeWithSeedArgs {
|
||||||
pub authority_owner: Pubkey,
|
pub authority_owner: Pubkey,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
|
||||||
|
pub struct AuthorizeCheckedWithSeedArgs {
|
||||||
|
pub stake_authorize: StakeAuthorize,
|
||||||
|
pub authority_seed: String,
|
||||||
|
pub authority_owner: Pubkey,
|
||||||
|
}
|
||||||
|
|
||||||
pub fn initialize(stake_pubkey: &Pubkey, authorized: &Authorized, lockup: &Lockup) -> Instruction {
|
pub fn initialize(stake_pubkey: &Pubkey, authorized: &Authorized, lockup: &Lockup) -> Instruction {
|
||||||
Instruction::new_with_bincode(
|
Instruction::new_with_bincode(
|
||||||
id(),
|
id(),
|
||||||
|
@ -195,6 +263,19 @@ pub fn initialize(stake_pubkey: &Pubkey, authorized: &Authorized, lockup: &Locku
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn initialize_checked(stake_pubkey: &Pubkey, authorized: &Authorized) -> Instruction {
|
||||||
|
Instruction::new_with_bincode(
|
||||||
|
id(),
|
||||||
|
&StakeInstruction::InitializeChecked,
|
||||||
|
vec![
|
||||||
|
AccountMeta::new(*stake_pubkey, false),
|
||||||
|
AccountMeta::new_readonly(sysvar::rent::id(), false),
|
||||||
|
AccountMeta::new_readonly(authorized.staker, false),
|
||||||
|
AccountMeta::new_readonly(authorized.withdrawer, true),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn create_account_with_seed(
|
pub fn create_account_with_seed(
|
||||||
from_pubkey: &Pubkey,
|
from_pubkey: &Pubkey,
|
||||||
stake_pubkey: &Pubkey,
|
stake_pubkey: &Pubkey,
|
||||||
|
@ -237,6 +318,46 @@ pub fn create_account(
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn create_account_with_seed_checked(
|
||||||
|
from_pubkey: &Pubkey,
|
||||||
|
stake_pubkey: &Pubkey,
|
||||||
|
base: &Pubkey,
|
||||||
|
seed: &str,
|
||||||
|
authorized: &Authorized,
|
||||||
|
lamports: u64,
|
||||||
|
) -> Vec<Instruction> {
|
||||||
|
vec![
|
||||||
|
system_instruction::create_account_with_seed(
|
||||||
|
from_pubkey,
|
||||||
|
stake_pubkey,
|
||||||
|
base,
|
||||||
|
seed,
|
||||||
|
lamports,
|
||||||
|
std::mem::size_of::<StakeState>() as u64,
|
||||||
|
&id(),
|
||||||
|
),
|
||||||
|
initialize_checked(stake_pubkey, authorized),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_account_checked(
|
||||||
|
from_pubkey: &Pubkey,
|
||||||
|
stake_pubkey: &Pubkey,
|
||||||
|
authorized: &Authorized,
|
||||||
|
lamports: u64,
|
||||||
|
) -> Vec<Instruction> {
|
||||||
|
vec![
|
||||||
|
system_instruction::create_account(
|
||||||
|
from_pubkey,
|
||||||
|
stake_pubkey,
|
||||||
|
lamports,
|
||||||
|
std::mem::size_of::<StakeState>() as u64,
|
||||||
|
&id(),
|
||||||
|
),
|
||||||
|
initialize_checked(stake_pubkey, authorized),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
fn _split(
|
fn _split(
|
||||||
stake_pubkey: &Pubkey,
|
stake_pubkey: &Pubkey,
|
||||||
authorized_pubkey: &Pubkey,
|
authorized_pubkey: &Pubkey,
|
||||||
|
@ -383,6 +504,31 @@ pub fn authorize(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn authorize_checked(
|
||||||
|
stake_pubkey: &Pubkey,
|
||||||
|
authorized_pubkey: &Pubkey,
|
||||||
|
new_authorized_pubkey: &Pubkey,
|
||||||
|
stake_authorize: StakeAuthorize,
|
||||||
|
custodian_pubkey: Option<&Pubkey>,
|
||||||
|
) -> Instruction {
|
||||||
|
let mut account_metas = vec![
|
||||||
|
AccountMeta::new(*stake_pubkey, false),
|
||||||
|
AccountMeta::new_readonly(sysvar::clock::id(), false),
|
||||||
|
AccountMeta::new_readonly(*authorized_pubkey, true),
|
||||||
|
AccountMeta::new_readonly(*new_authorized_pubkey, true),
|
||||||
|
];
|
||||||
|
|
||||||
|
if let Some(custodian_pubkey) = custodian_pubkey {
|
||||||
|
account_metas.push(AccountMeta::new_readonly(*custodian_pubkey, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
Instruction::new_with_bincode(
|
||||||
|
id(),
|
||||||
|
&StakeInstruction::AuthorizeChecked(stake_authorize),
|
||||||
|
account_metas,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn authorize_with_seed(
|
pub fn authorize_with_seed(
|
||||||
stake_pubkey: &Pubkey,
|
stake_pubkey: &Pubkey,
|
||||||
authority_base: &Pubkey,
|
authority_base: &Pubkey,
|
||||||
|
@ -416,6 +562,39 @@ pub fn authorize_with_seed(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn authorize_checked_with_seed(
|
||||||
|
stake_pubkey: &Pubkey,
|
||||||
|
authority_base: &Pubkey,
|
||||||
|
authority_seed: String,
|
||||||
|
authority_owner: &Pubkey,
|
||||||
|
new_authorized_pubkey: &Pubkey,
|
||||||
|
stake_authorize: StakeAuthorize,
|
||||||
|
custodian_pubkey: Option<&Pubkey>,
|
||||||
|
) -> Instruction {
|
||||||
|
let mut account_metas = vec![
|
||||||
|
AccountMeta::new(*stake_pubkey, false),
|
||||||
|
AccountMeta::new_readonly(*authority_base, true),
|
||||||
|
AccountMeta::new_readonly(sysvar::clock::id(), false),
|
||||||
|
AccountMeta::new_readonly(*new_authorized_pubkey, true),
|
||||||
|
];
|
||||||
|
|
||||||
|
if let Some(custodian_pubkey) = custodian_pubkey {
|
||||||
|
account_metas.push(AccountMeta::new_readonly(*custodian_pubkey, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
let args = AuthorizeCheckedWithSeedArgs {
|
||||||
|
stake_authorize,
|
||||||
|
authority_seed,
|
||||||
|
authority_owner: *authority_owner,
|
||||||
|
};
|
||||||
|
|
||||||
|
Instruction::new_with_bincode(
|
||||||
|
id(),
|
||||||
|
&StakeInstruction::AuthorizeCheckedWithSeed(args),
|
||||||
|
account_metas,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn delegate_stake(
|
pub fn delegate_stake(
|
||||||
stake_pubkey: &Pubkey,
|
stake_pubkey: &Pubkey,
|
||||||
authorized_pubkey: &Pubkey,
|
authorized_pubkey: &Pubkey,
|
||||||
|
@ -475,6 +654,30 @@ pub fn set_lockup(
|
||||||
Instruction::new_with_bincode(id(), &StakeInstruction::SetLockup(*lockup), account_metas)
|
Instruction::new_with_bincode(id(), &StakeInstruction::SetLockup(*lockup), account_metas)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_lockup_checked(
|
||||||
|
stake_pubkey: &Pubkey,
|
||||||
|
lockup: &LockupArgs,
|
||||||
|
custodian_pubkey: &Pubkey,
|
||||||
|
) -> Instruction {
|
||||||
|
let mut account_metas = vec![
|
||||||
|
AccountMeta::new(*stake_pubkey, false),
|
||||||
|
AccountMeta::new_readonly(*custodian_pubkey, true),
|
||||||
|
];
|
||||||
|
|
||||||
|
let lockup_checked = LockupCheckedArgs {
|
||||||
|
unix_timestamp: lockup.unix_timestamp,
|
||||||
|
epoch: lockup.epoch,
|
||||||
|
};
|
||||||
|
if let Some(new_custodian) = lockup.custodian {
|
||||||
|
account_metas.push(AccountMeta::new_readonly(new_custodian, true));
|
||||||
|
}
|
||||||
|
Instruction::new_with_bincode(
|
||||||
|
id(),
|
||||||
|
&StakeInstruction::SetLockupChecked(lockup_checked),
|
||||||
|
account_metas,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
|
@ -147,6 +147,10 @@ pub mod verify_tx_signatures_len {
|
||||||
solana_sdk::declare_id!("EVW9B5xD9FFK7vw1SBARwMA4s5eRo5eKJdKpsBikzKBz");
|
solana_sdk::declare_id!("EVW9B5xD9FFK7vw1SBARwMA4s5eRo5eKJdKpsBikzKBz");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub mod vote_stake_checked_instructions {
|
||||||
|
solana_sdk::declare_id!("BcWknVcgvonN8sL4HE4XFuEVgfcee5MwxWPAgP6ZV89X");
|
||||||
|
}
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
/// Map of feature identifiers to user-visible description
|
/// Map of feature identifiers to user-visible description
|
||||||
pub static ref FEATURE_NAMES: HashMap<Pubkey, &'static str> = [
|
pub static ref FEATURE_NAMES: HashMap<Pubkey, &'static str> = [
|
||||||
|
@ -183,6 +187,7 @@ lazy_static! {
|
||||||
(system_transfer_zero_check::id(), "perform all checks for transfers of 0 lamports"),
|
(system_transfer_zero_check::id(), "perform all checks for transfers of 0 lamports"),
|
||||||
(blake3_syscall_enabled::id(), "blake3 syscall"),
|
(blake3_syscall_enabled::id(), "blake3 syscall"),
|
||||||
(dedupe_config_program_signers::id(), "dedupe config program signers"),
|
(dedupe_config_program_signers::id(), "dedupe config program signers"),
|
||||||
|
(vote_stake_checked_instructions::id(), "vote/state program checked instructions #18345"),
|
||||||
/*************** ADD NEW FEATURES HERE ***************/
|
/*************** ADD NEW FEATURES HERE ***************/
|
||||||
]
|
]
|
||||||
.iter()
|
.iter()
|
||||||
|
|
Loading…
Reference in New Issue