Staking Pattern
Ethereum allows a Dev to create a simple set of rules that an adversarial group of players can use to work together.
- Coordinate a group funding effort.
- If the users cooperate
- money is collected in a second smart contract
- If users defect
- the worst that can happen is everyone gets their money back.
The users only have to trust the code.
Scaffold Eth Challenge
Create a contract with:
- Collect money from multiple addresses with a payable function
- After a deadline
- if threshold of ETH has been reached
- send the balance to another contract
- trigger the complete function
- if not reached allow users to withdraw
- if threshold of ETH has been reached
Challenge Overview
Checks | Done | Notes |
---|---|---|
Staking: track user transfers/balances | X | |
State Machine & Timing | - | |
Improve Receive Function UX | - | |
Investigate Edge Cases | - | |
Mitigate Traps | - | |
Deploy and Validate | - |
Checkpoint: 🥩 Staking
Collect funds in a payable stake()
function to track account balances
using mapping
.
make sure to add a Stake(address,uint256)
event and emit it for the frontend
Goals
[x] Do you see the balance of the Staker contract go up when you stake()? [x] Is your balance correctly tracked? [x] Do you see the events in the Staker UI tab?
Checkpoint: 🔬 State Machine / Timing
At certain stages a contract may behave differently or allow different functions to be called. Function calls often:
- end one stage
- transition into the next
- state can changes occur automatically at a certain point in time
State changes of a blind auction
- accepting blinded bids
- revealing bids
- determine auction outcome
Function modifiers can be used to enforce state rules
In this exaample the state changes are:
- Staking: Active
- Success: Enough funds staked
- Withdraw: Deadline for funding has passed
Smart contracts can't execute automatically. So you need to create function that can be called externally, that control logic to use dependent on the current state of the contract.
Set a deadline for when when the contract can be checked for sufficient funds.
uint256 public deadline = block.timestamp + 30 seconds;
Goals
- Can you see timeLeft counting down in the Staker UI tab when you trigger a transaction with the faucet?
- If you stake() enough ETH before the deadline, does it call complete()?
- If you don't stake() enough can you withdraw(address payable) your funds?
Questions
Can execute get called more than once, and is that okay? Can you stake and withdraw freely after the deadline, and is that okay? What are other implications of anyone being able to withdraw for someone?
Checkpoint: 💵 Receive Function / UX
Improve the user experience, set your contract up so it accepts ETH sent to it and calls stake()
Always ensure there is a Receive function that accepts ETH sent to the contract.
Side Quest: Investigate Edge Cases
- If you send ETH directly to the contract address does it update your balance?
- Can execute get called more than once, and is that okay?
- Can you stake and withdraw freely after the deadline, and is that okay?
- What are other implications of anyone being able to withdraw for someone?
Traps
- Make sure funds can't get trapped in the contract! Try sending funds after you have executed! What happens?
- Try to create a modifier called notCompleted. It will check that ExampleExternalContract is not completed yet. Use it to protect your execute and withdraw functions.
Contract Testing
TODO: add more tests for these scenarios above.
Checkpoint 7: Deploy and Verify
See Web3 Deploy
Remember to update all the account settings!!!
Be sure to set your deadline to at least block.timestamp + 72 hours
Results
Etherscan
https://rinkeby.etherscan.io/address/0x8103919C1612bACCf55fC10d96b7756498E58170
App
https://ashamed-tray.surge.sh/
New Deploy
https://rinkeby.etherscan.io/address/0x380a51F75248baaBc97Bc17Fc06beb8a1ef54518
https://apathetic-sun.surge.sh/