Skip to content
Merged
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
100 changes: 68 additions & 32 deletions docs/LayerEdgeStaking.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ The LayerEdgeStaking contract implements a tiered staking system for EDGEN token
- **Tiered Staking System**: Three tiers with different reward rates
- **Dynamic Tier Allocation**: Tiers determined by staking position and total active stakers
- **Reward Mechanisms**: Simple claiming or compounding options
- **Unstaking Rules**: Unstaking window of 7 days and permanent tier downgrade after unstaking
- **Unstaking Rules**: Two-step unstaking process with a 7-day waiting period
- **Native Token Support**: Support for both ERC20 tokens and native tokens (via WETH wrapper)

## Core Components

Expand Down Expand Up @@ -42,12 +43,15 @@ The tier allocation is dynamically calculated based on the total number of activ
For each staker, the contract tracks:

- Current staked balance
- Deposit time
- Last claim time
- Interest earned but not claimed
- Total claimed interest
- Join ID (position in the staking queue)
- Whether the user is active
- Whether the user is out of the tree (permanently in Tier 3)
- Whether the user's first deposit was more than minimum stake amount
- Tier change history
- Unstake requests

### Fenwick Tree Implementation

Expand Down Expand Up @@ -80,38 +84,51 @@ This allows for O(log n) time complexity for:
└──────────────┘ └───────────────┘ └────────────────┘
```

1. User calls `stake(amount)` function
1. User calls `stake(amount)` or `stakeNative()` function
2. Contract updates any pending interest
3. Tokens are transferred to the contract
4. If first time staking, user is assigned a join ID
5. User's balance and staking details are updated
6. User's tier is determined and recorded
7. Tier boundaries are checked and updated if necessary
3. Tokens are transferred to the contract (or converted from native tokens)
4. If first time staking with more than minimum stake, user is assigned a join ID and added to the tree
5. If first time staking with less than minimum stake, user is marked as out of the tree and permanently assigned to Tier 3
6. User's balance and staking details are updated
7. User's tier is determined and recorded
8. Tier boundaries are checked and updated if necessary

### Unstaking Flow
### Unstaking Flow (Two-Step Process)

```
┌──────────┐ ┌───────────────┐ ┌────────────────┐
│ User │ │ Check Unstake │ │ Update User's │
Unstakes │────▶│ Eligibility │────▶│ Interest │
EDGEN │ │ │ │ │
Requests │────▶│ Eligibility │────▶│ Interest │
Unstake │ │ │ │ │
└──────────┘ └───────────────┘ └────────────────┘
┌──────────────┐ ┌───────────────┐ ┌────────────────┐
Transfer EDGEN│ │ Check & Update│ │ Update User │
to User │◀────│ Tier │◀────│ State & Tier
│ │ Boundaries │ │ │
Create │ │ Check & Update│ │ Update User │
Unstake │◀────│ Tier │◀────│ State & Balance
Request │ │ Boundaries │ │ │
└──────────────┘ └───────────────┘ └────────────────┘
```

Then, after the 7-day waiting period:

```
┌──────────┐ ┌───────────────┐ ┌────────────────┐
│ User │ │ Check Request │ │ Transfer EDGEN │
│ Completes│────▶│ Eligibility & │────▶│ to User │
│ Unstake │ │ Waiting Period│ │ │
└──────────┘ └───────────────┘ └────────────────┘
```

1. User calls `unstake(amount)` function
2. Contract checks that user has sufficient stake and the unstaking window (7 days) has passed
2. Contract checks that user has sufficient stake
3. Contract updates any pending interest
4. User's balance is reduced and staking details updated
5. User is marked as having unstaked, which permanently downgrades them to Tier 3
5. If balance falls below minimum stake, user is marked as out of the tree and permanently assigned to Tier 3
6. Tier boundaries are checked and updated if necessary
7. Tokens are transferred back to the user
7. An unstake request is created with timestamp
8. After 7 days, user calls `completeUnstake(index)` or `completeUnstakeNative(index)`
9. If waiting period has passed, tokens are transferred back to the user

### Interest Calculation & Claiming

Expand All @@ -135,6 +152,8 @@ Where:
- SECONDS_IN_YEAR is 31,536,000 (365 days)
- PRECISION is 10^18 (to handle decimal calculations)

The contract maintains a history of APY changes for each tier to ensure accurate interest calculations across APY changes.

### Tier Transitions

When users join or leave, tier boundaries may change, affecting other users. Let's look at some concrete examples:
Expand Down Expand Up @@ -190,10 +209,6 @@ In this example:
- Users #4 and #5 remain in Tier 3
- Users #6 and #7 join as Tier 3

This example demonstrates how a user (User #3) can move from Tier 3 to Tier 2 when new users join, due to the recalculation of tier boundaries as the total number of users increases. With 7 total users, the tier 2 allocation naturally increases to 2 users without any special minimum rules being applied.



When a user joins or leaves, the contract:
1. Calculates new tier boundaries
2. Identifies any users crossing tier boundaries
Expand All @@ -202,11 +217,11 @@ When a user joins or leaves, the contract:
Note: When a user joins or leaves the system, at most two people's tier will be changed and the method `_checkBoundariesAndRecord` will find exactly whose tier is going to change and record them.

### Key points to note
- Any user who stakes more than `minStakeAmount` will be add to the tree/tier system. They might get promoted/demoted based on FCFS condition as mentioned above.
- Any user who stakes less than `minStakeAmount` will be in Tier3 permanently and out of the tree/tier system(won't get promoted) even if they stake more later.
- Any user who unstakes and if the balance goes less than `minStakeAmount` they will also be moved out of the tree/tier system and will be in Tier 3 permanently.
- Any users who is out of the tree/system can stake more at any time but will only be earning interest at Tier3 apy.
- If compounding is enabled globally, all the users should be able to compound and earn interest with respective to their tier. This also includes user whose balance is less than `minStakeAmount` and in Tier3.
- Any user who stakes more than `minStakeAmount` will be added to the tree/tier system. They might get promoted/demoted based on FCFS condition as mentioned above.
- Any user who stakes less than `minStakeAmount` will be in Tier3 permanently and out of the tree/tier system (won't get promoted) even if they stake more later.
- Any user who unstakes and if the balance goes less than `minStakeAmount` will also be moved out of the tree/tier system and will be in Tier 3 permanently.
- Any users who is out of the tree/system can stake more at any time but will only be earning interest at Tier3 APY.
- If compounding is enabled globally, all the users should be able to compound and earn interest with respect to their tier. This also includes users whose balance is less than `minStakeAmount` and in Tier3.

## Administrative Functions

Expand Down Expand Up @@ -242,6 +257,19 @@ Rewards can be deposited by:

Rewards are tracked in a separate `rewardsReserve` balance to ensure sufficient funds are available for claiming.

## Native Token Support

The contract supports both ERC20 token staking and native token staking:

- `stake(amount)` - For staking ERC20 tokens
- `stakeNative()` - For staking native tokens (automatically wrapped to WETH)
- `claimInterest()` - For claiming ERC20 token rewards
- `claimInterestNative()` - For claiming rewards as native tokens
- `completeUnstake(index)` - For completing unstaking of ERC20 tokens
- `completeUnstakeNative(index)` - For completing unstaking as native tokens

This dual support allows for flexibility in user interactions with the staking system.

## Security Considerations

The contract implements several security measures:
Expand All @@ -257,9 +285,10 @@ The contract implements several security measures:
The contract emits the following events:

- `Staked`: When a user stakes tokens
- `Unstaked`: When a user unstakes tokens
- `Unstaked`: When a user completes unstaking tokens
- `UnstakedQueued`: When a user queues an unstake request
- `RewardClaimed`: When a user claims rewards
- `TierDowngraded`: When a user's tier is downgraded
- `TierChanged`: When a user's tier changes
- `APYUpdated`: When APY rates are updated
- `RewardsDeposited`: When rewards are deposited

Expand All @@ -280,7 +309,9 @@ The contract emits the following events:
- `users`: Mapping of user addresses to their staking information
- `stakerAddress`: Mapping of join IDs to staker addresses
- `stakerTierHistory`: History of tier changes for each user
- `activeStakerCount`: Total number of active stakers
- `unstakeRequests`: Queue of unstake requests per user
- `stakerCountInTree`: Number of stakers in the tiering tree
- `stakerCountOutOfTree`: Number of stakers permanently in Tier 3
- `totalStaked`: Total amount of tokens staked
- `rewardsReserve`: Available rewards balance
- `nextJoinId`: Next join ID to assign
Expand Down Expand Up @@ -322,12 +353,17 @@ The contract uses OpenZeppelin's UUPS (Universal Upgradeable Proxy Standard) pat
- Emergency pause functionality
- Admin function access controls

5. **Unstaking Process**
- Two-step unstaking security
- Waiting period enforcement
- Request queue management

### Known Limitations

1. **Tier System**
- Maximum of 100,000,000 users (MAX_USERS constant)
- Tier percentages are fixed (20%, 30%, 50%)
- Permanent tier downgrade after unstaking
- Permanent tier downgrade after balance falls below minimum stake

2. **Staking Rules**
- Minimum stake amount requirement
Expand Down Expand Up @@ -357,7 +393,7 @@ The contract uses OpenZeppelin's UUPS (Universal Upgradeable Proxy Standard) pat
- Direct ETH transfer vulnerabilities
- Potential balance tracking issues

Note: The staking contract will be deployed on Ethereum(or other evems) and on LayerEdge's L1 (EVM compatible).
On Ethereum, the staking token will be a simple ERC20 contract(Openzeppelin's implementation) of $EDGEN token (only $EDGEN).
Note: The staking contract will be deployed on Ethereum (or other EVMs) and on LayerEdge's L1 (EVM compatible).
On Ethereum, the staking token will be a simple ERC20 contract (OpenZeppelin's implementation) of $EDGEN token (only $EDGEN).
On LayerEdge's L1, the staking token will be a WETH9 implementation, a wrapper of native token $EDGEN.