Skip to content

Feat add per jurisdiction transfer cooldown configurable via set transfer cooldown - #702

Merged
thlpkee20-wq merged 4 commits into
RevoraOrg:masterfrom
obswrld:feat-Add-per-jurisdiction-transfer-cooldown-configurable-via-set-transfer-cooldown
Jul 29, 2026
Merged

Feat add per jurisdiction transfer cooldown configurable via set transfer cooldown#702
thlpkee20-wq merged 4 commits into
RevoraOrg:masterfrom
obswrld:feat-Add-per-jurisdiction-transfer-cooldown-configurable-via-set-transfer-cooldown

Conversation

@obswrld

@obswrld obswrld commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

closes #588

Summary
Adds set_transfer_cooldown(offering_id, jurisdiction, cooldown_secs) and enforces it in the transfer path. Some jurisdictions require a mandatory waiting period between successive share transfers by the same holder. This feature allows issuers to configure per-jurisdiction cooldown windows that are enforced automatically on every transfer_with_attestation and reported via estimate_transfer .

Changes
Storage (DataKey2)

  • TransferCooldownConfig(OfferingId, Symbol) → u64 — per-jurisdiction cooldown in seconds (0 = disabled)
  • HolderLastTransferTime(OfferingId, Address) → u64 — ledger timestamp of the holder's last transfer
    Contract API
  • set_transfer_cooldown(env, issuer, namespace, token, jurisdiction, cooldown_secs) — configures the cooldown, emits tr_cool event
  • get_transfer_cooldown(env, issuer, namespace, token, jurisdiction) → u64 — reads the configured cooldown
    Enforcement
  • Cooldown check in check_transfer_eligibility (shared gate called by transfer_with_attestation ) and duplicated in estimate_transfer for consistency
  • Only the sender's jurisdiction is checked (cooldown prevents rapid sending, not receiving)
  • No cooldown applied when the sender has no jurisdiction tag
  • HolderLastTransferTime is only written when a cooldown is actually configured (no wasted writes)
  • Rejects premature transfers with RevoraError::TransferCooldownActive (discriminant 89)
    Error variant
    // rust
    TransferCooldownActive = 89,
    Files changed
    ┌─────────────────┬─────────────────────────────────────────────────────────────────────────────────────────────────────────┐
    │ File │ Change │
    ├─────────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────┤
    │ src/lib.rs │ +error variant, +event constant, +DataKey2 variants, +check_transfer_eligibility, │
    │ │ +set/get_transfer_cooldown, cooldown checks in transfer paths │
    │ src/structured_ │ Added TransferCooldownActive to all discriminant stability tests │
    │ error_tests.rs │ │
    │ tools/storage_l │ Registered new DataKey2 entries │
    │ ayout_schema.rs │ │
    │ docs/STORAGE_LA │ Regenerated │
    │ YOUT.json │ │
    │ src/test_transf │ 10 tests covering set/get, blocked by cooldown, allowed after elapsed, exact boundary, zero=disabled, │
    │ er_cooldown.rs │ independent jurisdiction cooldowns, no jurisdiction bypass, no-storage-write optimization, │
    │ │ estimate_transfer consistency │
    └─────────────────┴─────────────────────────────────────────────────────────────────────────────────────────────────────────┘
    Test coverage
  1. test_set_and_get_transfer_cooldown — set, read back, verify event emission
  2. test_transfer_blocked_by_cooldown — immediate retry rejected
  3. test_transfer_allowed_after_cooldown_elapsed — retry after window passes
  4. test_cooldown_exactly_at_boundary_rejects — 59s with 60s cooldown
  5. test_cooldown_zero_means_disabled — cooldown=0 is a no-op
  6. test_different_jurisdictions_have_independent_cooldowns — US=3600s, SG=60s
  7. test_cooldown_not_applied_when_jurisdiction_not_set — no jurisdiction = no cooldown
  8. test_cooldown_state_not_recorded_when_no_cooldown_configured — storage efficiency
  9. test_estimate_transfer_cooldown_consistency — estimate returns same error

obswrld added 3 commits July 29, 2026 18:38
- Add EVENT_REG_LIMIT_DELTA (rg_lim_d) event symbol with doc comments
- Add update_and_emit_reg_limit_delta helper that tracks
  JurisdictionAggregateShare per (offering, jurisdiction)
- Hook into set_holder_share_internal for automatic emission
  on every holding change (issuance, transfer)
- Add get_indexer_fixture_topics with 16 canonical fixture
  entries including rg_lim_d (non-period-scoped, period_id=0)
- Add EVENT_JUR_UNSET sentinel constant (was missing)
- Bump STORAGE_LAYOUT_VERSION from 4 to 5
- Add 12 tests (9 behavioral + 3 gas-budget) covering issuance,
  cross/same-jurisdiction transfers, no-jurisdiction edge cases,
  data shape, and gas bounds
- Update test_indexer_fixtures.rs to expect 16 fixtures
- Update milestone_signals.rs for new tuple return and fixture count
- Update docs/indexer-fixture-coverage.md with rg_lim_d entry
Resolved ~50 pre-existing compilation errors across 3 files:
- src/lib.rs: SafeMath import fix, RevoraError discriminant renumbering (62->77, 63->78, 67->79), 9 missing enum variants (80-88), symbol_short! length, sha256().into(), Proposal fields, set_holder_share_internal args, is_dispute_freeze_active param, MerkleLeaf contracttype, MigrationDataKey variants
- src/merkle_helpers.rs: Added #[contracttype] to MerkleLeaf struct
- tools/storage_layout_schema.rs: Added MigrationDataKey entries

~420 pre-existing structural errors remain (DataKey2 >50 variants exceeds Soroban #[contracttype] limit, plus cascading errors) — these are unrelated to the regulatory-limit feature.
@drips-wave

drips-wave Bot commented Jul 29, 2026

Copy link
Copy Markdown

@obswrld 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

@thlpkee20-wq
thlpkee20-wq merged commit f9bb85a into RevoraOrg:master Jul 29, 2026
1 of 3 checks passed
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 per-jurisdiction transfer cooldown configurable via set_transfer_cooldown

2 participants