Skip to content
Open
Show file tree
Hide file tree
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
18 changes: 8 additions & 10 deletions contracts/milestone-escrow/src/admin_override_cancel_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,12 @@
//! - Error::InvalidAmount is returned (not a panic) for edge-case amounts.
//! - Terminal milestones are correctly skipped in every scenario.

#![cfg(test)]

use super::*;
use crate::test::setup_funded_escrow;
use crate::{DataKey, Error, MilestoneEscrowClient, MilestoneStatus};
use soroban_sdk::{token, vec, Address, Env};
use soroban_sdk::{testutils::Address as _, token, vec, Address, Env};

// ────────────────────────────────────────────────────────────────────────────
// Issue #383: admin_override_cancel_release storage footprint
Expand Down Expand Up @@ -118,8 +121,7 @@ fn test_cancel_release_requires_cancel_lock() {
let env = Env::default();
env.mock_all_auths();

let (_, _, _, admin_addr, _, _, client) =
setup_funded_escrow(&env, vec![&env, 1_000_i128]);
let (_, _, _, admin_addr, _, _, client) = setup_funded_escrow(&env, vec![&env, 1_000_i128]);

let result = client.try_admin_override_cancel_release(&admin_addr);
assert_eq!(result, Err(Ok(Error::InvalidStatus)));
Expand All @@ -131,8 +133,7 @@ fn test_cancel_release_unauthorized_caller_rejected() {
let env = Env::default();
env.mock_all_auths();

let (client_addr, _, _, _, _, _, client) =
setup_funded_escrow(&env, vec![&env, 1_000_i128]);
let (client_addr, _, _, _, _, _, client) = setup_funded_escrow(&env, vec![&env, 1_000_i128]);
client.cancel_escrow(&client_addr);

let attacker = Address::generate(&env);
Expand Down Expand Up @@ -225,8 +226,7 @@ fn test_cancel_refund_requires_cancel_lock() {
let env = Env::default();
env.mock_all_auths();

let (_, _, _, admin_addr, _, _, client) =
setup_funded_escrow(&env, vec![&env, 1_000_i128]);
let (_, _, _, admin_addr, _, _, client) = setup_funded_escrow(&env, vec![&env, 1_000_i128]);

let result = client.try_admin_override_cancel_refund(&admin_addr);
assert_eq!(result, Err(Ok(Error::InvalidStatus)));
Expand Down Expand Up @@ -324,8 +324,7 @@ fn test_cancel_refund_multiple_milestones_sum_correctly() {
env.mock_all_auths();

let amounts = vec![&env, 100_i128, 200_i128, 300_i128, 400_i128];
let (client_addr, _, _, admin_addr, token_id, _, client) =
setup_funded_escrow(&env, amounts);
let (client_addr, _, _, admin_addr, token_id, _, client) = setup_funded_escrow(&env, amounts);

client.cancel_escrow(&client_addr);

Expand Down Expand Up @@ -357,4 +356,3 @@ fn test_cancel_refund_minimum_valid_amount() {

assert_eq!(token.balance(&client_addr), client_before + 1);
}

30 changes: 26 additions & 4 deletions contracts/milestone-escrow/src/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ impl ReentrantToken {
}
}

fn setup_funded_escrow(
pub(crate) fn setup_funded_escrow(
env: &Env,
milestone_amounts: soroban_sdk::Vec<i128>,
) -> (
Expand Down Expand Up @@ -7487,7 +7487,8 @@ fn test_multisig_approval_init_succeeds() {
}

/// Initialisation: a second call to `multisig_approval_init` must be rejected
/// with `AlreadyInitialized`.
/// with `AlreadyInitialized` (the illegal source state for this one-time
/// setup function), and no storage entry is mutated by the rejected call.
#[test]
fn test_multisig_approval_init_duplicate_fails() {
let env = Env::default();
Expand All @@ -7496,9 +7497,18 @@ fn test_multisig_approval_init_duplicate_fails() {
let (client, admin, _signers) = setup_multisig(&env, 2);

let extra = Address::generate(&env);
let new_signers = vec![&env, extra];
let new_signers = vec![&env, extra.clone()];
let result = client.try_multisig_approval_init(&admin, &new_signers, &1u32);
assert_eq!(result, Err(Ok(Error::AlreadyInitialized)));

// No storage entry was mutated: the original threshold (2, not the
// attempted 1) is still in effect.
let state = client.try_is_multisig_approved(&0u32).unwrap().unwrap();
assert_eq!(state.threshold, 2);

// The new signer from the rejected call was never written either.
let approve_result = client.try_multisig_approve(&extra, &0u32);
assert_eq!(approve_result, Err(Ok(Error::Unauthorized)));
}

/// Initialisation: zero signers must be rejected.
Expand Down Expand Up @@ -7787,7 +7797,9 @@ fn test_multisig_approve_emits_structured_event() {
assert_eq!(matched, 1);
}

/// Admin: unauthorised caller cannot initialise multisig.
/// Admin: unauthorised caller cannot initialise multisig, and no storage
/// entry is mutated by the rejected attempt (the original signer set and
/// threshold from `setup_multisig` remain in effect).
#[test]
fn test_multisig_approval_init_unauthorized_fails() {
let env = Env::default();
Expand All @@ -7799,6 +7811,16 @@ fn test_multisig_approval_init_unauthorized_fails() {
let new_signers = vec![&env, impostor.clone()];
let result = client.try_multisig_approval_init(&impostor, &new_signers, &1u32);
assert_eq!(result, Err(Ok(Error::Unauthorized)));

// No storage entry was mutated: the original threshold (2, not the
// impostor's attempted 1) is still in effect.
let state = client.try_is_multisig_approved(&0u32).unwrap().unwrap();
assert_eq!(state.threshold, 2);

// The impostor was never written into the signer set either: they
// cannot approve as if they were a registered signer.
let approve_result = client.try_multisig_approve(&impostor, &0u32);
assert_eq!(approve_result, Err(Ok(Error::Unauthorized)));
}

// ============================================================================
Expand Down