Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

solana: Add set_threshold ix #589

Merged
merged 12 commits into from
Feb 27, 2025
7 changes: 5 additions & 2 deletions solana/programs/example-native-token-transfers/src/bitmap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,11 @@ impl Bitmap {
.expect("Bitmap length must not exceed the bounds of u8")
}

pub fn len(self) -> usize {
BM::<128>::from_value(self.map).len()
pub fn len(self) -> u8 {
BM::<128>::from_value(self.map)
.len()
.try_into()
.expect("Bitmap length must not exceed the bounds of u8")
}

pub fn is_empty(self) -> bool {
Expand Down
4 changes: 4 additions & 0 deletions solana/programs/example-native-token-transfers/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ pub enum NTTError {
IncorrectRentPayer,
#[msg("InvalidMultisig")]
InvalidMultisig,
#[msg("ThresholdTooHigh")]
ThresholdTooHigh,
#[msg("InvalidTransceiverProgram")]
InvalidTransceiverProgram,
}

impl From<ScalingError> for NTTError {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use ntt_messages::chain_id::ChainId;

use crate::{
config::Config,
error::NTTError,
peer::NttManagerPeer,
queue::{inbox::InboxRateLimit, outbox::OutboxRateLimit, rate_limit::RateLimitState},
registered_transceiver::RegisteredTransceiver,
Expand Down Expand Up @@ -76,7 +77,7 @@ pub fn set_peer(ctx: Context<SetPeer>, args: SetPeerArgs) -> Result<()> {
Ok(())
}

// * Register transceivers
// * Transceiver registration

#[derive(Accounts)]
pub struct RegisterTransceiver<'info> {
Expand All @@ -91,13 +92,16 @@ pub struct RegisterTransceiver<'info> {
#[account(mut)]
pub payer: Signer<'info>,

#[account(executable)]
#[account(
executable,
constraint = transceiver.key() != Pubkey::default() @ NTTError::InvalidTransceiverProgram
)]
/// CHECK: transceiver is meant to be a transceiver program. Arguably a `Program` constraint could be
/// used here that wraps the Transceiver account type.
pub transceiver: UncheckedAccount<'info>,

#[account(
init,
init_if_needed,
space = 8 + RegisteredTransceiver::INIT_SPACE,
payer = payer,
seeds = [RegisteredTransceiver::SEED_PREFIX, transceiver.key().as_ref()],
Expand All @@ -109,17 +113,62 @@ pub struct RegisterTransceiver<'info> {
}

pub fn register_transceiver(ctx: Context<RegisterTransceiver>) -> Result<()> {
let id = ctx.accounts.config.next_transceiver_id;
ctx.accounts.config.next_transceiver_id += 1;
// initialize registered transceiver with new id on init
if ctx.accounts.registered_transceiver.transceiver_address == Pubkey::default() {
let id = ctx.accounts.config.next_transceiver_id;
ctx.accounts.config.next_transceiver_id += 1;
ctx.accounts
.registered_transceiver
.set_inner(RegisteredTransceiver {
bump: ctx.bumps.registered_transceiver,
id,
transceiver_address: ctx.accounts.transceiver.key(),
});
}

ctx.accounts
.registered_transceiver
.set_inner(RegisteredTransceiver {
bump: ctx.bumps.registered_transceiver,
id,
transceiver_address: ctx.accounts.transceiver.key(),
});

ctx.accounts.config.enabled_transceivers.set(id, true)?;
.config
.enabled_transceivers
.set(ctx.accounts.registered_transceiver.id, true)?;
Ok(())
}

#[derive(Accounts)]
pub struct DeregisterTransceiver<'info> {
#[account(
mut,
has_one = owner,
)]
pub config: Account<'info, Config>,

#[account(mut)]
pub owner: Signer<'info>,

#[account(executable)]
/// CHECK: transceiver is meant to be a transceiver program. Arguably a `Program` constraint could be
/// used here that wraps the Transceiver account type.
pub transceiver: UncheckedAccount<'info>,

#[account(
seeds = [RegisteredTransceiver::SEED_PREFIX, transceiver.key().as_ref()],
bump,
constraint = config.enabled_transceivers.get(registered_transceiver.id)? @ NTTError::DisabledTransceiver,
)]
pub registered_transceiver: Account<'info, RegisteredTransceiver>,
}

pub fn deregister_transceiver(ctx: Context<DeregisterTransceiver>) -> Result<()> {
ctx.accounts
.config
.enabled_transceivers
.set(ctx.accounts.registered_transceiver.id, false)?;

// decrement threshold if too high
let num_enabled_transceivers = ctx.accounts.config.enabled_transceivers.len();
if num_enabled_transceivers < ctx.accounts.config.threshold {
// threshold should be at least 1
ctx.accounts.config.threshold = num_enabled_transceivers.max(1);
}
Ok(())
}

Expand Down Expand Up @@ -200,3 +249,26 @@ pub fn set_paused(ctx: Context<SetPaused>, paused: bool) -> Result<()> {
ctx.accounts.config.paused = paused;
Ok(())
}

// * Set Threshold

#[derive(Accounts)]
#[instruction(threshold: u8)]
pub struct SetThreshold<'info> {
pub owner: Signer<'info>,

#[account(
mut,
has_one = owner,
constraint = threshold <= config.enabled_transceivers.len() @ NTTError::ThresholdTooHigh
)]
pub config: Account<'info, Config>,
}

pub fn set_threshold(ctx: Context<SetThreshold>, threshold: u8) -> Result<()> {
if threshold == 0 {
return Err(NTTError::ZeroThreshold.into());
}
ctx.accounts.config.threshold = threshold;
Ok(())
}
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ fn initialize_config_and_rate_limit(
pending_owner: None,
paused: false,
next_transceiver_id: 0,
// NOTE: can't be changed for now
// NOTE: can be changed via `set_threshold` ix
threshold: 1,
enabled_transceivers: Bitmap::new(),
custody: common.custody.key(),
Expand Down
8 changes: 8 additions & 0 deletions solana/programs/example-native-token-transfers/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,10 @@ pub mod example_native_token_transfers {
instructions::register_transceiver(ctx)
}

pub fn deregister_transceiver(ctx: Context<DeregisterTransceiver>) -> Result<()> {
instructions::deregister_transceiver(ctx)
}

pub fn set_outbound_limit(
ctx: Context<SetOutboundLimit>,
args: SetOutboundLimitArgs,
Expand All @@ -206,6 +210,10 @@ pub mod example_native_token_transfers {
instructions::mark_outbox_item_as_released(ctx)
}

pub fn set_threshold(ctx: Context<SetThreshold>, threshold: u8) -> Result<()> {
instructions::set_threshold(ctx, threshold)
}

// standalone transceiver stuff

pub fn set_wormhole_peer(
Expand Down
Loading
Loading