# xCTR Staking

xCTR is an upgradeable ERC-4626 vault with voting power (ERC20Votes). It is **non-transferable** — `transfer()` and `transferFrom()` revert. Standard ERC-4626 `withdraw()` and `redeem()` also revert; use the exit system instead.

## Specifications

| Property     | Value                               |
| ------------ | ----------------------------------- |
| Name         | Staked CTR                          |
| Symbol       | xCTR                                |
| Decimals     | 18                                  |
| Standard     | ERC-4626 + ERC20Votes (upgradeable) |
| Transferable | No                                  |
| Clock Mode   | Timestamp                           |

## Configuration

| Parameter               | Default    | Description                         |
| ----------------------- | ---------- | ----------------------------------- |
| `epochPeriod`           | 7 days     | Reward streaming period             |
| `minExitDuration`       | 15 days    | Minimum wait before exit completion |
| `maxExitDuration`       | 90 days    | Wait time for zero penalty          |
| `minExitPenaltyBps`     | 0 (0%)     | Penalty at max duration             |
| `maxExitPenaltyBps`     | 5000 (50%) | Penalty at min duration             |
| `instantExitPenaltyBps` | 5000 (50%) | Fixed instant exit penalty          |

All parameters are updatable by the contract owner.

## Staking

Deposit CTR to receive xCTR shares:

```solidity
// Approve first
ctr.approve(xCTR_ADDRESS, amount);

// Deposit CTR, receive xCTR
uint256 shares = xCTR.deposit(amount, receiver);

// Or specify shares
uint256 assets = xCTR.mint(shares, receiver);
```

Shares are calculated at the current exchange rate (`totalAssets / totalSupply`). As rewards accrue, each xCTR becomes redeemable for more CTR.

## Rewards

Rewards are streamed linearly over weekly epochs:

1. Rewards added via `addRewards(amount)` are queued for the **next** epoch
2. When a new epoch starts, queued rewards stream linearly over 7 days
3. Exit penalties are also added as rewards for remaining stakers

```solidity
// Add external rewards (requires approval)
ctr.approve(xCTR_ADDRESS, rewardAmount);
xCTR.addRewards(rewardAmount);
```

## Exit System

### Start Exit

Burns xCTR shares and locks the CTR value at the current exchange rate:

```solidity
uint256 exitId = xCTR.startExit(shares);
```

Each user can have multiple pending exits, each with its own ID and timeline. Exit parameters (penalty rates, durations) are **snapshotted** at start time — subsequent parameter changes don't affect existing exits.

### Complete Exit (after day 15)

Penalty decreases linearly from 50% → 0% over the exit window:

```solidity
xCTR.completeExit(exitId);
```

Penalty formula:

```
penaltyBps = minPenalty + (maxPenalty - minPenalty) × (maxDuration - elapsed) / (maxDuration - minDuration)
```

### Cancel Exit (before day 15)

Returns xCTR at the current exchange rate (may differ from original amount):

```solidity
xCTR.cancelExit(exitId);
```

### Instant Exit

Immediate withdrawal with a fixed 50% penalty:

```solidity
xCTR.instantExit(shares);
```

## Read Functions

```solidity
// xCTR balance
uint256 shares = xCTR.balanceOf(user);

// CTR value of shares
uint256 ctrValue = xCTR.convertToAssets(shares);

// Shares needed for a CTR amount
uint256 sharesNeeded = xCTR.convertToShares(ctrAmount);

// Total assets backing all xCTR
uint256 total = xCTR.totalAssets();

// Preview exit outcome
(uint256 assets, uint256 minDur, uint256 maxDur, uint256 minPen, uint256 maxPen) = xCTR.previewStartExit(shares);

// Preview completion at a given timestamp
(uint256 netAssets, uint256 penalty) = xCTR.previewCompleteExit(user, exitId, timestamp);

// Preview cancellation
(uint256 assets, uint256 sharesRestored) = xCTR.previewCancelExit(user, exitId);

// Penalty calculations
uint256 penalty = xCTR.getExitPenalty(assets, duration);
uint256 instantPenalty = xCTR.getInstantExitPenalty(assets);
```

## Voting

xCTR integrates ERC20Votes for governance. Voting power equals xCTR balance but must be delegated to activate:

```solidity
// Delegate to self
xCTR.delegate(msg.sender);

// Delegate to another address
xCTR.delegate(delegatee);

// Check voting power
uint256 votes = xCTR.getVotes(account);

// Historical voting power
uint256 pastVotes = xCTR.getPastVotes(account, timestamp);
```

## Events

| Event                                                    | Description                   |
| -------------------------------------------------------- | ----------------------------- |
| `RewardsAdded(sender, amount, isPenalty)`                | Rewards queued for next epoch |
| `ExitStarted(user, exitId, shares, assets)`              | Exit initiated                |
| `ExitCompleted(user, exitId, amount, penalty, duration)` | Exit finalized                |
| `ExitCancelled(user, exitId, assets, sharesRestored)`    | Exit cancelled, xCTR restored |
| `InstantExited(user, shares, amount, penalty)`           | Instant exit executed         |


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.citrea.xyz/developer-documentation/ctr-token/staking.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
