Skip to content

fix(circle): add payout cooldown and zero net payout guard - #415

Open
fridaypetra55-afk wants to merge 1 commit into
cocor-tech:masterfrom
fridaypetra55-afk:fix/115-117-payout-cooldown-and-zero-net-guard
Open

fix(circle): add payout cooldown and zero net payout guard#415
fridaypetra55-afk wants to merge 1 commit into
cocor-tech:masterfrom
fridaypetra55-afk:fix/115-117-payout-cooldown-and-zero-net-guard

Conversation

@fridaypetra55-afk

Copy link
Copy Markdown
Contributor

Summary

Closes #115
Closes #117


Problem

#115trigger_payout could be called back-to-back with no minimum interval between rounds, allowing rapid repeat calls and potential race conditions.

#117 — When the fee is high enough that the net payout rounds down to zero (e.g., 100% fee_bps), the contract would transfer zero tokens and emit a misleading PayoutExecuted event, wasting gas and corrupting the audit trail.


Changes

packages/common/src/types.rs

  • Add payout_cooldown_seconds: u64 to CircleConfig (additive field; defaults to 0 = no cooldown, fully backward-compatible)

packages/circle/src/types.rs

  • Add payout_cooldown_seconds: u64 and last_payout_timestamp: u64 to the Circle struct
  • Add LastPayoutTimestamp to the DataKey enum
  • Add PayoutCooldownActive = 40 to CircleError

packages/circle/src/contract.rs

Tests (10 new tests, all 54 pass)

  • Cooldown: first payout always allowed, blocked within window, passes after window, zero-cooldown allows immediate repeat, fields present on new circle
  • Zero-net: 100% fee rejected with ZeroPayoutAmount; reasonable fee and zero fee succeed
  • Migration: storage-versioning tests confirm additive defaults and cooldown enforcement survive a round-trip

Other files

  • test_integration.rs, test_stress.rs, circle-factory/src/test.rs: add payout_cooldown_seconds to CircleConfig literals
  • Create 11 missing test stub files referenced by tests/mod.rs (pre-existing compile blocker)
  • packages/treasury/src/contract.rs: remove pre-existing compile error (env.has_contract() does not exist in the Soroban SDK)

Test Results

test result: ok. 54 passed; 0 failed; 0 ignored

…ocor-tech#115, cocor-tech#117)

## Summary

Closes cocor-tech#115 — configurable payout cooldown between rounds
Closes cocor-tech#117 — zero net payout guard before token transfer

## Changes

### packages/common/src/types.rs
- Add `payout_cooldown_seconds: u64` field to `CircleConfig` (additive,
  defaults to 0 to preserve backward compatibility with existing circles)

### packages/circle/src/types.rs
- Add `payout_cooldown_seconds: u64` and `last_payout_timestamp: u64`
  to the `Circle` struct
- Add `LastPayoutTimestamp` variant to `DataKey` enum
- Add `PayoutCooldownActive = 40` to `CircleError` enum

### packages/circle/src/contract.rs
- Restore full contract implementation from commit f0d9b39 (replaced by a
  stub in dd8750f)
- `init`: populate `payout_cooldown_seconds` from config;
  `last_payout_timestamp` initialises to 0
- `trigger_payout` (cocor-tech#115): enforce cooldown guard — if
  `payout_cooldown_seconds > 0` and a prior payout has occurred
  (`last_payout_timestamp > 0`), reject with `PayoutCooldownActive`
  until `now >= last_payout_timestamp + cooldown`
- `trigger_payout` (cocor-tech#117): the `net <= 0 → ZeroPayoutAmount` guard was
  already present in f0d9b39 and is preserved here; no zero-value transfers
  or misleading payout events are emitted
- `trigger_payout`: write `circle.last_payout_timestamp = now` after
  every successful payout to seed future cooldown checks
- `get_status` default struct updated with the two new fields (both 0)

### Test files
- `packages/circle/src/test.rs`: add `payout_cooldown_seconds: 0` to
  both `create_config` helpers; add 8 new tests covering happy paths,
  blocked-within-window, passes-after-window, zero-cooldown, field defaults,
  zero-net rejection, and reasonable/zero-fee success
- `packages/circle/src/tests/test_migration.rs`: replace broken stub with
  two storage-versioning tests for the new fields
- `packages/circle/src/tests/test_integration.rs`,
  `test_stress.rs`: add `payout_cooldown_seconds` to `CircleConfig`
  literals
- Create missing test stub files referenced by `tests/mod.rs`
- `packages/circle-factory/src/test.rs`: add `payout_cooldown_seconds`
  to `CircleConfig` literal in `sample_config`

### packages/treasury/src/contract.rs
- Remove pre-existing compile error: `env.has_contract()` does not exist
  in the Soroban SDK; removed the dead guard (non-functional check)

## Test results
  54 passed; 0 failed (circle package)
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.

fix(contract): validate payout amount is not zero before executing feat(contract): add configurable cooldown period between payout rounds

1 participant