Skip to content

feat: add per-wallet buy cooldown to creator keys - #848

Closed
Moh-dakai wants to merge 5 commits into
accesslayerorg:mainfrom
Moh-dakai:feat/per-wallet-buy-cooldown
Closed

feat: add per-wallet buy cooldown to creator keys#848
Moh-dakai wants to merge 5 commits into
accesslayerorg:mainfrom
Moh-dakai:feat/per-wallet-buy-cooldown

Conversation

@Moh-dakai

@Moh-dakai Moh-dakai commented Aug 31, 2026

Copy link
Copy Markdown

This PR implements a per-wallet cooldown period for buy transactions to prevent automated bots from rapidly accumulating large positions ahead of manual traders.
​Changes
​Persistent Storage: Added a last_buy_ledger tracker recorded per (key_id, wallet) on every successful buy transaction.
​Cooldown Configuration: Introduced the set_buy_cooldown(key_id: BytesN<32>, cooldown_ledgers: u32) function, restricted to the key creator. Enforces a maximum limit of 720 ledgers (~1 hour) and defaults to 0 (no restriction).
​Buy Guard & Events: Updated the buy function to panic with CooldownActive if the cooldown period has not elapsed, emitting a cooldown_blocked event containing the wallet, key ID, and ledgers_remaining.
​Testing & Acceptance Criteria
​[ ] Second buy attempted within the cooldown period panics with CooldownActive.
​[ ] Buy transaction executed after the cooldown period elapses succeeds normally.
​[ ] Setting cooldown_ledgers above 720 correctly panics with CooldownTooLong.
​[ ] Non-creator attempts to call set_buy_cooldown panic with Unauthorized.
​[ ] cooldown_blocked event fires correctly with the accurate ledgers_remaining count.

Closes #830

Implement the per-wallet buy cooldown feature to slow bot-driven
key accumulation.

Changes:
- CooldownError enum (CooldownActive=1, CooldownTooLong=2) in lib.rs
- DataKey::LastBuyLedger(Address, Address) and DataKey::BuyCooldown(Address)
  variants + constants::storage helpers
- set_buy_cooldown(creator, cooldown_ledgers) — creator-authed, 0..=720 range;
  returns CooldownError::CooldownTooLong above cap
- get_buy_cooldown(creator) — read-only view, returns 0 when not configured
- buy_key_with_referrer: cooldown guard emits cooldown_blocked event then
  panics with CooldownError::CooldownActive when elapsed < cooldown_ledgers
- buy_key_with_referrer: writes LastBuyLedger on every successful buy so
  subsequent buys use the most recent purchase ledger
- CooldownBlockedEvent struct + cooldown_blocked_topics helper + COOLDOWN_BLOCKED_EVENT_NAME
  constant in events.rs
- Integration test suite: tests/buy_cooldown.rs covering all five acceptance criteria
- docs: authorization-model.md — set_buy_cooldown + get_buy_cooldown entries
- docs: contract-event-conventions.md — cd_blk event row

MAX_BUY_COOLDOWN_LEDGERS = 720 (~1 hour at 5 s/ledger).
Default is 0 (no restriction) when unconfigured.
@drips-wave

drips-wave Bot commented Aug 31, 2026

Copy link
Copy Markdown

@Moh-dakai Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@Chucks1093

Copy link
Copy Markdown
Member

❌ CI Failed — verify (Contracts CI)

The verify check is failing on the per-wallet buy cooldown feature.

Likely causes:

  • New function signature not matching the trait or interface expected by the contract
  • Missing bump_persistent call on the last_buy_ledger storage entry
  • Type mismatch on cooldown_ledgers (u32 vs u64)

Steps to fix:

  1. Run cargo build and fix any type or signature errors
  2. Ensure last_buy_ledger storage entry has a TTL bump
  3. Run cargo fmt --all and cargo clippy
  4. Push

Moh-dakai and others added 2 commits September 4, 2026 17:09
- Add ContractError::CooldownActive = 36 so buy_key can return it
- Replace panic_with_error(CooldownError::CooldownActive) with
  return Err(ContractError::CooldownActive) in buy_key, matching
  the function's declared return type
- Add CooldownError::NotRegistered = 3 and a registration check
  to set_buy_cooldown so non-registered callers are rejected
- Update try_buy_key assertions in buy_cooldown.rs to use
  ContractError::CooldownActive instead of CooldownError::CooldownActive
@Moh-dakai Moh-dakai closed this Sep 4, 2026
@Moh-dakai Moh-dakai reopened this Sep 4, 2026
…edger write

- Add BuyCooldown(Address) variant to DataKey enum (was missing, caused
  compile error in constants::storage::buy_cooldown calls)
- Add constants::storage::buy_cooldown() accessor fn in storage module
- Remove duplicate last_buy_ledger_key write in buy_key; the flash-loan
  guard write already covers the cooldown window reset — second identical
  binding shadowed the first and would fail Clippy's variable shadow lint
@Moh-dakai Moh-dakai closed this Sep 4, 2026
@Moh-dakai Moh-dakai reopened this Sep 4, 2026

@Moh-dakai Moh-dakai left a comment

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

@Moh-dakai Moh-dakai closed this Sep 4, 2026
@Moh-dakai
Moh-dakai deleted the feat/per-wallet-buy-cooldown branch September 4, 2026 17:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add a cooldown period between consecutive buys by the same wallet to prevent bot-driven accumulation

3 participants