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
41 changes: 6 additions & 35 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,48 +1,19 @@
# Repository Guidelines

## Project Structure & Module Organization

- Source contracts live under `src/`; `contract.cairo` is the TicketMaster entrypoint, `interfaces.cairo` exposes the Starknet ABI, and `utils.cairo` holds TWAMM and fee utilities.
- Shared constants sit in `src/constants.cairo`; unit-style specs live alongside their modules (for example, TWAMM helper tests remain in `src/utils.cairo`).
- End-to-end and fork tests belong in `tests/`, consumable by Starknet Foundry. Keep build outputs (`target/`, `.snfoundry_cache/`) untracked.
Keep contract sources under `src/`. `contract.cairo` serves as the TicketMaster entrypoint, `interfaces.cairo` exposes the Starknet ABI, and `utils.cairo` hosts TWAMM and fee helpers. Shared values live in `src/constants.cairo`. Unit-style specs stay beside their modules, while end-to-end and fork tests belong in `tests/` for Starknet Foundry (`snforge`) to discover. Build artifacts such as `target/` and `.snfoundry_cache/` remain untracked.

## Build, Test, and Development Commands

- `scarb build` — compile the Cairo package and verify dependency locks resolve.
- `snforge test` — run the full Foundry suite; use `snforge test util_tests::` when iterating on time helpers.
- `snforge test --detailed-resources` — capture gas/resource deltas before merging.
- `scarb fmt` — format all Cairo modules to the project standard.
Use `scarb build` to compile the Cairo package and confirm lockfiles resolve. Run `snforge test` for the full suite, or narrow with targets like `snforge test util_tests::` while iterating on helpers. Capture resource deltas before merging via `snforge test --detailed-resources`. Format all Cairo modules with `scarb fmt` before committing. Deployment scripts reside in `scripts/` and expect environment variables sourced from the provided `.env.*` files.

## Coding Style & Naming Conventions

- Favor four-space indentation and grouped imports; always run `scarb fmt` before committing.
- Functions and modules use `snake_case`; structs and type aliases use `UpperCamelCase`; constants follow `SCREAMING_SNAKE_CASE` per `src/constants.cairo`.
- Document public ABIs with triple-slash comments so tooling surfaces them.
Adopt four-space indentation, grouped imports, and snake_case for functions/modules. Structs and type aliases use UpperCamelCase, while constants follow SCREAMING_SNAKE_CASE (see `src/constants.cairo`). Document public ABI functions with triple-slash comments so downstream tooling surfaces them. Always run `scarb fmt` and address formatter feedback instead of manual spacing tweaks.

## Testing Guidelines

- Write positive and guard-path assertions for new behavior; regressions need reproducing tests.
- Keep unit helpers alongside their modules (for example, TWAMM helpers stay in `src/utils.cairo`); scenario tests stay in `tests/`.
- Name tests `test_<feature>_<expectation>` for searchable failures.
- Leverage Foundry fuzzing, storage inspection, and forking when edge cases demand it.

## Feature Notes

- TicketMaster now tracks a low-issuance mode controlled by oracle pricing. Enter the mode when the three-day average price is below `issuance_reduction_price_x128`, and exit only after the average rises back above the threshold.
- Reducing issuance relies on `issuance_reduction_bips`; validate inputs remain `< BIPS_BASIS` and ensure tests cover both entry and exit paths.
- Constructor calls must supply the Ekubo oracle address plus issuance reduction parameters, and tests in `tests/test_contract.cairo` set expectations for the new getters (`is_low_issuance_mode`, `get_low_issuance_returned_tokens`, etc.).
- Constructor now also accepts the veLords revenue recipient address; deployment tooling and tests must thread this parameter and leverage `set_velords_address` for post-deploy rotations.
- Constructor now also requires the address of the position NFT contract; make sure helpers and deployment scripts thread this through whenever the positions deployment differs from the NFT address.
- `init_distribution_pool` now accepts a single distribution tick (owner-only), persists it, and returns the pool identifier; `provide_initial_liquidity` likewise takes payment/dungeon/minimum amounts and is owner-only. Deployment tooling should derive the distribution tick after the contract address is known and pass the liquidity values to this step.
- proceeds distribution splits payment token balances 20/80 between the stored veLords address and TWAMM buybacks; use the new setter when rotating recipients.
Favor positive and guard-path assertions for any new logic; regressions need reproducing tests. Unit helpers should live with their modules (e.g., TWAMM helpers in `src/utils.cairo`), while end-to-end scenarios stay under `tests/`. Name tests `test_<feature>_<expectation>` to keep failure output searchable. For fork tests, annotate with `#[fork("<network>")]` and verify prerequisites such as approvals or oracle mocks. Leverage Foundry fuzzing and storage inspection when defending edge cases like low-issuance mode transitions. When adding new storage variables or getters (e.g., `liquidity_position_id`), ensure corresponding getter tests verify storage consistency after relevant state transitions.

## Commit & Pull Request Guidelines

- Follow Conventional Commits (`feat:`, `fix:`, `refactor:`, `docs:`); keep subjects under ~70 characters.
- Squash fixups locally and avoid merge commits in feature branches.
- PRs should outline context, cite `snforge` commands run, link issues, and flag security-sensitive changes.
Follow Conventional Commits (`feat:`, `fix:`, `refactor:`, `docs:`) with subjects under ~70 characters. Squash fixups locally and avoid merge commits in feature branches. PR descriptions should summarize context, cite the `snforge` commands run, link relevant issues, and highlight security-sensitive touchpoints (reentrancy, access control, math safety). Before requesting review, ensure formatting is clean, fork tests are green, and new parameters (e.g., oracle, veLords, position NFT addresses) are wired through constructors and deployment helpers.

## Security & Review Focus

- Treat reentrancy, access control, and math safety as audit priorities; justify deviations from established patterns.
- Prefer incremental, tested changes; validate risky modifications locally before requesting review.
Validate oracle-driven low-issuance flows (`enable_low_issuance_mode`, `disable_low_issuance_mode`) with both entry and exit tests. Treat proceeds distribution, TWAMM interactions, and owner-only pathways as audit priorities—justify any departure from existing patterns. Confirm external calls (registries, Ekubo dispatchers, ERC20/ERC721 withdrawals) respect access control and cannot strand tokens. When touching deployment scripts, thread new addresses and ticks end-to-end to prevent misconfigured mainnet operations.
3 changes: 2 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,8 @@ The contract implements sophisticated time alignment for TWAMM compatibility:
contract owner. The distribution tick should be derived off-chain after the contract address is known.
- `provide_initial_liquidity` likewise accepts payment- and dungeon-token amounts plus a minimum
liquidity threshold, and only the owner may call it. Deployment scripts must forward the desired
liquidity configuration at invocation time.
liquidity configuration at invocation time. The function stores the returned liquidity position ID
in contract storage, accessible via `get_liquidity_position_id()` for tracking the initial liquidity NFT.

### Issuance Throttling

Expand Down
76 changes: 76 additions & 0 deletions GEMINI.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# TicketMaster Cairo Project

## Project Overview

This project implements a TicketMaster smart contract on the Starknet blockchain using the Cairo language. It leverages Ekubo's TWAMM (Time-Weighted Average Market Maker) extension to create a sophisticated, demand-based pricing mechanism for "Dungeon Tickets". The contract is an extension of OpenZeppelin's ERC20 component and includes a state machine to manage the lifecycle of token distribution.

The core functionalities include:
- **Automated Market Making:** Initializes a TWAMM pool on Ekubo to facilitate the sale of Dungeon Tickets.
- **Dynamic Pricing:** The price of tickets is determined by market demand through the TWAMM.
- **Issuance Throttling:** The contract can reduce the rate of ticket issuance if the market price falls below a configurable threshold, and resume when the price recovers.
- **Proceeds Distribution:** Proceeds from ticket sales are split between a treasury and a buyback mechanism for a different token.

## Building and Running

The project uses Scarb for dependency management and Starknet Foundry for testing.

### Prerequisites

- [Scarb](https://docs.swmansion.com/scarb/) v2.12.2+
- [Starknet Foundry](https://foundry-rs.github.io/starknet-foundry/) v0.49.0+

### Setup

1. **Clone the repository:**
```bash
git clone <repo-url>
cd ticket-master
```

2. **Install dependencies:**
```bash
scarb build
```

### Build

To compile the contract, run:

```bash
scarb build
```

### Testing

The project includes a comprehensive test suite using Starknet Foundry.

- **Run all tests:**
```bash
snforge test
```

- **Run tests with forking:**
The tests can be run against a forked mainnet or sepolia environment.
```bash
snforge test --fork mainnet
snforge test --fork sepolia
```

## Development Conventions

### Code Style

The project follows the standard Cairo formatting guidelines. Use `scarb fmt` to format the code.

### Testing Practices

- **Unit Tests:** Located alongside the source code (e.g., `src/utils.cairo`).
- **Integration Tests:** Located in the `tests/` directory, covering the full contract lifecycle.
- **Fork Testing:** Tests are run against forked environments to ensure correct integration with external contracts like Ekubo.

### Contribution Guidelines

1. Format code with `scarb fmt`.
2. Run all tests, including fork tests.
3. Update documentation and tests along with code changes.
4. Follow Conventional Commits for git history (e.g., `feat:`, `fix:`, `refactor:`).
39 changes: 23 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ The contract follows a strict four-phase deployment sequence:
- Mints `dungeon_amount` of dungeon tickets directly to Ekubo Positions contract
- Calls Ekubo's `mint_and_deposit_and_clear_both` with symmetric bounds to establish the initial liquidity position
- Validates that the resulting liquidity meets the `min_liquidity` threshold
- Stores the liquidity position ID for future reference
- Advances state to `2 (LiquidityProvided)`

3. **Start Token Distribution** – `start_token_distribution()` (callable by anyone once liquidity is provided)
Expand All @@ -100,21 +101,22 @@ The contract follows a strict four-phase deployment sequence:
- Caches the position NFT token ID and advances state to `3 (DistributionStarted)`

4. **Recycle Proceeds** – Ongoing operations after distribution starts:
- `claim_proceeds()`: Withdraws realized payment token sales from the distribution TWAMM order, then splits proceeds 80% to treasury and 20% for buybacks
- `distribute_proceeds()`: Creates a new TWAMM buyback order using the accumulated 20% share, converting payment tokens back to buyback tokens over time
- `claim_and_distribute_buybacks(limit)`: Iterates through matured buyback orders, withdrawing completed buyback tokens and forwarding them to the veLords address
- `claim_proceeds()`: Withdraws realized payment token sales from the distribution TWAMM order
- `distribute_proceeds(end_time)`: Splits proceeds 80% to buybacks and 20% to veLords, then creates a new TWAMM buyback order that starts immediately and runs until `end_time`
- `claim_and_distribute_buybacks(limit)`: Iterates through matured buyback orders, withdrawing completed buyback tokens and forwarding them to the treasury address

### Buyback Order Configuration

The constructor accepts a `BuybackOrderConfig` structure that defines constraints for buyback TWAMM orders created
during proceeds distribution. This configuration includes:

- `min_delay` / `max_delay`: Valid time window (in seconds) between claiming proceeds and when the buyback order can start
- `min_delay` / `max_delay`: *(Currently unused - buyback orders always start immediately)* Reserved for future use
- `min_duration` / `max_duration`: Valid duration range (in seconds) for the buyback order execution
- `fee`: The pool fee tier to use for buyback orders (encoded as a Q128 value)

These constraints ensure buyback orders are created with parameters that match the protocol's operational requirements
and prevent invalid TWAMM order configurations.
and prevent invalid TWAMM order configurations. Note that all buyback orders start immediately (`start_time = 0`)
upon calling `distribute_proceeds(end_time)`.

### Issuance Reduction Guard

Expand All @@ -124,33 +126,38 @@ The contract implements dynamic issuance throttling that responds to market cond
`issuance_reduction_price_duration` in seconds, owner-configurable) returned by Ekubo's on-chain oracle.
When the average price drops below the configured Q128 threshold (`issuance_reduction_price_x128`), the
function reduces the active distribution sale rate by `issuance_reduction_bips` (basis points) and holds
the reclaimed tokens on the contract.
the reclaimed tokens on the contract. Returns the number of tokens returned from the TWAMM order.
- `disable_low_issuance_mode()` performs the inverse operation: once the average price climbs back above
the threshold over the same lookback period (querying Ekubo's on-chain oracle), the stored tokens are
re-supplied to the TWAMM position and the original sale rate is restored.
re-supplied to the TWAMM position and the original sale rate is restored. Returns the new distribution rate.
- `force_enable_low_issuance_mode()` and `force_disable_low_issuance_mode()` (owner-only) allow emergency
override of the oracle-driven checks, enabling manual control during oracle failures or extreme market conditions.
- The contract exposes `is_low_issuance_mode()`, `get_low_issuance_returned_tokens()`,
`get_issuance_reduction_price_x128()`, `get_issuance_reduction_price_duration()`, and
`get_issuance_reduction_bips()` so off-chain monitoring can track throttle state and configuration.

This mechanism protects against oversupply during unfavorable market conditions while maintaining flexibility to
resume normal distribution rates when conditions improve.
resume normal distribution rates when conditions improve. The force functions provide emergency controls for the
contract owner to respond to unforeseen circumstances.

### Public Interface Highlights

The on-chain interface (`ITicketMaster`) exposes:

- **Lifecycle actions**: `init_distribution_pool`, `provide_initial_liquidity`, `start_token_distribution`,
`claim_proceeds`, `claim_and_distribute_buybacks`, `distribute_proceeds`,
`enable_low_issuance_mode`, `disable_low_issuance_mode`
`claim_proceeds`, `claim_and_distribute_buybacks`, `distribute_proceeds`
- **Issuance controls**: `enable_low_issuance_mode`, `disable_low_issuance_mode`,
`force_enable_low_issuance_mode`, `force_disable_low_issuance_mode`
- **Pool & order metadata**: `get_distribution_pool_key`, `get_distribution_pool_key_hash`,
`get_distribution_order_key`, `get_pool_id`, `get_distribution_fee`, `get_buyback_order_config`,
`get_position_token_id`
`get_position_token_id`, `get_liquidity_position_id`
- **Distribution telemetry**: `get_token_distribution_rate`, `get_tokens_for_distribution`,
`get_distribution_end_time`, `get_distribution_initial_tick`, `get_lords_price_x128`,
`get_dungeon_ticket_price_x128`, `get_survivor_price_x128`
- **Issuance controls**: `is_low_issuance_mode`, `get_low_issuance_returned_tokens`,
`get_issuance_reduction_price_x128`, `get_issuance_reduction_price_duration`, `get_issuance_reduction_bips`
- **Administrative controls**: `set_treasury_address`, `set_velords_address`, `set_issuance_reduction_price_duration`,
`get_distribution_end_time`, `get_distribution_initial_tick`, `get_dungeon_ticket_price_x128`
- **Issuance telemetry**: `is_low_issuance_mode`, `get_issuance_reduction_price_x128`,
`get_issuance_reduction_price_duration`, `get_issuance_reduction_bips`
- **Administrative controls**: `set_treasury_address`, `set_velords_address`,
`set_issuance_reduction_price_x128`, `set_issuance_reduction_price_duration`,
`set_issuance_reduction_bips`, `set_buyback_order_config`,
`withdraw_erc721`, `withdraw_erc20`
- **Deployment helpers**: `get_deployed_at`, `get_payment_token`, `get_buyback_token`,
`get_extension_address`, `get_core_dispatcher`, `get_positions_dispatcher`,
Expand Down
2 changes: 2 additions & 0 deletions src/constants.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ pub mod Errors {
pub const NO_TICKETS_AVAILABLE: felt252 = 'no tickets available';
pub const REDUCTION_BIPS_TOO_LARGE: felt252 = 'reduction bips too large';
pub const REDUCTION_DURATION_NOT_SET: felt252 = 'reduction duration not set';
pub const LOW_ISSUANCE_CRITERIA_NOT_MET: felt252 = 'low issuance criteria not met';
pub const DISABLE_LOW_ISSUANCE_CRITERIA_NOT_MET: felt252 = 'disable criteria not met';
}

// Mathematical constants
Expand Down
Loading