diff --git a/Cargo.lock b/Cargo.lock index cb0766b..268225d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1307,6 +1307,14 @@ version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99" +[[package]] +name = "validator" +version = "0.1.0" +dependencies = [ + "anchor-lang", + "squads-mpl", +] + [[package]] name = "version_check" version = "0.9.4" diff --git a/programs/validator/Cargo.toml b/programs/validator/Cargo.toml new file mode 100644 index 0000000..6651d2d --- /dev/null +++ b/programs/validator/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "validator" +version = "0.1.0" +description = "Created with Anchor" +edition = "2021" + +[lib] +crate-type = ["cdylib", "lib"] +name = "validator" + +[features] +no-entrypoint = [] +no-idl = [] +no-log-ix-name = [] +cpi = ["no-entrypoint"] +default = [] + +[dependencies] +anchor-lang = "0.25.0" +squads-mpl = { path = "../squads-mpl", features = ["cpi"] } \ No newline at end of file diff --git a/programs/validator/Xargo.toml b/programs/validator/Xargo.toml new file mode 100644 index 0000000..475fb71 --- /dev/null +++ b/programs/validator/Xargo.toml @@ -0,0 +1,2 @@ +[target.bpfel-unknown-unknown.dependencies.std] +features = [] diff --git a/programs/validator/src/lib.rs b/programs/validator/src/lib.rs new file mode 100644 index 0000000..3cae78e --- /dev/null +++ b/programs/validator/src/lib.rs @@ -0,0 +1,106 @@ +use anchor_lang::prelude::*; +use state::validator::*; +use squads_mpl::state::*; +use squads_mpl::errors::*; +pub mod state; + +declare_id!(""); + +#[program] +pub mod validator { + use anchor_lang::solana_program::{bpf_loader_upgradeable::upgrade}; + + use super::*; + + pub fn create_validator_manager(ctx: Context)-> Result<()>{ + let validator_manager = &mut ctx.accounts.validator_manager; + validator_manager.init( + ctx.accounts.multisig.key(), + *ctx.bumps.get("validator_manager").unwrap(), + ) + } + + pub fn create_managed_validator(ctx: Context, validator_address: Pubkey, name: String)->Result<()>{ + let managed_validator = &mut ctx.accounts.managed_validator; + let validator_manager = &mut ctx.accounts.validator_manager; + let new_mvi = validator_manager.managed_validator_index.checked_add(1).unwrap(); + managed_validator.init( + validator_address, + ctx.accounts.multisig.key(), + *ctx.bumps.get("managed_validator").unwrap(), + name, + new_mvi + )?; + validator_manager.managed_validator_index = new_mvi; + Ok(()) + } + + + +} + +#[derive(Accounts)] +pub struct CreateManager<'info> { + #[account( + owner = squads_mpl::ID, + constraint = matches!(multisig.is_member(creator.key()), Some(..)) @MsError::KeyNotInMultisig, + )] + pub multisig: Account<'info, Ms>, + + #[account( + init, + payer = creator, + space = ValidatorManager::MAXIMUM_SIZE, + seeds = [ + b"squad", + multisig.key().as_ref(), + b"vmanage" + ], + bump + )] + pub validator_manager: Account<'info,ValidatorManager>, + + #[account(mut)] + pub creator: Signer<'info>, + pub system_program: Program<'info, System> +} + + +#[derive(Accounts)] +#[instruction(program_address: Pubkey, name: String)] +pub struct CreateManagedValidator<'info> { + #[account( + owner = squads_mpl::ID, + constraint = matches!(multisig.is_member(creator.key()), Some(..)) @MsError::KeyNotInMultisig, + )] + pub multisig: Account<'info, Ms>, + + #[account( + mut, + seeds = [ + b"squad", + multisig.key().as_ref(), + b"vmanage" + ], + bump = validator_manager.bump + )] + pub validator_manager: Account<'info, ValidatorManager>, + + #[account( + init, + payer = creator, + space = ManagedValidator::MINIMUM_SIZE + name.try_to_vec().unwrap().len() + 4, + seeds = [ + b"squad", + validator_manager.key().as_ref(), + &validator_manager.managed_validator_index.checked_add(1).unwrap().to_le_bytes(), + b"validator" + ], + bump + )] + pub managed_validator: Account<'info,ManagedValidator>, + + #[account(mut)] + pub creator: Signer<'info>, + pub system_program: Program<'info, System> +} diff --git a/programs/validator/src/state/mod.rs b/programs/validator/src/state/mod.rs new file mode 100644 index 0000000..93ce9c9 --- /dev/null +++ b/programs/validator/src/state/mod.rs @@ -0,0 +1,2 @@ +pub use validator::*; +pub mod validator; \ No newline at end of file diff --git a/programs/validator/src/state/validator.rs b/programs/validator/src/state/validator.rs new file mode 100644 index 0000000..849b141 --- /dev/null +++ b/programs/validator/src/state/validator.rs @@ -0,0 +1,50 @@ +use anchor_lang::{prelude::*, solana_program::instruction::Instruction}; +use anchor_lang::solana_program::borsh::get_instance_packed_len; + +#[account] +pub struct ValidatorManager { + pub multisig: Pubkey, + pub managed_validator_index: u32, + pub bump: u8, +} + +impl ValidatorManager { + pub const MAXIMUM_SIZE: usize = 8 + // anchor discriminator + 32 + // multisig key (used to derive as well) + 4 + // to track the validators + 1; // bump + + pub fn init(&mut self, multisig: Pubkey, bump: u8) -> Result<()>{ + self.multisig = multisig; + self.bump = bump; + self.managed_validator_index = 0; + Ok(()) + } +} + +#[account] +pub struct ManagedValidator { + pub managed_validator_index: u32, + pub validator_address: Pubkey, + pub multisig: Pubkey, + pub bump: u8, + pub name: String, +} + +impl ManagedValidator { + // minimum size, as name will be dynamic + pub const MINIMUM_SIZE: usize = 8 + // anchor disrciminator + 4 + // the managed validator index + 32 + // the validator address + 32 + // the multisig address + 1; // the bump of the PDA deriv + + pub fn init(&mut self, validator_address: Pubkey, multisig: Pubkey, bump: u8, name: String, managed_validator_index: u32) -> Result<()>{ + self.managed_validator_index = managed_validator_index; + self.validator_address = validator_address; + self.multisig = multisig; + self.bump = bump; + self.name = name; + Ok(()) + } +}