diff --git a/staking/cli/src/cli.rs b/staking/cli/src/cli.rs index 294dd485..904c687a 100644 --- a/staking/cli/src/cli.rs +++ b/staking/cli/src/cli.rs @@ -71,4 +71,30 @@ pub enum Action { #[clap(long, help = "New fee")] delegation_fee: u64, }, + SetPublisherStakeAccount { + #[clap(long, help = "Publisher")] + publisher: Pubkey, + #[clap(long, help = "Stake account positions")] + stake_account_positions: Pubkey, + }, + CreateSlashEvent { + #[clap(long, help = "Publisher")] + publisher: Pubkey, + #[clap(long, help = "Amount")] + slash_ratio: u64, + }, + UpdateRewardProgramAuthority { + #[clap(long, help = "New reward program authority")] + new_reward_program_authority: Pubkey, + }, + Slash { + #[clap(long, help = "Publisher")] + publisher: Pubkey, + #[clap(long, help = "Stake account positions")] + stake_account_positions: Pubkey, + }, + UpdateY { + #[clap(long, help = "New Y")] + y: u64, + }, } diff --git a/staking/cli/src/instructions.rs b/staking/cli/src/instructions.rs index 945f24a1..a069b62f 100644 --- a/staking/cli/src/instructions.rs +++ b/staking/cli/src/instructions.rs @@ -11,14 +11,25 @@ use { base64::Engine, integration_tests::{ integrity_pool::pda::{ + get_delegation_record_address, get_pool_config_address, get_pool_reward_custody_address, + get_slash_event_address, + }, + staking::pda::{ + get_config_address, + get_stake_account_custody_address, + get_stake_account_custody_authority_address, + get_stake_account_metadata_address, + get_target_address, }, - staking::pda::get_config_address, }, - integrity_pool::state::pool::{ - PoolConfig, - PoolData, + integrity_pool::state::{ + delegation_record::DelegationRecord, + pool::{ + PoolConfig, + PoolData, + }, }, publisher_caps::PublisherCaps, pythnet_sdk::wire::v1::{ @@ -50,6 +61,7 @@ use { std::{ cmp::min, convert::TryInto, + mem::size_of, }, wormhole_core_bridge_solana::sdk::{ WriteEncodedVaaArgs, @@ -487,3 +499,210 @@ pub fn update_delegation_fee(rpc_client: &RpcClient, payer: &Keypair, delegation process_transaction(rpc_client, &[instruction], &[payer]); } + +pub fn set_publisher_stake_account( + rpc_client: &RpcClient, + signer: &Keypair, + publisher: &Pubkey, + stake_account_positions: &Pubkey, +) { + let pool_config = get_pool_config_address(); + + let PoolConfig { pool_data, .. } = PoolConfig::try_deserialize( + &mut rpc_client + .get_account_data(&pool_config) + .unwrap() + .as_slice(), + ) + .unwrap(); + + let accounts = integrity_pool::accounts::SetPublisherStakeAccount { + signer: signer.pubkey(), + publisher: *publisher, + current_stake_account_positions_option: None, + new_stake_account_positions_option: Some(*stake_account_positions), + pool_config, + pool_data, + }; + + let instruction_data = integrity_pool::instruction::SetPublisherStakeAccount {}; + + let instruction = Instruction { + program_id: integrity_pool::ID, + accounts: accounts.to_account_metas(None), + data: instruction_data.data(), + }; + + process_transaction(rpc_client, &[instruction], &[signer]); +} + +pub fn create_slash_event( + rpc_client: &RpcClient, + signer: &Keypair, + publisher: &Pubkey, + slash_ratio: u64, +) { + let pool_config = get_pool_config_address(); + + let PoolConfig { + pool_data: pool_data_address, + slash_custody, + .. + } = PoolConfig::try_deserialize( + &mut rpc_client + .get_account_data(&pool_config) + .unwrap() + .as_slice(), + ) + .unwrap(); + + let pool_data = PoolData::try_deserialize( + &mut rpc_client.get_account_data(&pool_data_address).unwrap()[..8 + size_of::()] + .as_ref(), + ) + .unwrap(); + + let publisher_index = pool_data.get_publisher_index(publisher).unwrap(); + let index = pool_data.num_slash_events[publisher_index]; + + let accounts = integrity_pool::accounts::CreateSlashEvent { + payer: signer.pubkey(), + reward_program_authority: signer.pubkey(), + publisher: *publisher, + slash_custody, + pool_config, + pool_data: pool_data_address, + slash_event: get_slash_event_address(index, *publisher), + system_program: system_program::ID, + }; + + let instruction_data = integrity_pool::instruction::CreateSlashEvent { index, slash_ratio }; + + let instruction = Instruction { + program_id: integrity_pool::ID, + accounts: accounts.to_account_metas(None), + data: instruction_data.data(), + }; + + process_transaction(rpc_client, &[instruction], &[signer]); +} + +pub fn update_reward_program_authority( + rpc_client: &RpcClient, + signer: &Keypair, + new_reward_program_authority: &Pubkey, +) { + let pool_config = get_pool_config_address(); + + let accounts = integrity_pool::accounts::UpdateRewardProgramAuthority { + reward_program_authority: signer.pubkey(), + pool_config, + system_program: system_program::ID, + }; + + let instruction_data = integrity_pool::instruction::UpdateRewardProgramAuthority { + reward_program_authority: *new_reward_program_authority, + }; + + let instruction = Instruction { + program_id: integrity_pool::ID, + accounts: accounts.to_account_metas(None), + data: instruction_data.data(), + }; + + process_transaction(rpc_client, &[instruction], &[signer]); +} + +pub fn slash( + rpc_client: &RpcClient, + signer: &Keypair, + publisher: &Pubkey, + stake_account_positions: &Pubkey, +) { + let pool_config = get_pool_config_address(); + let PoolConfig { + pool_data, + slash_custody, + .. + } = PoolConfig::try_deserialize( + &mut rpc_client + .get_account_data(&pool_config) + .unwrap() + .as_slice(), + ) + .unwrap(); + + let delegation_record = get_delegation_record_address(*publisher, *stake_account_positions); + let DelegationRecord { + next_slash_event_index, + .. + } = { + let delegation_record_account_data = rpc_client.get_account_data(&delegation_record); + if let Ok(data) = delegation_record_account_data { + DelegationRecord::try_deserialize(&mut data.as_slice()).unwrap() + } else { + DelegationRecord { + last_epoch: 0, + next_slash_event_index: 0, + } + } + }; + + + let stake_account_metadata = get_stake_account_metadata_address(*stake_account_positions); + let stake_account_custody = get_stake_account_custody_address(*stake_account_positions); + let custody_authority = get_stake_account_custody_authority_address(*stake_account_positions); + let config_account = get_config_address(); + let governance_target_account = get_target_address(); + + + let accounts = integrity_pool::accounts::Slash { + signer: signer.pubkey(), + pool_data, + pool_config, + slash_event: get_slash_event_address(next_slash_event_index, *publisher), + delegation_record, + publisher: *publisher, + stake_account_positions: *stake_account_positions, + stake_account_metadata, + stake_account_custody, + config_account, + governance_target_account, + slash_custody, + custody_authority, + staking_program: staking::ID, + token_program: spl_token::ID, + }; + + let instruction_data = integrity_pool::instruction::Slash { + index: next_slash_event_index, + }; + + let instruction = Instruction { + program_id: integrity_pool::ID, + accounts: accounts.to_account_metas(None), + data: instruction_data.data(), + }; + + process_transaction(rpc_client, &[instruction], &[signer]); +} + +pub fn update_y(rpc_client: &RpcClient, signer: &Keypair, y: u64) { + let pool_config = get_pool_config_address(); + + let accounts = integrity_pool::accounts::UpdateY { + reward_program_authority: signer.pubkey(), + pool_config, + system_program: system_program::ID, + }; + + let instruction_data = integrity_pool::instruction::UpdateY { y }; + + let instruction = Instruction { + program_id: integrity_pool::ID, + accounts: accounts.to_account_metas(None), + data: instruction_data.data(), + }; + + process_transaction(rpc_client, &[instruction], &[signer]); +} diff --git a/staking/cli/src/main.rs b/staking/cli/src/main.rs index 8ef6e954..4f2b50e3 100644 --- a/staking/cli/src/main.rs +++ b/staking/cli/src/main.rs @@ -8,10 +8,15 @@ use { Cli, }, instructions::{ + create_slash_event, fetch_publisher_caps_and_advance, initialize_pool, initialize_reward_custody, + set_publisher_stake_account, + slash, update_delegation_fee, + update_reward_program_authority, + update_y, }, solana_client::rpc_client::RpcClient, solana_sdk::commitment_config::CommitmentConfig, @@ -54,5 +59,23 @@ fn main() { Action::UpdateDelegationFee { delegation_fee } => { update_delegation_fee(&rpc_client, &keypair, delegation_fee) } + Action::SetPublisherStakeAccount { + publisher, + stake_account_positions, + } => { + set_publisher_stake_account(&rpc_client, &keypair, &publisher, &stake_account_positions) + } + Action::CreateSlashEvent { + publisher, + slash_ratio, + } => create_slash_event(&rpc_client, &keypair, &publisher, slash_ratio), + Action::UpdateRewardProgramAuthority { + new_reward_program_authority, + } => update_reward_program_authority(&rpc_client, &keypair, &new_reward_program_authority), + Action::Slash { + publisher, + stake_account_positions, + } => slash(&rpc_client, &keypair, &publisher, &stake_account_positions), + Action::UpdateY { y } => update_y(&rpc_client, &keypair, y), } }