use borsh::{BorshDeserialize, BorshSerialize};
use solana_program::pubkey::Pubkey;
use solana_program::secp256k1_recover::{SECP256K1_PUBLIC_KEY_LENGTH, SECP256K1_SIGNATURE_LENGTH};
use solana_program::instruction::{Instruction, AccountMeta};
use crate::PDA_ADMIN_SEED;
#[repr(C)]
#[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug, Clone)]
pub struct InitializeAdminArgs {
pub public_key: [u8; SECP256K1_PUBLIC_KEY_LENGTH],
pub contract: Pubkey,
}
#[repr(C)]
#[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug, Clone)]
pub struct ChangePublicKeyArgs {
pub new_public_key: [u8; SECP256K1_PUBLIC_KEY_LENGTH],
pub signature: [u8; SECP256K1_SIGNATURE_LENGTH],
pub recovery_id: u8,
}
#[repr(C)]
#[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug, Clone)]
pub struct ChangeAuthorityArgs {
pub signature: [u8; SECP256K1_SIGNATURE_LENGTH],
pub recovery_id: u8,
}
#[repr(C)]
#[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug, Clone)]
pub struct UpgradeArgs {
pub signature: [u8; SECP256K1_PUBLIC_KEY_LENGTH],
pub recovery_id: u8,
}
#[repr(C)]
#[derive(BorshSerialize, BorshDeserialize, Clone)]
pub enum UpgradeInstruction {
InitializeAdmin(InitializeAdminArgs),
ChangePublicKey(ChangePublicKeyArgs),
ChangeAuthority(ChangeAuthorityArgs),
Upgrade(UpgradeArgs),
}
pub fn initialize_admin(
program_id: Pubkey,
contract: Pubkey,
fee_payer: Pubkey,
public_key: [u8; SECP256K1_PUBLIC_KEY_LENGTH],
) -> Instruction {
let (admin, _) = Pubkey::find_program_address(&[PDA_ADMIN_SEED.as_bytes(), contract.as_ref()], &program_id);
Instruction{
program_id,
data: UpgradeInstruction::InitializeAdmin(
InitializeAdminArgs {
public_key,
contract: Default::default(),
}
).try_to_vec().unwrap(),
accounts: vec![
AccountMeta::new(admin, false),
AccountMeta::new(fee_payer, true),
AccountMeta::new_readonly(solana_program::system_program::id(), false),
AccountMeta::new_readonly(solana_program::sysvar::clock::id(), false),
],
}
}
pub fn change_public_key(
program_id: Pubkey,
contract: Pubkey,
new_public_key: [u8; SECP256K1_PUBLIC_KEY_LENGTH],
signature: [u8; SECP256K1_SIGNATURE_LENGTH],
recovery_id: u8,
) -> Instruction {
let (admin, _) = Pubkey::find_program_address(&[PDA_ADMIN_SEED.as_bytes(), contract.as_ref()], &program_id);
Instruction{
program_id,
data: UpgradeInstruction::ChangePublicKey(
ChangePublicKeyArgs {
new_public_key,
signature,
recovery_id,
}
).try_to_vec().unwrap(),
accounts: vec![
AccountMeta::new(admin, false),
],
}
}
pub fn change_authority(
program_id: Pubkey,
contract: Pubkey,
new_authority: Pubkey,
signature: [u8; SECP256K1_SIGNATURE_LENGTH],
recovery_id: u8,
) -> Instruction {
let (admin, _) = Pubkey::find_program_address(&[PDA_ADMIN_SEED.as_bytes(), contract.as_ref()], &program_id);
let (program_data, _) = Pubkey::find_program_address(&[contract.as_ref()], &solana_program::bpf_loader_upgradeable::id());
Instruction{
program_id,
data: UpgradeInstruction::ChangeAuthority(
ChangeAuthorityArgs {
signature,
recovery_id,
}
).try_to_vec().unwrap(),
accounts: vec![
AccountMeta::new(admin, false),
AccountMeta::new(program_data, false),
AccountMeta::new(new_authority, false),
AccountMeta::new(solana_program::bpf_loader_upgradeable::id(), false),
],
}
}
pub fn upgrade(
program_id: Pubkey,
contract: Pubkey,
buffer: Pubkey,
spill: Pubkey,
signature: [u8; SECP256K1_SIGNATURE_LENGTH],
recovery_id: u8,
) -> Instruction {
let (admin, _) = Pubkey::find_program_address(&[PDA_ADMIN_SEED.as_bytes(), contract.as_ref()], &program_id);
let (program_data, _) = Pubkey::find_program_address(&[contract.as_ref()], &solana_program::bpf_loader_upgradeable::id());
Instruction {
program_id,
data: UpgradeInstruction::Upgrade(
UpgradeArgs {
signature,
recovery_id,
}
).try_to_vec().unwrap(),
accounts: vec![
AccountMeta::new(admin, false),
AccountMeta::new(program_data, false),
AccountMeta::new(contract, false),
AccountMeta::new(buffer, false),
AccountMeta::new(spill, false),
AccountMeta::new(solana_program::sysvar::rent::id(), false),
AccountMeta::new(solana_program::sysvar::clock::id(), false),
AccountMeta::new(solana_program::bpf_loader_upgradeable::id(), false),
],
}
}