From cccf9d3f39094b7e7304b6a2b6e90d2fa50954df Mon Sep 17 00:00:00 2001 From: Cmitchelle7 Date: Sat, 17 Oct 2026 17:15:17 -0700 Subject: [PATCH] feat(creator-keys): add get_cooldown_remaining view (#1050) --- creator-keys/src/lib.rs | 14 ++++++ creator-keys/tests/trade_cooldown.rs | 64 ++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+) diff --git a/creator-keys/src/lib.rs b/creator-keys/src/lib.rs index 4a3142cf..e2bce1d1 100644 --- a/creator-keys/src/lib.rs +++ b/creator-keys/src/lib.rs @@ -11241,6 +11241,20 @@ impl CreatorKeysContract { Ok(()) } + /// Seconds remaining before `wallet` may trade `key_id` again. + /// + /// Returns `0` when no cooldown is configured or the cooldown window has + /// already elapsed. Convenience alias over `get_cooldown_status` for + /// callers that want the raw seconds instead of the full status struct. + pub fn get_cooldown_remaining(env: Env, key_id: Address, wallet: Address) -> u64 { + let status = Self::get_cooldown_status(env.clone(), key_id, wallet); + if !status.active { + return 0; + } + let now = env.ledger().timestamp(); + status.expires_at.saturating_sub(now) + } + /// Returns the cooldown status for a specific wallet on a creator's key. /// /// - `active`: `true` when the wallet is currently within its cooldown window. diff --git a/creator-keys/tests/trade_cooldown.rs b/creator-keys/tests/trade_cooldown.rs index 02ebb81b..a2567741 100644 --- a/creator-keys/tests/trade_cooldown.rs +++ b/creator-keys/tests/trade_cooldown.rs @@ -318,3 +318,67 @@ fn test_cooldown_independent_per_creator() { let supply_b = client.buy_key(&creator_b, &buyer, &KEY_PRICE, &None); assert_eq!(supply_b, 2); } + +// -- get_cooldown_remaining ---------------------------------------------- + +/// AC: `get_cooldown_remaining` returns `duration_secs` immediately after a +/// trade, `duration/2` at the midpoint, and `0` once the window has elapsed. +#[test] +fn test_get_cooldown_remaining_tracks_window() { + let env = test_env_with_auths(); + let s = setup_with_cooldown(&env, COOLDOWN_SECS); + + // No trades yet ? 0. + assert_eq!(s.client.get_cooldown_remaining(&s.creator, &s.creator), 0); + + let buyer = Address::generate(&env); + s.client.buy_key(&s.creator, &buyer, &KEY_PRICE, &None); + + // Immediately after the buy ? full window remaining. + assert_eq!( + s.client.get_cooldown_remaining(&s.creator, &buyer), + COOLDOWN_SECS + ); + + // Halfway through the window. + set_test_timestamp(&env, DEFAULT_TEST_TIMESTAMP + COOLDOWN_SECS / 2); + assert_eq!( + s.client.get_cooldown_remaining(&s.creator, &buyer), + COOLDOWN_SECS / 2 + ); + + // Past the window ? 0. + set_test_timestamp(&env, DEFAULT_TEST_TIMESTAMP + COOLDOWN_SECS + 1); + assert_eq!(s.client.get_cooldown_remaining(&s.creator, &buyer), 0); +} + +/// AC: `get_cooldown_remaining` returns `0` when no cooldown is configured, +/// even after a trade. +#[test] +fn test_get_cooldown_remaining_zero_when_unconfigured() { + let env = test_env_with_auths(); + let s = setup_with_cooldown(&env, 0); + + let buyer = Address::generate(&env); + s.client.buy_key(&s.creator, &buyer, &KEY_PRICE, &None); + + assert_eq!(s.client.get_cooldown_remaining(&s.creator, &buyer), 0); +} + +/// AC: `get_cooldown_remaining` is per-wallet; one wallet's remaining time +/// does not affect another's. +#[test] +fn test_get_cooldown_remaining_is_per_wallet() { + let env = test_env_with_auths(); + let s = setup_with_cooldown(&env, COOLDOWN_SECS); + + let alice = Address::generate(&env); + let bob = Address::generate(&env); + s.client.buy_key(&s.creator, &alice, &KEY_PRICE, &None); + + assert_eq!( + s.client.get_cooldown_remaining(&s.creator, &alice), + COOLDOWN_SECS + ); + assert_eq!(s.client.get_cooldown_remaining(&s.creator, &bob), 0); +}