use alloc::collections::{BTreeSet, VecDeque};
use alloc::string::{String, ToString};
use alloc::sync::Arc;
use alloc::vec::Vec;
use keetanetwork_account::GenericAccount;
pub type AccountRef = Arc<GenericAccount>;
#[derive(Debug, Clone)]
pub enum Signer {
Single(AccountRef),
Multisig {
address: AccountRef,
signers: Vec<Signer>,
},
}
impl Signer {
pub fn principal(&self) -> &AccountRef {
match self {
Signer::Single(account) => account,
Signer::Multisig { address, .. } => address,
}
}
pub fn required_signers(&self) -> Vec<AccountRef> {
let mut queue: VecDeque<&Signer> = VecDeque::new();
queue.push_back(self);
let mut visited: BTreeSet<String> = BTreeSet::new();
let mut out: Vec<AccountRef> = Vec::new();
while let Some(current) = queue.pop_front() {
match current {
Signer::Single(account) => {
if visited.insert(account.to_string()) {
out.push(account.clone());
}
}
Signer::Multisig { signers, .. } => {
for child in signers.iter().rev() {
queue.push_front(child);
}
}
}
}
out
}
}
impl From<AccountRef> for Signer {
fn from(account: AccountRef) -> Self {
Signer::Single(account)
}
}
impl From<GenericAccount> for Signer {
fn from(account: GenericAccount) -> Self {
Signer::Single(Arc::new(account))
}
}
#[cfg(test)]
mod tests {
use super::*;
use keetanetwork_account::KeyPairType;
use crate::testing::{generate_ed25519_ref, generate_identifier_ref};
#[test]
fn test_single_required_signers() {
let account = generate_ed25519_ref(1);
let signer = Signer::from(account.clone());
let required = signer.required_signers();
assert_eq!(required.len(), 1);
assert_eq!(required[0].to_string(), account.to_string());
}
#[test]
fn test_multisig_preorder_flatten() {
let nested = Signer::Multisig {
address: generate_identifier_ref(9, KeyPairType::MULTISIG, 0),
signers: vec![Signer::from(generate_ed25519_ref(3)), Signer::from(generate_ed25519_ref(4))],
};
let signer = Signer::Multisig {
address: generate_identifier_ref(8, KeyPairType::MULTISIG, 0),
signers: vec![Signer::from(generate_ed25519_ref(1)), nested, Signer::from(generate_ed25519_ref(2))],
};
let required: Vec<String> = signer
.required_signers()
.iter()
.map(|a| a.to_string())
.collect();
let expected: Vec<String> = [1u8, 3, 4, 2]
.iter()
.map(|seed_byte| generate_ed25519_ref(*seed_byte).to_string())
.collect();
assert_eq!(required, expected);
}
#[test]
fn test_duplicate_signers_deduplicated() {
let signer = Signer::Multisig {
address: generate_identifier_ref(8, KeyPairType::MULTISIG, 0),
signers: vec![
Signer::from(generate_ed25519_ref(1)),
Signer::Multisig {
address: generate_identifier_ref(9, KeyPairType::MULTISIG, 0),
signers: vec![Signer::from(generate_ed25519_ref(1)), Signer::from(generate_ed25519_ref(2))],
},
],
};
let required = signer.required_signers();
assert_eq!(required.len(), 2);
}
#[test]
fn test_principal() {
let address = generate_identifier_ref(7, KeyPairType::MULTISIG, 0);
let signer =
Signer::Multisig { address: address.clone(), signers: vec![Signer::from(generate_ed25519_ref(1))] };
assert_eq!(signer.principal().to_string(), address.to_string());
}
}