pub mod ixs;
pub mod run;
pub mod show;
pub mod types;
pub use types::{Member, Multisig, Permissions};
use borsh::BorshDeserialize;
use solana_client::rpc_client::RpcClient;
use solana_sdk::pubkey::Pubkey;
pub struct ResolvedMultisig {
pub multisig: Pubkey,
pub vault: Pubkey,
pub account: Multisig,
}
pub fn resolve(rpc: &RpcClient, create_key: &Pubkey) -> eyre::Result<ResolvedMultisig> {
let program_id = types::SQUADS_PROGRAM_ID.parse::<Pubkey>()?;
let (multisig, _) = types::get_multisig_pda(create_key, &program_id);
let (vault, _) = types::get_vault_pda(&multisig, 0, &program_id);
let account = rpc.get_account(&multisig).map_err(|_| {
eyre::eyre!("No multisig found for create-key {create_key} (derived PDA {multisig})")
})?;
if account.owner != program_id {
return Err(eyre::eyre!(
"Account {multisig} is not a Squads multisig (owner {})",
account.owner
));
}
if account.data.len() < 8 {
return Err(eyre::eyre!("Invalid multisig account data (too short)"));
}
let mut data = &account.data[8..];
let parsed = Multisig::deserialize_reader(&mut data)
.map_err(|e| eyre::eyre!("Failed to deserialize multisig account: {e}"))?;
if parsed.create_key != *create_key {
return Err(eyre::eyre!(
"Account {multisig} create_key mismatch (expected {create_key}, found {})",
parsed.create_key
));
}
Ok(ResolvedMultisig {
multisig,
vault,
account: parsed,
})
}
pub enum MultisigRef {
ConfigAccount,
CreateKey,
}
pub fn classify(rpc: &RpcClient, pubkey: &Pubkey) -> eyre::Result<Option<MultisigRef>> {
let program_id = types::SQUADS_PROGRAM_ID.parse::<Pubkey>()?;
if let Ok(account) = rpc.get_account(pubkey) {
if account.owner == program_id {
return Ok(Some(MultisigRef::ConfigAccount));
}
}
if resolve(rpc, pubkey).is_ok() {
return Ok(Some(MultisigRef::CreateKey));
}
Ok(None)
}