generated from scaffold-eth/scaffold-eth
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #22 from moonshotcollective/week2-stake-unstake
Week2 stake unstake
- Loading branch information
Showing
11 changed files
with
158 additions
and
279 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
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,159 +1,87 @@ | ||
pragma solidity >=0.8.0 <0.9.0; | ||
|
||
//SPDX-License-Identifier: MIT | ||
pragma solidity >=0.8.0 <0.9.0; | ||
|
||
import {IStaking} from "./IStaking.sol"; | ||
|
||
// import "hardhat/console.sol"; | ||
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; | ||
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; | ||
|
||
contract Staking is IStaking, Ownable { | ||
contract Staking is Ownable { | ||
IERC20 public token; | ||
uint256 public fee; | ||
|
||
constructor( | ||
IERC20 _token, | ||
uint256 _quorum, | ||
uint256 _fee | ||
) payable { | ||
token = _token; | ||
fee = _fee; | ||
quorum = _quorum; | ||
} | ||
uint256 public start; | ||
uint256 public duration; | ||
mapping(address => uint256) stakes; | ||
|
||
function updateJuror(address juror, bool active) | ||
public | ||
virtual | ||
override | ||
onlyOwner | ||
{ | ||
jurors[juror] = active; | ||
event tokenStaked(address staker, uint256 amount); | ||
event tokenUnstaked(address staker, uint256 amount); | ||
|
||
emit jurorAction(juror, active); | ||
modifier canUnstake() { | ||
require( | ||
(start == 0 && duration == 0) || | ||
(start > block.timestamp) || | ||
(start < block.timestamp && block.timestamp > start + duration), | ||
"Can't unstake during an active round" | ||
); | ||
_; | ||
} | ||
|
||
// stake | ||
function stake(uint256 amount) public virtual override { | ||
token.transferFrom(msg.sender, address(this), amount); | ||
|
||
stakes[msg.sender].balance += amount; | ||
|
||
emit tokenStaked(msg.sender, amount); | ||
constructor(IERC20 _token) payable { | ||
token = _token; | ||
} | ||
|
||
function unstake(uint256 amount) public virtual override { | ||
function updateMeta(uint256 _start, uint256 _duration) public onlyOwner { | ||
require( | ||
stakes[msg.sender].balance >= amount, | ||
"Not enough balance to withdraw" | ||
_start > 0 && _duration > 0, | ||
"start and duration has to be > 0" | ||
); | ||
require(!stakes[msg.sender].locked, "Your stakes are currently locked"); | ||
|
||
stakes[msg.sender].balance -= amount; | ||
|
||
token.transfer(msg.sender, amount); | ||
|
||
emit tokenWithdrawn(msg.sender, amount); | ||
} | ||
|
||
function challenge(address[] memory stakers) | ||
public | ||
virtual | ||
override | ||
returns (bytes32 id) | ||
{ | ||
// create challenge ID | ||
id = keccak256(abi.encodePacked(msg.sender, block.number)); | ||
uint256 totalStakers = stakers.length; | ||
|
||
require( | ||
totalStakers > 0 && totalStakers < 255, | ||
"Stakers out of bounds" | ||
start + duration < block.timestamp, | ||
"A round is currently active" | ||
); | ||
require(challenges[id].challenger == address(0), "Non-unique ID"); | ||
|
||
// pay challenge fee | ||
token.transferFrom(msg.sender, address(this), fee); | ||
|
||
// initiate challenge | ||
challenges[id].amount = fee; | ||
challenges[id].challenger = msg.sender; | ||
|
||
for (uint256 i = 0; i < totalStakers; i++) { | ||
address currentStaker = stakers[i]; | ||
require( | ||
stakes[currentStaker].balance > 0, | ||
"Not enough balance staked" | ||
); | ||
require( | ||
!challenges[id].stakerList[currentStaker], | ||
"Duplicate staker in array" | ||
); | ||
|
||
stakes[currentStaker].locked = true; | ||
challenges[id].stakers.push(currentStaker); | ||
challenges[id].stakerList[currentStaker] = true; | ||
} | ||
|
||
emit challenged(msg.sender, id); | ||
require( | ||
_start > block.timestamp, | ||
"start point should be in the future" | ||
); | ||
start = _start; | ||
duration = _duration; | ||
} | ||
|
||
function voteChallenge(bytes32 id) | ||
function fetchMeta() | ||
public | ||
virtual | ||
override | ||
onlyJuror | ||
challengeExists(id) | ||
view | ||
returns ( | ||
uint256 _start, | ||
uint256 _duration, | ||
bool isActiveRound | ||
) | ||
{ | ||
challenges[id].voted[msg.sender] = true; | ||
challenges[id].votes += 1; | ||
challenges[id].voters.push(msg.sender); | ||
|
||
emit challengeVoted(id, msg.sender); | ||
return ( | ||
start, | ||
duration, | ||
start < block.timestamp && block.timestamp < (start + duration) | ||
); | ||
} | ||
|
||
function finalizeChallenge(bytes32 id) | ||
public | ||
virtual | ||
override | ||
challengeExists(id) | ||
{ | ||
challenges[id].resolved = true; | ||
// stake | ||
function stake(uint256 amount) public { | ||
token.transferFrom(msg.sender, address(this), amount); | ||
|
||
uint256 amount = challenges[id].amount; | ||
challenges[id].amount = 0; | ||
address[] memory challengedAddresses = challenges[id].stakers; | ||
stakes[msg.sender] += amount; | ||
|
||
// slashes & payout | ||
for (uint256 i = 0; i < challengedAddresses.length; i++) { | ||
amount += stakes[challengedAddresses[i]].balance; | ||
stakes[challengedAddresses[i]].balance = 0; | ||
} | ||
emit tokenStaked(msg.sender, amount); | ||
} | ||
|
||
uint256 totalVoters = challenges[id].voters.length; | ||
// unstake | ||
function unstake(uint256 amount) public canUnstake { | ||
require(stakes[msg.sender] >= amount, "Not enough balance to withdraw"); | ||
|
||
// split token among voters and challenger | ||
uint256 share = ((amount * 80) / 100) / totalVoters; | ||
token.transferFrom( | ||
address(this), | ||
challenges[id].challenger, | ||
(amount * 20) / 100 | ||
); | ||
stakes[msg.sender] -= amount; | ||
|
||
for (uint256 i = 0; i < totalVoters; i++) { | ||
token.transferFrom(address(this), challenges[id].voters[i], share); | ||
} | ||
token.transfer(msg.sender, amount); | ||
|
||
emit challengeFinalized(id); | ||
emit tokenUnstaked(msg.sender, amount); | ||
} | ||
|
||
function getStakeFor(address user) | ||
public | ||
view | ||
virtual | ||
override | ||
returns (Stake memory) | ||
{ | ||
// view for stake amount | ||
function getStakeFor(address user) public view returns (uint256) { | ||
return stakes[user]; | ||
} | ||
} |
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
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
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
Oops, something went wrong.