# Staking

## Verified Contracts

All contracts are deployed on Ethereum mainnet and verified on Etherscan.

| Contract   | Address                                      | Etherscan                                                                            |
| ---------- | -------------------------------------------- | ------------------------------------------------------------------------------------ |
| Zentachain | `0x6B58cfBEdCfe7C59d456c864c92257910A61D8FC` | [View](https://etherscan.io/address/0x6B58cfBEdCfe7C59d456c864c92257910A61D8FC#code) |
| StakeChain | `0xC00D35881e66E9eCC116De9696Ae12A18104B106` | [View](https://etherscan.io/address/0xC00D35881e66E9eCC116De9696Ae12A18104B106#code) |
| Zentanode  | `0x5a427e6aA609509C6EE089502a048f17B4895a9b` | [View](https://etherscan.io/address/0x5a427e6aA609509C6EE089502a048f17B4895a9b#code) |

***

## Overview

StakeChain is the staking smart contract that allows CHAIN token holders to stake their tokens in configurable pools and earn rewards. Rewards are minted directly to stakers — there is no pre-funded reward pool.

The contract is built on Solidity ^0.8.28 with OpenZeppelin v5.2.0 libraries and includes reentrancy protection, timestamp manipulation safeguards, and owner-controlled administration.

***

## Live Staking Pools

Three staking pools are currently active on mainnet:

| Pool | APR | Min Stake   | Max Stake    | Pool Size     | Claim Lock | Unstake Lock |
| ---- | --- | ----------- | ------------ | ------------- | ---------- | ------------ |
| 0    | 12% | 1,000 CHAIN | 10,000 CHAIN | 100,000 CHAIN | 1 day      | 7 days       |
| 1    | 16% | 2,000 CHAIN | 20,000 CHAIN | 200,000 CHAIN | 1 day      | 14 days      |
| 2    | 20% | 5,000 CHAIN | 50,000 CHAIN | 500,000 CHAIN | 1 day      | 28 days      |

Higher APR pools require larger minimum stakes and longer lock-up periods.

***

## Pool System

Each staking pool is an independent configuration with its own parameters:

| Parameter              | Description                                         |
| ---------------------- | --------------------------------------------------- |
| APR                    | Annual Percentage Rate in basis points (1600 = 16%) |
| Minimum Stake Amount   | Lowest amount a user can stake                      |
| Maximum Stake Per User | Cap on individual stakes                            |
| Pool Size Limit        | Maximum total tokens in the pool                    |
| Claim Time Lock        | Minimum time between reward claims (1 day)          |
| Unstake Time Lock      | Minimum time before withdrawal allowed              |

***

## Staking

### Standard Staking

Two-transaction process:

1. **Approve** — User approves the StakeChain contract to spend their CHAIN tokens
2. **Stake** — Call `stake(poolId, amount)` to deposit tokens into a pool

### Permit-Based Staking

Single-transaction process using ERC-2612 permit signatures:

* Call `stakeWithPermit(poolId, amount, deadline, v, r, s)`
* Combines approval and staking in one transaction
* Saves gas and improves UX

### Compound Staking

Users can add more tokens to an existing stake at any time:

* Previous rewards are preserved and continue accruing
* The unstake timer resets for the **entire** staked amount
* New rewards begin accruing on the combined amount

***

## Rewards

### Calculation

Rewards are calculated based on time elapsed and the pool's APR:

```
Annual Rewards = (Staked Amount × APR) / 10,000
Rewards Per Second = Annual Rewards / 31,536,000
Earned = Rewards Per Second × Time Elapsed
```

**Key details:**

* APR is stored in basis points (1200 = 12%, 1600 = 16%, 2000 = 20%)
* A 15-minute timestamp buffer is applied to prevent manipulation
* Rewards are **minted** to the user (inflationary), not drawn from a pool

### Claiming

* User calls `claimRewards(poolId)`
* Claim time lock (1 day) must have elapsed since last claim
* Pool must not be paused
* Rewards are minted directly to the user's wallet

***

## Unstaking

### Standard Unstake

* Unstake time lock must have elapsed since staking (7/14/28 days depending on pool)
* Returns full staked amount plus any unclaimed rewards
* Removes user from the pool

### Emergency Unstake

* Only available when emergency mode is enabled for the pool
* Bypasses time lock restrictions
* Returns staked amount plus accumulated rewards
* Emergency mode has a 24-hour toggle cooldown to prevent abuse

***

## Security

| Feature                 | Implementation                                       |
| ----------------------- | ---------------------------------------------------- |
| Reentrancy Protection   | `nonReentrant` modifier on all external calls        |
| No Contract Interaction | `noContracts` modifier blocks smart contract callers |
| APR Change Delay        | 48-hour delay prevents front-running                 |
| Timestamp Buffer        | 15-minute buffer reduces manipulation window         |
| Emergency Cooldown      | 24-hour cooldown on emergency toggle                 |
| Pause Mechanism         | Pools can be paused individually                     |
| Max Stake Limits        | Per-user cap enforcement per pool                    |

***

## Testing & Audit

| Metric               | Value                       |
| -------------------- | --------------------------- |
| Test Cases           | 152 passing (100% coverage) |
| Test Files           | 18 dedicated test files     |
| Security Rating      | 9.2 / 10                    |
| Code Quality         | 9.0 / 10                    |
| Gas Efficiency       | 8.5 / 10                    |
| Solidity Version     | ^0.8.28                     |
| OpenZeppelin Version | 5.2.0                       |
| Framework            | Hardhat + Chai              |

### Security Tests Include

* Access control enforcement
* Staking limits and pool size enforcement
* Timelock mechanism validation
* Emergency function testing
* Reward calculation precision and edge cases
* APR change protection (48-hour delay, front-running prevention)
* Timestamp manipulation protection
* Pool deletion safety (only when empty)
* Emergency toggle rate limiting
* Permit-based staking validation
* Deployment integrity verification

### Security Verification Matrix

| Check                    | Zentachain | StakeChain | Zentanode |
| ------------------------ | ---------- | ---------- | --------- |
| Reentrancy Protection    | Passed     | Passed     | Passed    |
| Access Control           | Passed     | Passed     | Passed    |
| Input Validation         | Passed     | Passed     | Passed    |
| Integer Overflow         | Passed     | Passed     | Passed    |
| Emergency Pause          | Passed     | Passed     | Passed    |
| Time Manipulation        | Passed     | Passed     | Passed    |
| Front-running Protection | Passed     | Passed     | Passed    |
| Rate Limiting            | Passed     | Passed     | Passed    |

***

## APR Changes

To prevent front-running:

1. Owner schedules an APR change via `scheduleAPRChange(poolId, newAPR)`
2. A 48-hour delay period begins
3. After the delay, anyone can call `applyPendingAPRChange(poolId)` to activate it
4. All changes are publicly visible on-chain

***

## View Functions

| Function                                     | Returns                                   |
| -------------------------------------------- | ----------------------------------------- |
| `getPoolInfo(id)`                            | Complete pool configuration               |
| `getUserStakeInfo(address, id)`              | User's staked amount, rewards, timestamps |
| `getUserRewards(address, poolId)`            | Accumulated unclaimed rewards             |
| `getUnstakeUnlockTimestamp(address, poolId)` | When unstake becomes available            |
| `getClaimUnlockTimestamp(address, poolId)`   | When next claim is available              |
| `getPoolStatus(poolId)`                      | Whether pool is paused                    |
| `getPoolEmergencyStatus(poolId)`             | Whether emergency mode is active          |
| `getMaximumStakeStatus(poolId)`              | Whether max stake is enforced             |
| `getPendingAPRChange(poolId)`                | Scheduled APR change details              |

***

## Token Contract

| Property     | Value                                        |
| ------------ | -------------------------------------------- |
| Name         | Zentachain                                   |
| Symbol       | CHAIN                                        |
| Standard     | ERC-20                                       |
| Decimals     | 12                                           |
| Total Supply | 5,000,000                                    |
| Features     | Burnable, Pausable, Permit (EIP-2612)        |
| Address      | `0x6B58cfBEdCfe7C59d456c864c92257910A61D8FC` |

StakeChain and Zentanode are both whitelisted as minters on the CHAIN token contract, allowing them to mint reward tokens directly.

***

## Zentanode Rewards Contract

A separate contract (`Zentanode.sol`) handles node operator rewards independently from StakeChain:

| Parameter         | Value                                        |
| ----------------- | -------------------------------------------- |
| Address           | `0x5a427e6aA609509C6EE089502a048f17B4895a9b` |
| Rewards Per Claim | 25 CHAIN (configurable, max 1,000)           |
| Claim Duration    | 31 days                                      |
| Slash Duration    | 15 days                                      |
| Daily Mint Limit  | 100,000 CHAIN                                |
| Access            | Allowlist-based                              |

Node operators are added to the allowlist and can claim rewards at regular intervals. The contract includes a slashing mechanism for misbehaving nodes and pro-rated partial rewards for operator removal.
