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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ cancel_expired_settlement(id) – Reclaim a timed-out pending settlement's liqui
set_settlement_expiry_ledgers(ledgers) admin Set the ledger window after which a pending settlement may be reclaimed (0 disables)
settlement_expiry_ledgers() – Read the settlement expiry window in ledgers
settlement_exists(id) – Check whether a settlement exists
settlement_status(id) – Read only the status of a settlement, or SettlementNotFound if missing
is_settlement_pending(id) – Check whether a settlement exists and its status is Pending
is_settlement_expired(id) – Check whether a pending settlement has passed the expiry window, without reclaiming it
settlement(id) – Read a settlement record
Expand Down
16 changes: 16 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1074,6 +1074,22 @@ impl AnchornetContract {
storage::get_settlement(&env, id).is_some()
}

/// Returns the [`SettlementStatus`] of the settlement with `id`, or
/// [`Error::SettlementNotFound`] if the settlement does not exist.
///
/// Unlike [`settlement`](Self::settlement), which returns the full
/// [`Settlement`] struct, this entrypoint projects out only the
/// `status` field. For keeper polling loops (e.g. deciding whether to
/// call [`execute_settlement`](Self::execute_settlement) or
/// [`cancel_expired_settlement`](Self::cancel_expired_settlement)),
/// the narrower return type reduces cross-contract call payload size
/// and keeps settlement-state checks auditable in one place.
pub fn settlement_status(env: Env, id: u64) -> Result<SettlementStatus, Error> {
Ok(storage::get_settlement(&env, id)
.ok_or(Error::SettlementNotFound)?
.status)
}

/// Returns `true` if a settlement with `id` exists and its status is
/// [`SettlementStatus::Pending`]. Returns `false` (not an error) for a
/// missing id or any terminal-state settlement. Designed as a minimal-payload
Expand Down
20 changes: 10 additions & 10 deletions src/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -471,17 +471,17 @@ pub fn set_max_settlement_amount(env: &Env, asset: &Symbol, amount: i128) {
extend(env, &key);
}

/// Removes the minimum liquidity floor for `asset`, reverting to unset state.
pub fn clear_min_liquidity(env: &Env, asset: &Symbol) {
let key = DataKey::MinLiquidity(asset.clone());
env.storage().persistent().remove(&key);
}
/// Removes the minimum liquidity floor for `asset`, reverting to unset state.
pub fn clear_min_liquidity(env: &Env, asset: &Symbol) {
let key = DataKey::MinLiquidity(asset.clone());
env.storage().persistent().remove(&key);
}

/// Removes the maximum settlement amount for `asset`, reverting to unset state.
pub fn clear_max_settlement_amount(env: &Env, asset: &Symbol) {
let key = DataKey::MaxSettlementAmount(asset.clone());
env.storage().persistent().remove(&key);
}
/// Removes the maximum settlement amount for `asset`, reverting to unset state.
pub fn clear_max_settlement_amount(env: &Env, asset: &Symbol) {
let key = DataKey::MaxSettlementAmount(asset.clone());
env.storage().persistent().remove(&key);
}

/// Reads the per-asset fee override for `asset`, if one has been configured.
///
Expand Down
84 changes: 76 additions & 8 deletions src/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1649,6 +1649,58 @@ fn test_settlement_exists() {
assert!(client.settlement_exists(&id));
}

#[test]
fn test_settlement_status_pending() {
let env = Env::default();
let (client, _admin, anchor, asset) = funded(&env, 1_000);
let id = client.open_settlement(&anchor, &asset, &100);

assert_eq!(client.settlement_status(&id), SettlementStatus::Pending);
}

#[test]
fn test_settlement_status_executed() {
let env = Env::default();
let (client, _admin, anchor, asset) = funded(&env, 1_000);
client.set_fee(&100); // 1%
let id = client.open_settlement(&anchor, &asset, &100);
client.execute_settlement(&id);

assert_eq!(client.settlement_status(&id), SettlementStatus::Executed);
}

#[test]
fn test_settlement_status_cancelled() {
let env = Env::default();
let (client, _admin, anchor, asset) = funded(&env, 1_000);
let id = client.open_settlement(&anchor, &asset, &100);
client.cancel_settlement(&id);

assert_eq!(client.settlement_status(&id), SettlementStatus::Cancelled);
}

#[test]
fn test_settlement_status_expired() {
let env = Env::default();
let (client, _admin, anchor, asset) = funded(&env, 1_000);
client.set_settlement_expiry_ledgers(&10);
let id = client.open_settlement(&anchor, &asset, &100); // opened_at == 0

env.ledger().set_sequence_number(10);
client.cancel_expired_settlement(&id);

assert_eq!(client.settlement_status(&id), SettlementStatus::Expired);
}

#[test]
fn test_settlement_status_not_found() {
let env = Env::default();
let (client, _admin, _anchor, _asset) = funded(&env, 1_000);

let err = client.try_settlement_status(&99).err().unwrap().unwrap();
assert_eq!(err, Error::SettlementNotFound);
}

#[test]
fn test_is_settlement_pending() {
let env = Env::default();
Expand Down Expand Up @@ -6394,11 +6446,17 @@ fn test_pool_exists_true_after_provide_liquidity() {
client.initialize(&admin);
client.register_anchor(&anchor);

assert!(!client.pool_exists(&asset), "must be false before any liquidity");
assert!(
!client.pool_exists(&asset),
"must be false before any liquidity"
);

client.provide_liquidity(&anchor, &asset, &1_000);

assert!(client.pool_exists(&asset), "must be true after provide_liquidity");
assert!(
client.pool_exists(&asset),
"must be true after provide_liquidity"
);
}

/// `pool_exists` returns `true` once `provide_liquidity_multi` has touched the
Expand All @@ -6418,7 +6476,10 @@ fn test_pool_exists_true_after_provide_liquidity_multi() {
assert!(!client.pool_exists(&usdc));
assert!(!client.pool_exists(&eurc));

client.provide_liquidity_multi(&anchor, &vec![&env, (usdc.clone(), 100), (eurc.clone(), 200)]);
client.provide_liquidity_multi(
&anchor,
&vec![&env, (usdc.clone(), 100), (eurc.clone(), 200)],
);

assert!(client.pool_exists(&usdc));
assert!(client.pool_exists(&eurc));
Expand All @@ -6431,7 +6492,10 @@ fn test_pool_exists_true_after_full_withdrawal() {
let env = Env::default();
let (client, _admin, anchor, asset) = funded(&env, 1_000);

assert!(client.pool_exists(&asset), "precondition: pool exists after funding");
assert!(
client.pool_exists(&asset),
"precondition: pool exists after funding"
);

client.withdraw_all_liquidity(&anchor, &asset);

Expand Down Expand Up @@ -6924,8 +6988,10 @@ fn test_has_asset_fee_override_true_after_set_zero_bps() {

// Explicit 0 bps override — distinct from no override.
client.set_asset_fee(&asset, &0);
assert!(client.has_asset_fee_override(&asset),
"an explicit 0 bps override must be distinguishable from no override");
assert!(
client.has_asset_fee_override(&asset),
"an explicit 0 bps override must be distinguishable from no override"
);
assert_eq!(client.asset_fee(&asset), 0);
}

Expand Down Expand Up @@ -6955,7 +7021,9 @@ fn test_has_asset_fee_override_false_after_clear() {
assert!(client.has_asset_fee_override(&asset));

client.clear_asset_fee(&asset);
assert!(!client.has_asset_fee_override(&asset),
"clear_asset_fee must revert override visibility to false");
assert!(
!client.has_asset_fee_override(&asset),
"clear_asset_fee must revert override visibility to false"
);
assert_eq!(client.asset_fee(&asset), 0); // falls back to global fee (0)
}
Loading