Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
18377b5
feat: paginated view function
T-kesh Apr 26, 2026
f1d1353
CI fix
T-kesh Apr 26, 2026
912b11f
Merge branch 'Pulsefy:main' into main
T-kesh Apr 26, 2026
c5e7d71
Merge branch 'Pulsefy:main' into main
T-kesh Apr 26, 2026
df5e1dc
Fix Cargo.toml edition from 2024 to 2021
T-kesh Apr 27, 2026
240e706
Merge branch 'main' of https://github.com/T-kesh/Soter
T-kesh Apr 27, 2026
45da6be
Fix Rust 2024 let chains to use Rust 2021 compatible syntax and fix i…
T-kesh Apr 27, 2026
aca1c96
Merge branch 'Pulsefy:main' into main
T-kesh Apr 27, 2026
68f8886
CI issue fix
T-kesh Apr 27, 2026
f4b4759
Merge branch 'main' of https://github.com/T-kesh/Soter
T-kesh Apr 27, 2026
a75e507
CI issue update
T-kesh Apr 27, 2026
c355420
lib.rs update
T-kesh Apr 27, 2026
ef5fba1
lib.rs update
T-kesh Apr 27, 2026
77f99bd
lib.rs update
T-kesh Apr 27, 2026
f883c31
lib.rs update
T-kesh Apr 27, 2026
d20b3ad
lib.rs update
T-kesh Apr 28, 2026
158b3af
lib.rs update
T-kesh Apr 28, 2026
ece4472
lib.rs update
T-kesh Apr 28, 2026
7fc7375
Merge branch 'main' into main
T-kesh Apr 28, 2026
911a0d8
lib.rs update
T-kesh Apr 28, 2026
da57ce9
Merge branch 'main' of https://github.com/T-kesh/Soter
T-kesh Apr 28, 2026
2a2ac58
lib.rs update
T-kesh Apr 28, 2026
f966260
Lib.rs update
T-kesh Apr 29, 2026
8812b91
Merge pulsefy/main into main
T-kesh Apr 29, 2026
d9ad0e3
Fix import ordering in aid_escrow test files for cargo fmt compliance
T-kesh Apr 29, 2026
baf9c62
Fix create_package calls to include missing metadata parameter
T-kesh Apr 29, 2026
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
2 changes: 1 addition & 1 deletion app/onchain/contracts/aid_escrow/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "aid_escrow"
version = "0.1.0"
edition = "2024"
edition = "2021"
description = "Soroban contract for aid package escrow functionality"
license = "MIT OR Apache-2.0"
authors = ["Soter Team"]
Expand Down
232 changes: 211 additions & 21 deletions app/onchain/contracts/aid_escrow/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
#![no_std]

use soroban_sdk::{
Address, Env, Map, String, Symbol, Vec, contract, contracterror, contractevent, contractimpl,
contracttype, symbol_short, token,
contract, contracterror, contractevent, contractimpl, contracttype, symbol_short, token,
Address, Env, Map, String, Symbol, Vec,
};

// --- Storage Keys ---
Expand Down Expand Up @@ -1130,20 +1130,20 @@ impl AidEscrow {
let idx_key = (symbol_short!("pidx"), i);
if let Some(pkg_id) = env.storage().persistent().get::<_, u64>(&idx_key) {
let pkg_key = (symbol_short!("pkg"), pkg_id);
if let Some(package) = env.storage().persistent().get::<_, Package>(&pkg_key)
&& package.token == token
{
match package.status {
PackageStatus::Created => {
total_committed += package.amount;
}
PackageStatus::Claimed => {
total_claimed += package.amount;
}
PackageStatus::Expired
| PackageStatus::Cancelled
| PackageStatus::Refunded => {
total_expired_cancelled += package.amount;
if let Some(package) = env.storage().persistent().get::<_, Package>(&pkg_key) {
if package.token == token {
match package.status {
PackageStatus::Created => {
total_committed += package.amount;
}
PackageStatus::Claimed => {
total_claimed += package.amount;
}
PackageStatus::Expired
| PackageStatus::Cancelled
| PackageStatus::Refunded => {
total_expired_cancelled += package.amount;
}
}
}
}
Expand All @@ -1167,25 +1167,64 @@ impl AidEscrow {

for id in 0..count {
let key = (symbol_short!("pkg"), id);
if let Some(package) = env.storage().persistent().get::<_, Package>(&key)
&& package.recipient == recipient
{
matches += 1;
if let Some(package) = env.storage().persistent().get::<_, Package>(&key) {
if package.recipient == recipient {
matches += 1;
}
}
}

matches
}

/// Lists package IDs for a specific recipient with pagination.
///
/// # Arguments
/// * `recipient` - The address to filter packages by
/// * `cursor` - Starting position for pagination (0-indexed)
/// * `limit` - Maximum number of results to return
///
/// # Returns
/// A Vec<u64> containing package IDs that belong to the recipient,
/// starting from the cursor position and limited by the limit parameter.
pub fn list_recipient_packages(
env: Env,
recipient: Address,
cursor: u64,
limit: u32,
) -> Vec<u64> {
let package_counter: u64 = env.storage().instance().get(&KEY_PKG_COUNTER).unwrap_or(0);
let mut result: Vec<u64> = Vec::new(&env);

// Calculate the end position: cursor + limit or package_counter, whichever comes first
let end_pos = if cursor.saturating_add(limit as u64) > package_counter {
package_counter
} else {
cursor.saturating_add(limit as u64)
};

// Iterate from cursor to end_pos
for id in cursor..end_pos {
let key = (symbol_short!("pkg"), id);
if let Some(package) = env.storage().persistent().get::<_, Package>(&key) {
if package.recipient == recipient {
result.push_back(id);
}
}
}

result
}
}

// --- Tests ---

#[cfg(test)]
mod tests {
use super::*;
use soroban_sdk::Env;
use soroban_sdk::testutils::Address as _;
use soroban_sdk::token::{StellarAssetClient, TokenClient};
use soroban_sdk::Env;

fn setup() -> (Env, AidEscrowClient<'static>) {
let env = Env::default();
Expand Down Expand Up @@ -1236,17 +1275,168 @@ mod tests {
assert_eq!(package.status, PackageStatus::Cancelled);
}

#[test]
fn test_list_recipient_packages_few_packages() {
let (env, client) = setup();
let admin = Address::generate(&env);
let recipient1 = Address::generate(&env);
let recipient2 = Address::generate(&env);

// Deploy a mock Stellar asset contract to use as the token.
let token_id = env.register_stellar_asset_contract_v2(admin.clone());
let token = token_id.address();
let sac = StellarAssetClient::new(&env, &token);

env.mock_all_auths();

// Initialise the escrow contract.
client.init(&admin);

// Mint tokens to admin and fund the escrow pool.
sac.mint(&admin, &10_000);
client.fund(&token, &admin, &10_000);

// Create packages for recipient1 (3 packages) and recipient2 (2 packages)
let operator = admin.clone();
let empty_metadata = Map::new(&env);
let package1_id = client.create_package(
&operator,
&1,
&recipient1,
&1000,
&token,
&86400,
&empty_metadata,
);
let package2_id = client.create_package(
&operator,
&2,
&recipient1,
&1500,
&token,
&86400,
&empty_metadata,
);
let package3_id = client.create_package(
&operator,
&3,
&recipient1,
&2000,
&token,
&86400,
&empty_metadata,
);
let package4_id = client.create_package(
&operator,
&4,
&recipient2,
&1200,
&token,
&86400,
&empty_metadata,
);
let package5_id = client.create_package(
&operator,
&5,
&recipient2,
&1800,
&token,
&86400,
&empty_metadata,
);

// Test listing recipient1's packages with limit 10 (more than they have)
let packages = client.list_recipient_packages(&recipient1, &0, &10);
assert_eq!(packages.len(), 3);
assert!(packages.contains(package1_id));
assert!(packages.contains(package2_id));
assert!(packages.contains(package3_id));

// Test listing recipient2's packages with limit 10 (more than they have)
let packages = client.list_recipient_packages(&recipient2, &0, &10);
assert_eq!(packages.len(), 2);
assert!(packages.contains(package4_id));
assert!(packages.contains(package5_id));
}

#[test]
fn test_list_recipient_packages_pagination() {
let (env, client) = setup();
let admin = Address::generate(&env);
let recipient = Address::generate(&env);

// Deploy a mock Stellar asset contract to use as the token.
let token_id = env.register_stellar_asset_contract_v2(admin.clone());
let token = token_id.address();
let sac = StellarAssetClient::new(&env, &token);

env.mock_all_auths();

// Initialise the escrow contract.
client.init(&admin);

// Mint tokens to admin and fund the escrow pool.
sac.mint(&admin, &20_000);
client.fund(&token, &admin, &15_000);

// Create 7 packages for the recipient
let operator = admin.clone();
let mut package_ids: soroban_sdk::Vec<u64> = soroban_sdk::Vec::new(&env);
let empty_metadata = Map::new(&env);
for i in 0..7 {
package_ids.push_back(client.create_package(
&operator,
&i,
&recipient,
&(1000 + i as i128 * 100),
&token,
&86400,
&empty_metadata,
));
}

// Test pagination with limit 3
let page1 = client.list_recipient_packages(&recipient, &0, &3);
assert_eq!(page1.len(), 3);
assert!(page1.contains(package_ids.get(0).unwrap()));
assert!(page1.contains(package_ids.get(1).unwrap()));
assert!(page1.contains(package_ids.get(2).unwrap()));

let page2 = client.list_recipient_packages(&recipient, &3, &3);
assert_eq!(page2.len(), 3);
assert!(page2.contains(package_ids.get(3).unwrap()));
assert!(page2.contains(package_ids.get(4).unwrap()));
assert!(page2.contains(package_ids.get(5).unwrap()));

let page3 = client.list_recipient_packages(&recipient, &6, &3);
assert_eq!(page3.len(), 1);
assert!(page3.contains(package_ids.get(6).unwrap()));

// Test cursor beyond available packages
let empty_page = client.list_recipient_packages(&recipient, &10, &3);
assert_eq!(empty_page.len(), 0);

// Test limit that exceeds remaining packages
let last_page = client.list_recipient_packages(&recipient, &5, &10);
assert_eq!(last_page.len(), 2);
assert!(last_page.contains(package_ids.get(5).unwrap()));
assert!(last_page.contains(package_ids.get(6).unwrap()));
}

#[test]
fn test_action_specific_pause() {
let (env, client) = setup();
let admin = Address::generate(&env);
let recipient = Address::generate(&env);

// Deploy a mock Stellar asset contract to use as the token.
let token_id = env.register_stellar_asset_contract_v2(admin.clone());
let token = token_id.address();
let sac = StellarAssetClient::new(&env, &token);

env.mock_all_auths();

// Initialise the escrow contract.
client.init(&admin);
sac.mint(&admin, &10_000);
client.fund(&token, &admin, &5_000);
Expand Down
2 changes: 1 addition & 1 deletion app/onchain/contracts/aid_escrow/tests/aggregates.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

use aid_escrow::{Aggregates, AidEscrow, AidEscrowClient};
use soroban_sdk::{
Address, Env, Map,
testutils::{Address as _, Ledger},
token::{StellarAssetClient, TokenClient},
Address, Env, Map,
};

fn setup_token(env: &Env, admin: &Address) -> (TokenClient<'static>, StellarAssetClient<'static>) {
Expand Down
3 changes: 2 additions & 1 deletion app/onchain/contracts/aid_escrow/tests/aid_escrow_tests.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
#![cfg(all(test, not(target_arch = "wasm32")))]

use soroban_sdk::{
Address, Env, Map, Vec, symbol_short,
symbol_short,
testutils::{Address as _, Ledger, LedgerInfo},
token::{Client as TokenClient, StellarAssetClient},
Address, Env, Map, Vec,
};

use aid_escrow::{AidEscrow, AidEscrowClient, Config, Error, PackageStatus};
Expand Down
2 changes: 1 addition & 1 deletion app/onchain/contracts/aid_escrow/tests/batch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

use aid_escrow::{AidEscrow, AidEscrowClient, Error};
use soroban_sdk::{
Address, Env, Map, Vec,
testutils::Address as _,
token::{StellarAssetClient, TokenClient},
Address, Env, Map, Vec,
};

fn setup_token(env: &Env, admin: &Address) -> (TokenClient<'static>, StellarAssetClient<'static>) {
Expand Down
2 changes: 1 addition & 1 deletion app/onchain/contracts/aid_escrow/tests/core_flow_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

use aid_escrow::{AidEscrow, AidEscrowClient, Error, PackageStatus};
use soroban_sdk::{
Address, Env, Map,
testutils::{Address as _, Ledger},
token::{StellarAssetClient, TokenClient},
Address, Env, Map,
};

fn setup_token(env: &Env, admin: &Address) -> (TokenClient<'static>, StellarAssetClient<'static>) {
Expand Down
13 changes: 7 additions & 6 deletions app/onchain/contracts/aid_escrow/tests/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@

use aid_escrow::{AidEscrow, AidEscrowClient};
use soroban_sdk::{
Address, Env, Map, Symbol, TryFromVal, Val, Vec,
testutils::{Address as _, Events, Ledger},
token::{StellarAssetClient, TokenClient},
Address, Env, Map, Symbol, TryFromVal, Val, Vec,
};

fn setup_token(env: &Env, admin: &Address) -> (TokenClient<'static>, StellarAssetClient<'static>) {
Expand Down Expand Up @@ -34,11 +34,12 @@ fn last_event_data(env: &Env, contract_id: &Address, topic: &str) -> Val {
let expected = sym(env, topic);
let events = contract_events(env, contract_id);
for (_, topics, data) in events.iter().rev() {
if let Some(first) = topics.first()
&& let Ok(s) = Symbol::try_from_val(env, &first)
&& s == expected
{
return *data;
if let Some(first) = topics.first() {
if let Ok(s) = Symbol::try_from_val(env, &first) {
if s == expected {
return *data;
}
}
}
}
panic!(
Expand Down
2 changes: 1 addition & 1 deletion app/onchain/contracts/aid_escrow/tests/integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

use aid_escrow::{AidEscrow, AidEscrowClient, Config, Error, PackageStatus};
use soroban_sdk::{
Address, Env, Map, Vec,
testutils::{Address as _, Ledger},
token::{StellarAssetClient, TokenClient},
Address, Env, Map, Vec,
};

fn setup_token(env: &Env, admin: &Address) -> (TokenClient<'static>, StellarAssetClient<'static>) {
Expand Down
2 changes: 1 addition & 1 deletion app/onchain/contracts/aid_escrow/tests/versioning.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#![cfg(test)]

use aid_escrow::{AidEscrow, AidEscrowClient};
use soroban_sdk::{Address, Env, testutils::Address as _};
use soroban_sdk::{testutils::Address as _, Address, Env};

#[test]
fn test_version_set_on_init() {
Expand Down
2 changes: 1 addition & 1 deletion app/onchain/contracts/aid_escrow/tests/view_status.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

use aid_escrow::{AidEscrow, AidEscrowClient, Error, PackageStatus};
use soroban_sdk::{
Address, Env, Map,
testutils::Address as _,
token::{StellarAssetClient, TokenClient},
Address, Env, Map,
};

fn setup_token(env: &Env, admin: &Address) -> (TokenClient<'static>, StellarAssetClient<'static>) {
Expand Down
Loading
Loading