-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: edit_controller_authority IX (#337)
## Summary In order to fully migrate the UXD-Program to the new redemption DAO, we need to be able to migrate its authority pubkey. This PR provides a simple implementation for the authority to be transfered to a different pubkey.
- Loading branch information
1 parent
7d31b06
commit b860eaa
Showing
8 changed files
with
284 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
32 changes: 32 additions & 0 deletions
32
programs/uxd/src/instructions/edit_controller_authority.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
use crate::error::UxdError; | ||
use crate::validate_is_program_frozen; | ||
use crate::Controller; | ||
use crate::CONTROLLER_NAMESPACE; | ||
use anchor_lang::prelude::*; | ||
|
||
#[derive(Accounts)] | ||
pub struct EditControllerAuthority<'info> { | ||
/// #1 Authored call accessible only to the signer matching Controller.authority | ||
pub authority: Signer<'info>, | ||
/// #2 The top level UXDProgram on chain account managing the redeemable mint | ||
#[account( | ||
mut, | ||
seeds = [CONTROLLER_NAMESPACE], | ||
bump = controller.load()?.bump, | ||
has_one = authority @UxdError::InvalidAuthority, | ||
)] | ||
pub controller: AccountLoader<'info, Controller>, | ||
} | ||
|
||
pub(crate) fn handler(ctx: Context<EditControllerAuthority>, authority: &Pubkey) -> Result<()> { | ||
let controller = &mut ctx.accounts.controller.load_mut()?; | ||
controller.authority = *authority; | ||
Ok(()) | ||
} | ||
|
||
impl<'info> EditControllerAuthority<'info> { | ||
pub(crate) fn validate(&self, _authority: &Pubkey) -> Result<()> { | ||
validate_is_program_frozen(self.controller.load()?)?; | ||
Ok(()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
60 changes: 60 additions & 0 deletions
60
...tests/integration_tests/api/program_uxd/instructions/process_edit_controller_authority.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
use anchor_lang::InstructionData; | ||
use anchor_lang::ToAccountMetas; | ||
use solana_sdk::instruction::Instruction; | ||
use solana_sdk::pubkey::Pubkey; | ||
use solana_sdk::signature::Keypair; | ||
use solana_sdk::signer::Signer; | ||
|
||
use uxd::state::Controller; | ||
|
||
use crate::integration_tests::api::program_context; | ||
use crate::integration_tests::api::program_uxd; | ||
|
||
pub async fn process_edit_controller_authority( | ||
program_context: &mut Box<dyn program_context::ProgramContext>, | ||
payer: &Keypair, | ||
authority: &Keypair, | ||
new_authority: &Pubkey, | ||
) -> Result<(), program_context::ProgramError> { | ||
// Find needed accounts | ||
let controller = program_uxd::accounts::find_controller_pda().0; | ||
|
||
// Read state before | ||
let controller_before = | ||
program_context::read_account_anchor::<Controller>(program_context, &controller).await?; | ||
|
||
// Execute IX | ||
let accounts = uxd::accounts::EditControllerAuthority { | ||
authority: authority.pubkey(), | ||
controller, | ||
}; | ||
let payload = uxd::instruction::EditControllerAuthority { | ||
authority: *new_authority, | ||
}; | ||
let instruction = Instruction { | ||
program_id: uxd::id(), | ||
accounts: accounts.to_account_metas(None), | ||
data: payload.data(), | ||
}; | ||
program_context::process_instruction_with_signer( | ||
program_context, | ||
instruction, | ||
payer, | ||
authority, | ||
) | ||
.await?; | ||
|
||
// Read state after | ||
let controller_after = | ||
program_context::read_account_anchor::<Controller>(program_context, &controller).await?; | ||
|
||
// Check behaviour | ||
let controller_authority_before = controller_before.authority; | ||
assert_eq!(controller_authority_before, authority.pubkey()); | ||
|
||
let controller_authority_after = controller_after.authority; | ||
assert_eq!(controller_authority_after, *new_authority); | ||
|
||
// Done | ||
Ok(()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
171 changes: 171 additions & 0 deletions
171
programs/uxd/tests/integration_tests/suites/test_controller_edit_authority.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,171 @@ | ||
use solana_program_test::tokio; | ||
use solana_sdk::signer::keypair::Keypair; | ||
use solana_sdk::signer::Signer; | ||
use uxd::instructions::EditControllerFields; | ||
|
||
use crate::integration_tests::api::program_context; | ||
use crate::integration_tests::api::program_uxd; | ||
|
||
#[tokio::test] | ||
async fn test_controller_edit_authority() -> Result<(), program_context::ProgramError> { | ||
// --------------------------------------------------------------------- | ||
// -- Phase 1 | ||
// -- Setup basic context and accounts needed for this test suite | ||
// --------------------------------------------------------------------- | ||
|
||
let mut program_context: Box<dyn program_context::ProgramContext> = | ||
Box::new(program_context::create_program_test_context().await); | ||
|
||
// Fund payer | ||
let payer = Keypair::new(); | ||
program_context | ||
.process_airdrop(&payer.pubkey(), 1_000_000_000_000) | ||
.await?; | ||
|
||
// Hardcode mints decimals | ||
let collateral_mint_decimals = 6; | ||
let redeemable_mint_decimals = 6; | ||
|
||
// Important account keys | ||
let authority = Keypair::new(); | ||
let collateral_mint = Keypair::new(); | ||
let mercurial_vault_lp_mint = Keypair::new(); | ||
let credix_multisig = Keypair::new(); | ||
|
||
// Initialize basic UXD program state | ||
program_uxd::procedures::process_deploy_program( | ||
&mut program_context, | ||
&payer, | ||
&authority, | ||
&collateral_mint, | ||
&mercurial_vault_lp_mint, | ||
&credix_multisig, | ||
collateral_mint_decimals, | ||
redeemable_mint_decimals, | ||
) | ||
.await?; | ||
|
||
// --------------------------------------------------------------------- | ||
// -- Phase 2 | ||
// -- Change the controller authority back and forth | ||
// --------------------------------------------------------------------- | ||
|
||
let old_authority = authority; | ||
let new_authority = Keypair::new(); | ||
|
||
// Using the wrong authority should fail | ||
assert!( | ||
program_uxd::instructions::process_edit_controller_authority( | ||
&mut program_context, | ||
&payer, | ||
&payer, | ||
&new_authority.pubkey(), | ||
) | ||
.await | ||
.is_err() | ||
); | ||
|
||
// Using the correct authority should succeed | ||
program_uxd::instructions::process_edit_controller_authority( | ||
&mut program_context, | ||
&payer, | ||
&old_authority, | ||
&new_authority.pubkey(), | ||
) | ||
.await?; | ||
|
||
// After changing the authority we cant use it again | ||
assert!( | ||
program_uxd::instructions::process_edit_controller_authority( | ||
&mut program_context, | ||
&payer, | ||
&old_authority, | ||
&new_authority.pubkey(), | ||
) | ||
.await | ||
.is_err() | ||
); | ||
|
||
// The new authority can use it now | ||
program_uxd::instructions::process_edit_controller_authority( | ||
&mut program_context, | ||
&payer, | ||
&new_authority, | ||
&new_authority.pubkey(), | ||
) | ||
.await?; | ||
|
||
// The old authority can not use the program anymore, but the new one can | ||
assert!(program_uxd::instructions::process_edit_controller( | ||
&mut program_context, | ||
&payer, | ||
&old_authority, | ||
&EditControllerFields { | ||
redeemable_global_supply_cap: None, | ||
depositories_routing_weight_bps: None, | ||
router_depositories: None, | ||
outflow_limit_per_epoch_amount: None, | ||
outflow_limit_per_epoch_bps: None, | ||
slots_per_epoch: None, | ||
}, | ||
) | ||
.await | ||
.is_err()); | ||
program_uxd::instructions::process_edit_controller( | ||
&mut program_context, | ||
&payer, | ||
&new_authority, | ||
&EditControllerFields { | ||
redeemable_global_supply_cap: None, | ||
depositories_routing_weight_bps: None, | ||
router_depositories: None, | ||
outflow_limit_per_epoch_amount: None, | ||
outflow_limit_per_epoch_bps: None, | ||
slots_per_epoch: None, | ||
}, | ||
) | ||
.await?; | ||
|
||
// The new authority can send the authority again back to the old one | ||
program_uxd::instructions::process_edit_controller_authority( | ||
&mut program_context, | ||
&payer, | ||
&new_authority, | ||
&old_authority.pubkey(), | ||
) | ||
.await?; | ||
|
||
// The new authority can not use the program anymore, but the old one can | ||
assert!(program_uxd::instructions::process_edit_controller( | ||
&mut program_context, | ||
&payer, | ||
&new_authority, | ||
&EditControllerFields { | ||
redeemable_global_supply_cap: None, | ||
depositories_routing_weight_bps: None, | ||
router_depositories: None, | ||
outflow_limit_per_epoch_amount: None, | ||
outflow_limit_per_epoch_bps: None, | ||
slots_per_epoch: None, | ||
}, | ||
) | ||
.await | ||
.is_err()); | ||
program_uxd::instructions::process_edit_controller( | ||
&mut program_context, | ||
&payer, | ||
&old_authority, | ||
&EditControllerFields { | ||
redeemable_global_supply_cap: None, | ||
depositories_routing_weight_bps: None, | ||
router_depositories: None, | ||
outflow_limit_per_epoch_amount: None, | ||
outflow_limit_per_epoch_bps: None, | ||
slots_per_epoch: None, | ||
}, | ||
) | ||
.await?; | ||
|
||
// Done | ||
Ok(()) | ||
} |