|
1 | 1 | #![no_std] |
2 | 2 | use ip_registry::IpRegistryClient; |
3 | | -use soroban_sdk::{contract, contractimpl, contracttype, token, Address, BytesN, Env, Error}; |
| 3 | +use soroban_sdk::{contract, contractimpl, contracttype, token, Address, BytesN, Env, Error, Vec}; |
4 | 4 |
|
5 | 5 | // ── Error Codes ──────────────────────────────────────────────────────────── |
6 | 6 |
|
@@ -32,6 +32,8 @@ pub enum DataKey { |
32 | 32 | /// Maps ip_id → swap_id for any swap currently in Pending or Accepted state. |
33 | 33 | /// Cleared when a swap reaches Completed or Cancelled. |
34 | 34 | ActiveSwap(u64), |
| 35 | + /// Maps seller address → Vec<u64> of all swap IDs they have initiated. |
| 36 | + SellerSwaps(Address), |
35 | 37 | } |
36 | 38 |
|
37 | 39 | // ── Types ───────────────────────────────────────────────────────────────────── |
@@ -174,6 +176,21 @@ impl AtomicSwap { |
174 | 176 | env.storage() |
175 | 177 | .persistent() |
176 | 178 | .set(&DataKey::ActiveSwap(ip_id), &id); |
| 179 | + |
| 180 | + // Append to seller index |
| 181 | + let mut seller_ids: Vec<u64> = env |
| 182 | + .storage() |
| 183 | + .persistent() |
| 184 | + .get(&DataKey::SellerSwaps(swap.seller.clone())) |
| 185 | + .unwrap_or(Vec::new(&env)); |
| 186 | + seller_ids.push_back(id); |
| 187 | + env.storage() |
| 188 | + .persistent() |
| 189 | + .set(&DataKey::SellerSwaps(swap.seller.clone()), &seller_ids); |
| 190 | + env.storage() |
| 191 | + .persistent() |
| 192 | + .extend_ttl(&DataKey::SellerSwaps(swap.seller.clone()), 50000, 50000); |
| 193 | + |
177 | 194 | env.storage().instance().set(&DataKey::NextId, &(id + 1)); |
178 | 195 | id |
179 | 196 | } |
@@ -449,6 +466,13 @@ impl AtomicSwap { |
449 | 466 | ); |
450 | 467 | } |
451 | 468 |
|
| 469 | + /// List all swap IDs initiated by a seller. Returns `None` if the seller has no swaps. |
| 470 | + pub fn get_swaps_by_seller(env: Env, seller: Address) -> Option<Vec<u64>> { |
| 471 | + env.storage() |
| 472 | + .persistent() |
| 473 | + .get(&DataKey::SellerSwaps(seller)) |
| 474 | + } |
| 475 | + |
452 | 476 | /// Read a swap record. Returns `None` if the swap_id does not exist. |
453 | 477 | /// |
454 | 478 | /// Returns the complete swap record including IP details, parties, price, |
@@ -818,6 +842,69 @@ mod tests { |
818 | 842 | assert_eq!(token_client.balance(&swap_contract), 0); |
819 | 843 | assert_eq!(token_client.balance(&seller), seller_balance_before + 500); |
820 | 844 | } |
| 845 | + |
| 846 | + #[test] |
| 847 | + fn get_swaps_by_seller_returns_none_for_unknown_seller() { |
| 848 | + let env = Env::default(); |
| 849 | + let client = AtomicSwapClient::new(&env, &setup_swap(&env)); |
| 850 | + let stranger = Address::generate(&env); |
| 851 | + assert!(client.get_swaps_by_seller(&stranger).is_none()); |
| 852 | + } |
| 853 | + |
| 854 | + #[test] |
| 855 | + fn get_swaps_by_seller_tracks_all_initiated_swaps() { |
| 856 | + let env = Env::default(); |
| 857 | + env.mock_all_auths(); |
| 858 | + |
| 859 | + let seller = Address::generate(&env); |
| 860 | + let buyer = Address::generate(&env); |
| 861 | + let admin = Address::generate(&env); |
| 862 | + |
| 863 | + // Two distinct IPs for the same seller |
| 864 | + let registry_id = env.register(IpRegistry, ()); |
| 865 | + let registry = IpRegistryClient::new(&env, ®istry_id); |
| 866 | + let ip_id_0 = registry.commit_ip(&seller, &BytesN::from_array(&env, &[10u8; 32])); |
| 867 | + let ip_id_1 = registry.commit_ip(&seller, &BytesN::from_array(&env, &[11u8; 32])); |
| 868 | + let token_id = setup_token(&env, &admin, &buyer, 1000); |
| 869 | + |
| 870 | + let client = AtomicSwapClient::new(&env, &setup_swap(&env)); |
| 871 | + let swap_id_0 = client.initiate_swap(®istry_id, &token_id, &ip_id_0, &seller, &100_i128, &buyer); |
| 872 | + let swap_id_1 = client.initiate_swap(®istry_id, &token_id, &ip_id_1, &seller, &200_i128, &buyer); |
| 873 | + |
| 874 | + let ids = client.get_swaps_by_seller(&seller).expect("seller should have swaps"); |
| 875 | + assert_eq!(ids.len(), 2); |
| 876 | + assert_eq!(ids.get(0).unwrap(), swap_id_0); |
| 877 | + assert_eq!(ids.get(1).unwrap(), swap_id_1); |
| 878 | + } |
| 879 | + |
| 880 | + #[test] |
| 881 | + fn get_swaps_by_seller_does_not_include_other_sellers_swaps() { |
| 882 | + let env = Env::default(); |
| 883 | + env.mock_all_auths(); |
| 884 | + |
| 885 | + let seller_a = Address::generate(&env); |
| 886 | + let seller_b = Address::generate(&env); |
| 887 | + let buyer = Address::generate(&env); |
| 888 | + let admin = Address::generate(&env); |
| 889 | + |
| 890 | + let registry_id = env.register(IpRegistry, ()); |
| 891 | + let registry = IpRegistryClient::new(&env, ®istry_id); |
| 892 | + let ip_a = registry.commit_ip(&seller_a, &BytesN::from_array(&env, &[20u8; 32])); |
| 893 | + let ip_b = registry.commit_ip(&seller_b, &BytesN::from_array(&env, &[21u8; 32])); |
| 894 | + let token_id = setup_token(&env, &admin, &buyer, 1000); |
| 895 | + |
| 896 | + let client = AtomicSwapClient::new(&env, &setup_swap(&env)); |
| 897 | + let swap_a = client.initiate_swap(®istry_id, &token_id, &ip_a, &seller_a, &100_i128, &buyer); |
| 898 | + let swap_b = client.initiate_swap(®istry_id, &token_id, &ip_b, &seller_b, &100_i128, &buyer); |
| 899 | + |
| 900 | + let a_ids = client.get_swaps_by_seller(&seller_a).unwrap(); |
| 901 | + let b_ids = client.get_swaps_by_seller(&seller_b).unwrap(); |
| 902 | + |
| 903 | + assert_eq!(a_ids.len(), 1); |
| 904 | + assert_eq!(a_ids.get(0).unwrap(), swap_a); |
| 905 | + assert_eq!(b_ids.len(), 1); |
| 906 | + assert_eq!(b_ids.get(0).unwrap(), swap_b); |
| 907 | + } |
821 | 908 | } |
822 | 909 |
|
823 | 910 | #[cfg(test)] |
|
0 commit comments