> ## Documentation Index
> Fetch the complete documentation index at: https://tech.ramses.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# Fees

# Fee Architecture

Ramses V3 uses **tick spacing** to determine pool characteristics and allows **governance-controlled fee adjustment** per pool, diverging from Uniswap V3's fixed fee tiers.

<Note title="Key Difference from Uniswap V3">
  While Uniswap V3 uses predefined static fee tiers that are immutable after pool creation, Ramses V3 decouples tick spacing from fees. Each tick spacing has a default initial fee, but governance can adjust the swap fee of any pool at any time via `factory.setFee(pool, newFee)`.
</Note>

## Fee Model

### How Fees Are Set

Fees in Ramses V3 are **not determined by an on-chain algorithm during swaps**. Instead:

1. Each tick spacing has a **default initial fee** set in the factory's `tickSpacingInitialFee` mapping
2. When a pool is created, it inherits the initial fee for its tick spacing
3. Governance can **adjust any pool's fee** at any time via `RamsesV3Factory.setFee(pool, fee)`
4. The pool stores its current fee and applies it to all swaps

```solidity theme={null}
// Factory sets the fee for a specific pool (governance only)
function setFee(address _pool, uint24 _fee) external;

// Pool stores and exposes its fee
function fee() external view returns (uint24);
```

### Default Tick Spacing / Fee Mapping

| Tick Spacing | Default Fee   | Min Price Movement | Typical Use Case    | Example Pairs                |
| ------------ | ------------- | ------------------ | ------------------- | ---------------------------- |
| **1**        | 0.01% (100)   | 0.01%              | Ultra-stable        | Stablecoin pairs (USDC/USDT) |
| **5**        | 0.025% (250)  | 0.05%              | Highly correlated   | Pegged assets                |
| **10**       | 0.05% (500)   | 0.10%              | Correlated assets   | ETH/wstETH, BTC/WBTC         |
| **50**       | 0.30% (3000)  | 0.50%              | Standard volatility | Most token pairs             |
| **100**      | 1.00% (10000) | 1.00%              | Higher volatility   | Less liquid pairs            |
| **200**      | 2.00% (20000) | 2.00%              | High volatility     | Exotic/new tokens            |

Fees are denominated in parts per million (1/1,000,000). For example, `100` = 0.01%, `3000` = 0.30%.

## Swap Fee Distribution

### LP Fee Collection

Swap fees are distributed **pro-rata to all in-range liquidity** at the time of the swap:

* **In-Range Positions**: Positions where `tickLower ≤ currentTick < tickUpper` earn fees
* **Out-of-Range Positions**: Positions outside the active price earn **0 fees**
* **Fee Accrual**: Fees accumulate continuously as long as a position remains in-range
* **Manual Collection**: LPs must call `collect()` to claim accumulated fees (not auto-compounded)

```solidity theme={null}
// Collect accumulated fees for a position (via pool directly)
function collect(
    address recipient,
    uint256 index,
    int24 tickLower,
    int24 tickUpper,
    uint128 amount0Requested,
    uint128 amount1Requested
) external returns (uint128 amount0, uint128 amount1);
```

### Protocol Fee Split (feeProtocol)

The `feeProtocol` setting determines what percentage of swap fees are routed to the protocol (FeeCollector) vs staying with LPs. It is also denominated in parts per million (1/1,000,000).

The fee split differs dramatically based on whether a pool has a gauge:

#### Gauged Pools (100% to voters)

When a gauge is attached to a pool via the Voter contract, `gaugeFeeSplitEnable` sets the pool's `feeProtocol` to `1,000,000` (100%). This means **all swap fees** are routed to the `FeeCollector`, which distributes them to the pool's `FeeDistributor` for xRAM voters to claim. LPs on gauged pools earn emissions from the gauge instead of swap fees.

#### Non-Gauged Pools (95% to LPs, 5% to treasury)

Pools without a gauge use the factory's default `feeProtocol` of `50,000` (5%). This means:

* **95%** of swap fees go to LPs (collected via `pool.collect()`)
* **5%** goes to the FeeCollector, which sends it to the treasury (since there's no gauge/FeeDistributor)

### Fee Flow

```
Swap → Pool Collects Fee (per pool.fee())
   ↓
Split Based on feeProtocol Setting
   ↓
Gauged Pool (feeProtocol = 1,000,000):
   └─→ 100% → FeeCollector → FeeDistributor → xRAM Voters claim
       (minus treasuryFees share → Treasury)

Non-Gauged Pool (feeProtocol = 50,000):
   ├─→ 95% → LPs (collected via pool.collect())
   └─→ 5%  → FeeCollector → Treasury (no FeeDistributor exists)
```

## Protocol Fee Distribution

**Contract**: `FeeCollector.sol`

When `collectProtocolFees(pool)` is called, the FeeCollector:

1. Calls `pool.collectProtocol()` to pull the protocol's share of fees
2. If the pool has **no gauge** (or gauge is not alive): sends everything directly to the treasury
3. If the pool has a **live gauge**: splits fees between the FeeDistributor (for voters) and the treasury based on the `treasuryFees` ratio

| Scenario            | FeeDistributor (Voters) | Treasury                 |
| ------------------- | ----------------------- | ------------------------ |
| **Gauged pool**     | `100% - treasuryFees`   | `treasuryFees` share     |
| **Non-gauged pool** | N/A (no FeeDistributor) | 100% of protocol portion |

### FeeCollector Interface

```solidity theme={null}
interface IFeeCollector {
    // Collect protocol fees from a pool and distribute to FeeDistributor + Treasury
    function collectProtocolFees(address pool) external;

    // Treasury configuration (governance)
    function setTreasury(address newTreasury) external;
    function setTreasuryFees(uint256 _treasuryFees) external;

    // Read state
    function treasury() external returns (address);
    function treasuryFees() external returns (uint256);
}
```

### Distribution Cycle

1. **Accumulation**: Fees accumulate in pools continuously
2. **Collection**: Anyone can call `collectProtocolFees(pool)` to trigger collection and distribution (permissionless)
3. **Voter Claims**: On gauged pools, xRAM holders claim from FeeDistributor proportional to their voting weight
4. **LP Claims**: On non-gauged pools, LPs collect their 95% share anytime via `collect()`

## Integrator Considerations

### Querying Current Fees

Always query the current fee before estimating swap outputs:

```solidity theme={null}
// Get current fee for a pool
uint24 currentFee = pool.fee();

// Fee is denominated in parts per million (1/1,000,000)
// Example: 100 = 0.01%, 3000 = 0.30%
```

### Slippage Protection

Since fees can be changed by governance, set appropriate slippage tolerance:

```solidity theme={null}
// Bad: Hardcoded fee assumption
uint256 expectedOut = amountIn * (1000000 - 3000) / 1000000; // Assumes 0.30%

// Good: Query current fee
uint24 currentFee = pool.fee();
uint256 expectedOut = amountIn * (1000000 - currentFee) / 1000000;
uint256 minOut = expectedOut * 99 / 100; // 1% slippage tolerance
```

### Events

```solidity theme={null}
// Emitted by factory when a pool's fee is changed
event FeeAdjustment(address pool, uint24 newFee);

// Emitted by factory when default protocol fee changes
event SetFeeProtocol(uint24 feeProtocolOld, uint24 feeProtocolNew);

// Emitted by factory when pool-specific protocol fee changes
event SetPoolFeeProtocol(address pool, uint24 feeProtocolOld, uint24 feeProtocolNew);
```

## Additional Resources

* [Concentrated Liquidity](/concepts/protocol/concentrated-liquidity)
* [Token Contracts & Tokenomics](/concepts/tokenomics)
* [RamsesV3Pool Reference](/contracts/reference/core/RamsesV3Pool)
* [RamsesV3Factory Reference](/contracts/reference/core/RamsesV3Factory)

***

[^1]: **In-range liquidity** refers to liquidity contained in any positions where `tickLower ≤ currentTick < tickUpper`, meaning the position spans both sides of the current price.
