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
5 changes: 5 additions & 0 deletions contracts/settlement/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ use soroban_sdk::contracterror;
/// | 24 | InvalidClaimWindow | Claim window parameters are invalid |
/// | 25 | ClaimWindowClosed | Developer claim window is not currently open |
/// | 26 | MinBalanceViolation | Withdrawal would leave balance below the minimum |
/// | 27 | ReplayDetected | Settlement claim was replayed or out of order |
/// | 28 | BatchEmpty | Batch operation received an empty vector |
/// | 29 | BatchTooLarge | Batch operation exceeded the maximum allowed size |
#[contracterror]
#[derive(Clone, Copy, Debug, PartialEq)]
#[repr(u32)]
Expand Down Expand Up @@ -65,4 +68,6 @@ pub enum SettlementError {
ClaimWindowClosed = 25,
MinBalanceViolation = 26,
ReplayDetected = 27,
BatchEmpty = 28,
BatchTooLarge = 29,
}
14 changes: 11 additions & 3 deletions contracts/settlement/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,8 @@ impl CalloraSettlement {
///
/// # Validation
/// All amounts must be `> 0`. Empty and oversized batches are rejected before any state change.
/// The contract returns typed errors for empty batches (`BatchEmpty`), oversized batches
/// (`BatchTooLarge`), and non-positive amounts (`AmountNotPositive`).
///
/// # Atomicity
/// All validation runs before any state is written. A failure on any item leaves the
Expand All @@ -214,13 +216,19 @@ impl CalloraSettlement {
Self::require_authorized_caller(env.clone(), caller.clone());

let n = items.len();
assert!(n > 0, "batch_receive_payment requires at least one item");
assert!(n <= MAX_BATCH_SIZE, "batch too large");
if n == 0 {
env.panic_with_error(SettlementError::BatchEmpty);
}
if n > MAX_BATCH_SIZE {
env.panic_with_error(SettlementError::BatchTooLarge);
}

// Validate all amounts before touching state.
for item in items.iter() {
let (_, amount) = item;
assert!(amount > 0, "amount must be positive");
if amount <= 0 {
env.panic_with_error(SettlementError::AmountNotPositive);
}
}

// Replay guard: validate ALL developer HWMs before any state change.
Expand Down
8 changes: 4 additions & 4 deletions contracts/settlement/src/settlement_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2100,7 +2100,7 @@ mod settlement_tests {

let items: soroban_sdk::Vec<(Address, i128)> = soroban_sdk::Vec::new(&env);
let result = client.try_batch_receive_payment(&vault, &items, &token, &1u32);
assert!(result.is_err());
assert!(is_error(result, SettlementError::BatchEmpty));
}

#[test]
Expand All @@ -2115,7 +2115,7 @@ mod settlement_tests {
items.push_back((dev.clone(), 1i128));
}
let result = client.try_batch_receive_payment(&vault, &items, &token, &1u32);
assert!(result.is_err());
assert!(is_error(result, SettlementError::BatchTooLarge));
}

#[test]
Expand All @@ -2127,7 +2127,7 @@ mod settlement_tests {
let mut items = soroban_sdk::Vec::new(&env);
items.push_back((dev.clone(), 0i128));
let result = client.try_batch_receive_payment(&vault, &items, &token, &1u32);
assert!(result.is_err());
assert!(is_error(result, SettlementError::AmountNotPositive));
}

#[test]
Expand All @@ -2139,7 +2139,7 @@ mod settlement_tests {
let mut items = soroban_sdk::Vec::new(&env);
items.push_back((dev.clone(), -1i128));
let result = client.try_batch_receive_payment(&vault, &items, &token, &1u32);
assert!(result.is_err());
assert!(is_error(result, SettlementError::AmountNotPositive));
}

#[test]
Expand Down
10 changes: 9 additions & 1 deletion contracts/settlement/src/test_error_codes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ fn settlement_error_codes_are_stable_and_unique() {
(23, SettlementError::OverDraft),
(24, SettlementError::InvalidClaimWindow),
(25, SettlementError::ClaimWindowClosed),
(26, SettlementError::MinBalanceViolation),
(27, SettlementError::ReplayDetected),
(28, SettlementError::BatchEmpty),
(29, SettlementError::BatchTooLarge),
];

let mut seen = BTreeSet::new();
Expand All @@ -42,7 +46,7 @@ fn settlement_error_codes_are_stable_and_unique() {
);
}

assert_eq!(seen.len(), 25);
assert_eq!(seen.len(), 29);
}

#[test]
Expand Down Expand Up @@ -74,6 +78,10 @@ fn error_code_docs_list_every_settlement_code() {
"| 23 | `OverDraft` | Settlement | Withdrawal amount exceeds the developer's balance |",
"| 24 | `InvalidClaimWindow` | Settlement | Claim window end timestamp is before the start timestamp |",
"| 25 | `ClaimWindowClosed` | Settlement | Developer attempted to claim outside their configured claim window |",
"| 26 | `MinBalanceViolation` | Settlement | Withdrawal would leave balance below the minimum |",
"| 27 | `ReplayDetected` | Settlement | Settlement claim was replayed or out of order |",
"| 28 | `BatchEmpty` | Settlement | Batch operation received an empty vector |",
"| 29 | `BatchTooLarge` | Settlement | Batch operation exceeded the maximum allowed size |",
];

for line in expected_lines {
Expand Down
4 changes: 4 additions & 0 deletions docs/ERROR_CODES.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ must not be reassigned once released.
| 23 | `OverDraft` | Settlement | Withdrawal amount exceeds the developer's balance |
| 24 | `InvalidClaimWindow` | Settlement | Claim window end timestamp is before the start timestamp |
| 25 | `ClaimWindowClosed` | Settlement | Developer attempted to claim outside their configured claim window |
| 26 | `MinBalanceViolation` | Settlement | Withdrawal would leave balance below the minimum |
| 27 | `ReplayDetected` | Settlement | Settlement claim was replayed or out of order |
| 28 | `BatchEmpty` | Settlement | Batch operation received an empty vector |
| 29 | `BatchTooLarge` | Settlement | Batch operation exceeded the maximum allowed size |

## Revenue Pool

Expand Down
Loading