Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions contracts/globe-wallet/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,8 @@ pub enum WalletError {
InvalidAssetInfo = 1029,
/// Proposed wasm hash is not registered on-chain (never uploaded via upload_contract_wasm)
UpgradeWasmNotUploaded = 1030,
/// Guardian limit exceeded.
GuardianLimitExceeded = 1031,
}

// ── Contract ──────────────────────────────────────────────────────────────────
Expand Down Expand Up @@ -417,6 +419,11 @@ impl GlobeWallet {
// so a guardian having second thoughts can't be steam-rolled by a
// stale countdown started earlier.

/// Maximum guardians a wallet can have.
/// Chosen to stay well within instance storage limits and bound O(n) scan costs.
/// Social recovery sets rarely exceed 5-9 members in practice.
pub const MAX_GUARDIANS: u32 = 9;

/// Register a new guardian. Admin-authorized.
pub fn add_guardian(env: Env, admin: Address, guardian: Address) -> Result<(), WalletError> {
admin.require_auth();
Expand All @@ -426,6 +433,9 @@ impl GlobeWallet {
return Err(WalletError::GuardianAlreadyAdded);
}
let mut guardians = Self::guardians(env.clone());
if guardians.len() >= Self::MAX_GUARDIANS {
return Err(WalletError::GuardianLimitExceeded);
}
guardians.push_back(guardian.clone());
env.storage().instance().set(&DataKey::Guardians, &guardians);
membership.set(guardian.clone(), true);
Expand Down Expand Up @@ -2292,4 +2302,21 @@ mod tests {

assert_eq!(client.get_spend_limit(&user, &code), 1_000_000);
}

#[test]
fn test_guardian_list_has_upper_bound() {
let (env, _cid, admin, client) = setup();
for _ in 0..GlobeWallet::MAX_GUARDIANS {
let g = Address::generate(&env);
client.add_guardian(&admin, &g);
}
assert_eq!(client.guardians().len(), GlobeWallet::MAX_GUARDIANS);

let g_extra = Address::generate(&env);
assert_eq!(
client.try_add_guardian(&admin, &g_extra),
Err(Ok(WalletError::GuardianLimitExceeded))
);
assert_eq!(client.guardians().len(), GlobeWallet::MAX_GUARDIANS);
}
}