-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
380c582
commit 832f70b
Showing
5 changed files
with
175 additions
and
298 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,4 +10,6 @@ out/ | |
# Dotenv file | ||
.env | ||
|
||
node_modules/ | ||
node_modules/ | ||
|
||
lcov.info |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,66 +1,65 @@ | ||
## Foundry | ||
## Overview | ||
|
||
**Foundry is a blazing fast, portable and modular toolkit for Ethereum application development written in Rust.** | ||
Enables keypers to stake SHU tokens for a minimum period. In exchange, keypers receive rewards in the form of | ||
SHU. Rewards are automatically compounded when the contract state is updated and can be withdraw at any time. | ||
|
||
Foundry consists of: | ||
The architecture consists of two contracts: | ||
|
||
- **Forge**: Ethereum testing framework (like Truffle, Hardhat and DappTools). | ||
- **Cast**: Swiss army knife for interacting with EVM smart contracts, sending transactions and getting chain data. | ||
- **Anvil**: Local Ethereum node, akin to Ganache, Hardhat Network. | ||
- **Chisel**: Fast, utilitarian, and verbose solidity REPL. | ||
1. [Staking Contract](docs/staking-contract.md): The main contract where keypers can stake SHU tokens and claim rewards. | ||
2. [Rewards Distributor Contract](docs/rewards-distributor.md): A contract that distributes rewards to the | ||
staking contract at a fixed rate per second. | ||
|
||
## Documentation | ||
The contracts are designed to be customizable, with adjustable parameters such as the lock period, minimum stake, and reward emission. Additionally, the contracts uses the Transparent Proxy pattern, where only the DAO has the permission to upgrade the contract and call the owner functions defined below. | ||
|
||
https://book.getfoundry.sh/ | ||
## Security Considerations | ||
|
||
## Usage | ||
1. The contracts uses the Ownable2Step pattern where only the DAO has the | ||
permission to upgrade the contract and call the owner functions. | ||
2. The contracts follows the checks-effects-interactions pattern to | ||
prevent reentrancy attacks. | ||
3. The contracts has 100% unit test coverage | ||
4. The contracts has been deployed to the testnet and integration tests | ||
have been run. | ||
5. The contracts has integration tests running against the mainnet fork | ||
to ensure the contract behaves as expected in a real environment. | ||
6. The contracts has been audited by a third-party security firm or audit contest platform. | ||
7. An AST analyzer has been run on the staking contract. | ||
8. There are CI checks in place to ensure the code is formatted correctly and | ||
the tests pass. | ||
|
||
### Build | ||
## FAQ | ||
|
||
```shell | ||
$ forge build | ||
``` | ||
1. Is there a deadline for distributing the rewards? | ||
No, the rewards distribution will continue until the rewards contract is depleted. | ||
|
||
### Test | ||
2. Can the stkSHU token be transferred? | ||
No, the stkSHU token is non-transferable. Keyper can only unstake the SHU | ||
tokens which will burn the stkSHU tokens. | ||
|
||
```shell | ||
$ forge test | ||
``` | ||
3. Is the lock period the same for all stakes? | ||
No, each stake has an individual lock period determined by the current lock period set by the DAO at the time of keyper's stake. The lock period can be updated by the DAO. If the new lock period is shorter than the current one for that stake, the new lock period will be honored. This allows keyper to trust that their tokens will not be locked for longer than the originally agreed-upon period when they staked, and also enables keyper to unstake their tokens in emergency situations. | ||
|
||
### Format | ||
4. Are the rewards distributed per second or per block? | ||
Per second. | ||
|
||
```shell | ||
$ forge fmt | ||
``` | ||
5. Are the rewards automatically compounded? | ||
Yes, the rewards are automatically compounded when the contract state is updated, i.e., when anyone interacts with a non-view function. | ||
|
||
### Gas Snapshots | ||
6. Are the rewards calculated based on individual stakes or the total amount of shares the keyper has? | ||
The rewards are calculated based on the total amount of shares the keyper | ||
has. This means that when the keyper claims rewards, they will receive the | ||
rewards for all their stakes. | ||
|
||
```shell | ||
$ forge snapshot | ||
``` | ||
7. When unstaking, are the rewards also transferred to the keyper? | ||
The keyper has the option to choose whether they want to claim the rewards when they unstake. This is the default behavior. | ||
|
||
### Anvil | ||
8. Is there a minimum stake amount? | ||
Yes, there is a minimum amount of SHU tokens that must be staked at the first | ||
stake. This amount can be set by the DAO. An unstake can never result in a | ||
balance lower than the minimum stake amount. | ||
|
||
```shell | ||
$ anvil | ||
``` | ||
## Protocol Invariants [TBD] | ||
|
||
### Deploy | ||
|
||
```shell | ||
$ forge script script/Counter.s.sol:CounterScript --rpc-url <your_rpc_url> --private-key <your_private_key> | ||
``` | ||
|
||
### Cast | ||
|
||
```shell | ||
$ cast <subcommand> | ||
``` | ||
|
||
### Help | ||
|
||
```shell | ||
$ forge --help | ||
$ anvil --help | ||
$ cast --help | ||
``` | ||
1. The total amount of SHU tokens staked in the contract must be equal to the | ||
total amount of SHU tokens staked by each keyper: `totalStaked = sum(stakes[keyper].amount)`. | ||
2. On unstake, `keyperStake.timestamp + lockPeriod <= block.timestamp` if global `lockPeriod` is greater or equal to the stake lock period, otherwise `keyperStake.timestamp + keyperStake.lockPeriod <= block.timestamp`. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
# Rewards Distribution Contract | ||
|
||
The rewards distribution contract is responsible for distributing rewards to the | ||
staking and delegate contract. The rewards distribution contract is owned by the DAO and | ||
contains the rewards emission rate for each receiver, i.e either the staking or | ||
delegate contract. | ||
|
||
## Storage Layout | ||
|
||
- `mapping(address receiver => RewardConfiguration configuration) public | ||
rewardConfigurations`: a mapping from the receiver address to the reward configuration. | ||
|
||
```solidity | ||
struct RewardConfiguration { | ||
uint256 emissionRate; // emission per second | ||
uint256 lastUpdate; // last update timestamp | ||
} | ||
``` | ||
|
||
1. The `emissionRate` defines the number of rewards tokens distributed per | ||
second. This is a fixed rate and determines how many reward tokens the contract | ||
allocates every second to be distributed to all the stakers in the receiver contract. | ||
|
||
2. The `lastUpdate` timestamp is the last time the rewards were distributed to the | ||
receiver contract. This timestamp is used to calculate the rewards accumulated | ||
since the last update. | ||
|
||
## Owner Functions (DAO) | ||
|
||
### `setRewardConfiguration(address receiver, uint256 emissionRate)` | ||
|
||
Add, update or stop distributing rewards to a receiver. The emission rate is | ||
the number of reward tokens distributed per second. This function can only be | ||
called by the Owner (DAO). If the emission rate for the specified receiver is not 0, | ||
the function will update the `emissionRate`. If the owner wants to stop | ||
distributing rewards, they should set the emission rate to 0. | ||
|
||
## Permissionless Functions | ||
|
||
### `distributionRewards()` | ||
|
||
Distribute all the rewards to the receiver contract accumulated until from the | ||
`lastUpdate` timestamp to the current timestamp. If the msg.sender is not one of | ||
the receivers, the function will revert. | ||
|
||
## View Functions | ||
|
||
### `getRewardConfiguration(address receiver)` | ||
|
||
Get the reward configuration for a specific receiver. |
Oops, something went wrong.