-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathStakingContract.sol
More file actions
144 lines (101 loc) · 4.46 KB
/
StakingContract.sol
File metadata and controls
144 lines (101 loc) · 4.46 KB
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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
contract ERC721Staking is ReentrancyGuard {
using SafeERC20 for IERC20;
// Interfaces for ERC20 and ERC721
IERC20 public immutable rewardsToken;
IERC721 public immutable nftCollection;
IERC20 public immutable stakeToken;
error TransferFailed();
uint256 public totalStaked;
// Constructor function to set the rewards token and the NFT collection addresses
constructor(IERC721 _nftCollection, IERC20 _rewardsToken, IERC20 _stakeToken) {
nftCollection = _nftCollection;
rewardsToken = _rewardsToken;
stakeToken = _stakeToken;
}
struct TokenStaker{
// Amount of tokens staked by the staker
uint256 amountStaked;
// Staked token ids
//StakedToken[] stakedTokens;
// Last time of the rewards were calculated for this user
uint256 timeOfLastUpdate;
// Calculated, but unclaimed rewards for the User. The rewards are
// calculated each time the user writes to the Smart Contract
uint256 unclaimedRewards;
bool hasStaked;
}
// Rewards per hour per token deposited in wei.
uint256 private rewardsPerHour = 1;
// Mapping of User Address to Staker info
mapping(address => TokenStaker) public tokenStakers;
// Mapping of Token Id to staker. Made for the SC to remeber
// who to send back the ERC721 Token to.
mapping(uint256 => address) public stakerAddress;
address[] public stakers;
function tokenStake(uint256 _amount) external nonReentrant{
// If wallet has tokens staked, calculate the rewards before adding the new token
require(_amount > 0, "amount cannot be 0");
if (tokenStakers[msg.sender].amountStaked > 0) {
uint256 rewards = calculateRewards(msg.sender);
tokenStakers[msg.sender].unclaimedRewards += rewards;
}
stakeToken.transferFrom(msg.sender, address(this), _amount);
// stakeToken.transfer(address(this),_amount);
totalStaked = totalStaked + _amount;
tokenStakers[msg.sender].amountStaked = tokenStakers[msg.sender].amountStaked + _amount;
if(!tokenStakers[msg.sender].hasStaked){
stakers.push(msg.sender);
}
tokenStakers[msg.sender].timeOfLastUpdate = block.timestamp;
}
function tokenWithdraw() external nonReentrant{
require(tokenStakers[msg.sender].amountStaked > 0,"You have no token staked!");
uint256 rewards = calculateRewards(msg.sender);
tokenStakers[msg.sender].unclaimedRewards += rewards;
uint256 balance = tokenStakers[msg.sender].amountStaked;
stakeToken.transfer(msg.sender,balance);
totalStaked = totalStaked - balance;
tokenStakers[msg.sender].amountStaked = 0;
tokenStakers[msg.sender].timeOfLastUpdate = block.timestamp;
}
function claimRewards() external {
uint256 rewards = calculateRewards(msg.sender) +
tokenStakers[msg.sender].unclaimedRewards;
require(rewards > 0, "You have no rewards to claim");
tokenStakers[msg.sender].timeOfLastUpdate = block.timestamp;
tokenStakers[msg.sender].unclaimedRewards = 0;
rewardsToken.safeTransfer(msg.sender, rewards);
}
function checkBalance(address owner) external view returns(uint256){
uint256 balance = stakeToken.balanceOf(owner);
return balance;
}
function availableRewards(address _tokenStaker) public view returns (uint256) {
uint256 rewards = calculateRewards(_tokenStaker) +
tokenStakers[_tokenStaker].unclaimedRewards;
return rewards;
}
function availabTotalStake() public view returns (uint256){
return totalStaked;
}
function amountStaked(address _tokenStaker) external view returns(uint256){
uint256 amount = tokenStakers[_tokenStaker].amountStaked;
return amount;
}
function calculateRewards(address _tokenStaker)
internal
view
returns (uint256 _rewards)
{
return (((
((block.timestamp - tokenStakers[_tokenStaker].timeOfLastUpdate) *
tokenStakers[_tokenStaker].amountStaked)
) * rewardsPerHour) / 36000000);
}
}