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
33 changes: 33 additions & 0 deletions contracts/router-quote/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,21 @@ impl RouterQuote {
/// The tiers are sorted by `min_amount` ascending and are used to select
/// the highest matching tier for a quote. When no tier matches, the flat
/// route fee (if any) or the default fee is used.
///
/// # Arguments
/// * `env` - The Soroban environment.
/// * `caller` - The address initiating the call; must be the admin.
/// * `route` - The route name to configure.
/// * `tiers` - The fee tiers to set; each `FeeTier.min_amount` must be
/// non-negative and each `FeeTier.fee_bps` must be <= 10000.
///
/// # Returns
/// `Ok(())` on success.
///
/// # Errors
/// * [`QuoteError::Unauthorized`] — if caller is not the admin.
/// * [`QuoteError::InvalidFeeTier`] — if any tier has a negative `min_amount`.
/// * [`QuoteError::InvalidFeeBps`] — if any tier's `fee_bps` > 10000.
pub fn set_route_fee_tiers(
env: Env,
caller: Address,
Expand Down Expand Up @@ -1191,6 +1206,24 @@ mod tests {
assert_eq!(result, Err(Ok(QuoteError::Unauthorized)));
}

#[test]
fn test_set_route_fee_tiers_rejects_negative_min_amount() {
let (env, admin, client) = setup();
let route = String::from_str(&env, "uniswap");
let tiers = vec![&env, FeeTier { min_amount: -1, fee_bps: 50 }];
let result = client.try_set_route_fee_tiers(&admin, &route, &tiers);
assert_eq!(result, Err(Ok(QuoteError::InvalidFeeTier)));
}

#[test]
fn test_set_route_fee_tiers_rejects_fee_bps_over_max() {
let (env, admin, client) = setup();
let route = String::from_str(&env, "uniswap");
let tiers = vec![&env, FeeTier { min_amount: 0, fee_bps: 10001 }];
let result = client.try_set_route_fee_tiers(&admin, &route, &tiers);
assert_eq!(result, Err(Ok(QuoteError::InvalidFeeBps)));
}

#[test]
fn test_unauthorized_transfer_admin_fails() {
let (env, _admin, client) = setup();
Expand Down
4 changes: 3 additions & 1 deletion contracts/router-timelock/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -427,7 +427,9 @@ impl RouterTimelock {
.checked_add(op.grace_period_seconds)
.map_or(true, |expiry| now > expiry);
if is_expired || op.executed || op.cancelled {
// It is expired or finalized!
// It is expired or finalized! Remove the underlying storage entries.
env.storage().instance().remove(&DataKey::Op(op_id.clone()));
env.storage().instance().remove(&DataKey::Deps(op_id.clone()));
cleaned_count += 1;
} else {
new_pending.push_back(op_id);
Expand Down
12 changes: 4 additions & 8 deletions integration-tests/tests/quote_execution_multicall_pipeline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,8 +198,7 @@ fn test_pipeline_quote_calculation() {
amount_in,
};

let quote = s.quote.get_quote(&quote_request)
.expect("Failed to get quote");
let quote = s.quote.get_quote(&quote_request);

// Verify quote response
assert_eq!(quote.amount_in, amount_in);
Expand Down Expand Up @@ -266,8 +265,7 @@ fn test_pipeline_execution_swap() {
};

// Execute (with mocked auth, this should succeed)
let result = s.execution.execute(&s.user, &exec_request)
.expect("Execution should succeed");
let result = s.execution.execute(&s.user, &exec_request);

// Verify execution result
assert_eq!(result.target, mock_target);
Expand Down Expand Up @@ -370,8 +368,7 @@ fn test_quote_to_execution_to_multicall_pipeline() {
amount_in,
};

let quote = s.quote.get_quote(&quote_request)
.expect("Quote should succeed");
let quote = s.quote.get_quote(&quote_request);
println!(" ✓ Quote obtained: amount_out = {}", quote.amount_out);

// ── Phase 2: Middleware Check ──────────────────────────────────────
Expand All @@ -396,8 +393,7 @@ fn test_quote_to_execution_to_multicall_pipeline() {
amount: 1_000_000,
};

let exec_result = s.execution.execute(&s.user, &exec_request)
.expect("Execution should succeed");
let exec_result = s.execution.execute(&s.user, &exec_request);
assert_eq!(exec_result.success, true);
println!(" ✓ Single swap executed successfully");

Expand Down
Loading