-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathStake.sol
87 lines (61 loc) · 3.12 KB
/
Stake.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
// SPDX-License-Identifier: MIT
pragma solidity 0.8.4;
contract Staker {
address public owner;
constructor(address exampleExternalContractAddress) public {
owner = msg.sender;
}
uint256 public constant threshold = 1 wei;
// Staking deadline. After this deadline, anyone send the funds
// to the other contract
uint256 public deadline = block.timestamp + 180 seconds;
// Collect funds in a payable `stake()` function and track individual `balances` with a mapping:
// ( make sure to add a `Stake(address,uint256)` event and emit it for the frontend <List/> display )
// emit event each time
event Stake(address indexed sender, uint256 amount);
// Balances of the users' staked funds
mapping(address => uint256) public balances;
function stake() public payable {
// update the user's balance
balances[msg.sender] += msg.value;
// emit the event to notify the blockchain that we have correctly Staked some fund for the user
emit Stake(msg.sender, msg.value);
}
// After some `deadline` allow anyone to call an `execute()` function
// It should either call `exampleExternalContract.complete{value: address(this).balance}()` to send all the value
//function execute() public stakeNotCompleted deadlineReached(false) {
function execute() public {
require(timeLeft() == 0, "Deadline not yet expired");
uint256 contractBalance = address(this).balance;
// check the contract has enough ETH to reach the threshold
require(contractBalance >= threshold, "Threshold is not reached");
// Execute the external contract, transfer all the balance to the contract
// (bool sent, bytes memory data) = exampleExternalContract.complete{value: contractBalance}();
(bool sent,) = address(exampleExternalContract).call{value: contractBalance}(abi.encodeWithSignature("complete()"));
require(sent, "exampleExternalContract.complete failed :(");
}
// if the `threshold` was not met, allow everyone to call a `withdraw()` function
// Add a `withdraw(address payable)` function lets users withdraw their balance
// function withdraw() public deadlineReached(true) stakeNotCompleted {
function withdraw(address payable depositor) public {
uint256 userBalance = balances[depositor];
// only allow withdrawals if the deadline has expired
require(timeLeft() == 0, "Deadline not yet expired");
// check if the user has balance to withdraw
require(userBalance > 0, "No balance to withdraw");
// reset the balance of the user.
// Do this before transferring balance to prevent re-entrancy attacks.
balances[depositor] = 0;
// Transfer balance back to the user
(bool sent,) = depositor.call{value: userBalance}("");
require(sent, "Failed to send user balance back to the user");
}
// Add a `timeLeft()` view function that returns the time left before the deadline for the frontend
function timeLeft() public view returns (uint256 timeleft) {
return deadline >= block.timestamp ? deadline - block.timestamp: 0;
}
// Add the `receive()` special function that receives eth and calls stake()
function receive() public {
stake();
}
}