Skip to content
Merged
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
22 changes: 22 additions & 0 deletions contracts/atomic_swap/src/arbitration_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,28 @@ mod arbitration_tests {

const RULING_DELAY: u64 = 48 * 3600;

// ── #830: Compile-time surface assertion ─────────────────────────────────
//
// Verify that the public contract surface used by these tests matches what
// ip_registry expects. The assertions below are pure compile-time checks:
// if the signatures drift the file will not compile.
//
// • `IpRegistryClient::commit_ip` must accept (owner: &Address,
// commitment_hash: &BytesN<32>, pow_difficulty: &u32) — three args.
// • `AtomicSwapClient::initiate_swap` must accept nine user-visible args
// (token, ip_id, seller, price, buyer, required_approvals, referrer,
// collateral_amount, insurance_enabled).
//
// Both are enforced implicitly throughout this module: every
// `registry.commit_ip(owner, &hash, &0u32)` call is a three-arg call site,
// and every `client.initiate_swap(…)` call passes exactly nine arguments.
// Any future removal of either parameter will break compilation here before
// it can reach main.
//
// Additionally, the removed function `accept_swap_with_quantity` has zero
// callers in this crate (confirmed by `grep accept_swap_with_quantity
// contracts/atomic_swap/src/*.rs` returning no results).

fn setup_registry(env: &Env, owner: &Address) -> (Address, u64, BytesN<32>, BytesN<32>) {
let registry_id = env.register(IpRegistry, ());
let registry = IpRegistryClient::new(env, &registry_id);
Expand Down
56 changes: 56 additions & 0 deletions contracts/atomic_swap/src/batch_history_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -418,4 +418,60 @@ mod batch_history_tests {
// Should return empty vector
assert_eq!(history.len(), 0);
}

/// #827: Explicit assertion — each swap in a batch_initiate_swap produces
/// exactly ONE history entry (the Pending transition) at initiation time.
/// The batch call itself does NOT produce a single shared entry for the
/// whole batch; every swap gets its own independent record.
#[test]
fn test_batch_initiate_produces_one_history_entry_per_swap() {
let env = Env::default();
env.mock_all_auths();

let seller = Address::generate(&env);
let buyer = Address::generate(&env);
let admin = Address::generate(&env);

let registry_id = setup_registry(&env, &seller);
let token_id = setup_token(&env, &admin, &buyer, 10_000_000);
let contract_id = setup_contract(&env, &registry_id);
let client = AtomicSwapClient::new(&env, &contract_id);

let (ip1, _, _) = commit_ip(&env, &registry_id, &seller, 0x10);
let (ip2, _, _) = commit_ip(&env, &registry_id, &seller, 0x11);
let (ip3, _, _) = commit_ip(&env, &registry_id, &seller, 0x12);

let mut ip_ids = Vec::new(&env);
ip_ids.push_back(ip1);
ip_ids.push_back(ip2);
ip_ids.push_back(ip3);

let mut prices = Vec::new(&env);
prices.push_back(100i128);
prices.push_back(200i128);
prices.push_back(300i128);

let swap_ids =
client.batch_initiate_swap(&token_id, &ip_ids, &seller, &prices, &buyer, &0u32, &None);

// Each swap must have exactly 1 history entry — the Pending transition —
// not zero (missed) and not >1 (double-counted at batch level).
for i in 0..swap_ids.len() {
let swap_id = swap_ids.get(i).unwrap();
let history = client.get_swap_history(&swap_id);
assert_eq!(
history.len(),
1,
"swap {} should have exactly 1 history entry after batch initiation, got {}",
swap_id,
history.len()
);
assert_eq!(
history.get(0).unwrap().status,
SwapStatus::Pending,
"swap {} initial history entry should be Pending",
swap_id
);
}
}
}
11 changes: 11 additions & 0 deletions contracts/atomic_swap/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2736,6 +2736,17 @@ impl AtomicSwap {
);
}

// ── #254: Query approvals ─────────────────────────────────────────────────

/// Returns all approvers who have called `approve_swap` for the given swap.
/// Returns an empty Vec if no approvals have been recorded yet.
pub fn get_swap_approvals(env: Env, swap_id: u64) -> Vec<Address> {
env.storage()
.persistent()
.get(&DataKey::SwapApprovals(swap_id))
.unwrap_or(Vec::new(&env))
}

// ── #309: Batch swap initiation ───────────────────────────────────────────

/// Seller initiates multiple patent sales in one call. Returns a Vec of swap IDs.
Expand Down