# Staking Using ERC-20 on CASPER
---
Before implementing and designing staking mechanism for Casper I conducted a research on the staking systems for Ethereum. An interesting [paper on scalable reward distribution](https://uploads-ssl.webflow.com/5ad71ffeb79acc67c8bcdaba/5ad8d1193a40977462982470_scalable-reward-distribution-paper.pdf) [1], [a staking mechanism implemented in Solidity](https://hackernoon.com/implementing-staking-in-solidity-1687302a82cf) [2] and a dicussion at [ethresear.ch](https://ethresear.ch/t/efficient-onchain-reward-distribution-pooled-payments-dividends/1924) [3] was a corner stone for the implementation presented below.
The goal of this hackaton task was for me to design and implement a similar reference staking mechanism for Casper blockchain, where the staked coin would be an ERC-20 based coin with additional staking features and a pull based reward distribution system. This means the staking mechanism would allow to collect rewards in the global contract state and the rewards could be withdrawn on demand by the account that staked the tokens.
---
## Design
Similar to the reference papers, my decision was to design and proceed with an implementation that can be further extended with more sophisticated rewards calculations and distribution.
The pieces of the puzzle to build this staking mechanism were:
* A staking token.
I forked the reference ERC-20 implementation from [Casper ecosystem](https://github.com/casper-ecosystem/erc20) and added entry points for the functions related to staking. I used a TDD (Test Driven Design) as a safety net to confirm that the staking token mechanisms would behave as I anticipated. In addition to the default ERC-20 entry points, the test staking token exposes additional functions that allow to deposit any amount of owned tokens for staking, keeping in mind the limits and allows to calculate, distribute rewards and withdraw rewards on demand.
* Data structures to keep track of stakes, stakeholders and rewards.
In addition to the default URef (unforgeable pointers) to Casper dictionaries.
stakers_uref - keeps track of all stakers, i.e. accounts that decided to stake tokens
stakes_uref - keeps track of stakes, i.e. amount of tokens staked by given account
rewards_uref - keeps track of rewards, i.e. amount of tokens to be distributed to the stakers
* Methods to create and remove stakes.
At any given time, the token owner can decide to create or remove stake. This effectively moves the tokens between owner's balance and global state of stakes kept in stakes_uref dictionary. Creating a new stake adds staked tokens.
```
#[no_mangle]
pub extern "C" fn create_stake() {
let owner: Address = runtime::get_named_arg(OWNER_RUNTIME_ARG_NAME);
let amount: U256 = runtime::get_named_arg(AMOUNT_RUNTIME_ARG_NAME);
ERC20::default()
.create_stake(owner, amount)
.unwrap_or_revert();
}
```
Removing a stake moves tokens back to the tokens balance.
```
#[no_mangle]
pub extern "C" fn remove_stake() {
let owner: Address = runtime::get_named_arg(OWNER_RUNTIME_ARG_NAME);
let amount: U256 = runtime::get_named_arg(AMOUNT_RUNTIME_ARG_NAME);
ERC20::default()
.remove_stake(owner, amount)
.unwrap_or_revert();
}
```
The functions are protected against overflows and keep track of owner balances.
* A rewards system.
I decided to keep the rewards system KISS (Keep It Simple, Stupid).
At any given time, a snapshot of all staked token balances at a given block can be used to calculate rewards. The rewards are added to rewards_uref dictionary by distribute_rewards() call for all current stakers recognized during snapshot and are waiting to be minted and withdrawn on demand. The new rewards are awarded and added to a staker balance using withdraw_reward() call.
---
## Implementation
The forked erc20 repository with the staking related enhancements is available at [GitHub](https://github.com/gitcoindev/casper-erc20-staking/commit/63f4b7fb5b2bf96aabef4ff4f832771eee53c6e5) and can be fetched and tested using the following commands:
```
$ git clone -b casper-network/gitcoin-hackathon/9/100026583 git@github.com:gitcoindev/casper-erc20-staking.git
$ cd casper-erc20-staking/
$ make test
```
Current reward distribution is 10% rounded amount of the staked tokens. As an example for 334 staked tokens the reward would be 33 tokens.
---
## Testing
At least half, if not the majority of time spent on the project was to extend the test fixture and new tests implementation. The staking functionality implementation was done in parallel to test fixture and tests implementation. The [staking integration tests](https://github.com/gitcoindev/casper-erc20-staking/commit/cb990781e9f198dc0e7f7fa184281bcb2e8e08db) can be executed together with the default ERC20 tests:
test tests::should_install ... ok
test tests::should_not_transfer_from_more_than_approved - should panic ... ok
test tests::should_not_transfer_with_insufficient_balance - should panic ... ok
test tests::should_fail_to_stake_if_balance_not_enough - should panic ... ok
test tests::should_create_stake ... ok
test tests::should_add_to_stake ... ok
test tests::should_create_and_remove_stake ... ok
test tests::should_distribute_rewards ... ok
test tests::should_transfer_from ... ok
test tests::should_transfer ... ok
test tests::should_stake_full_amount_from_two_accounts ... ok
test tests::should_transfer_full_amount ... ok
test tests::should_store_total_stakes ... ok
test tests::should_withdraw_rewards ... ok
test result: ok. 14 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 4.03s
A short description and goal of the staking related tests is as follows:
* `should_create_stake`
Verifies that a stake can be created and amount of staked tokens is correct.
* `should_add_to_stake`
Verifies that an owner can stake tokens multiple times.
* `should_create_and_remove_stake`
Verifies that tokens can be staked and removed.
* `should_distribute_rewards`
Verifies that a snapshot of staked tokens is used to distribute rewards.
* `should_stake_full_amount_from_two_accounts`
Verifies that potentially all tokens can be staked from multiple accounts.
* `should_store_total_stakes`
Verifies that total_stakes returns a total amount of staked tokens.
* `should_withdraw_rewards`
Verifies that rewards can be withdrawn and verifies correct balances after withdrawing the reward tokens.
---
## Future possibilities and enhancements
Due to limitations of the current implementation, the major enhancements to the current implementation would be:
* to introduce strict security rules, i.e. add groups / limit who can execute certain entry points, especially distribute rewards
* to design and implement a more sophisticated reward calculation mechanism
* to periodically execute staking rewards distribution if needed, (daily/hourly/per block)
---
The original version of this document is available at [hackmd.io](https://hackmd.io/OnNqdLprTqqD8vhORNFHYw).
References
[1] https://uploads-ssl.webflow.com/5ad71ffeb79acc67c8bcdaba/5ad8d1193a40977462982470_scalable-reward-distribution-paper.pdf
[2] https://hackernoon.com/implementing-staking-in-solidity-1687302a82cf
[3] https://ethresear.ch/t/efficient-onchain-reward-distribution-pooled-payments-dividends/1924