forked from chocho13/token
-
Notifications
You must be signed in to change notification settings - Fork 0
/
LPStaking.sol
128 lines (111 loc) · 5.14 KB
/
LPStaking.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
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
// SPDX-License-Identifier: MIT
pragma solidity 0.8.12;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
contract LPStakingContract is Ownable, ReentrancyGuard {
struct Stake {
address user;
uint amount;
uint unclaimed;
}
Stake[] public stakes;
mapping(address => uint[]) private ownerStakeIds;
uint public totalSupply;
bool public stakingAllowed;
uint public lastUpdate;
uint public rewardPerBlock;
uint public constant MINIMUM_AMOUNT = 500 * 1e18;
address public constant REWARD_TOKEN_ADDRESS = 0x1d0Ac23F03870f768ca005c84cBb6FB82aa884fD; // galeon address
address public constant STAKING_TOKEN_ADDRESS = 0x469E0D351B868cb397967E57a00dc7DE082542A3; // LP token address
IERC20 private constant STAKING_TOKEN = IERC20(STAKING_TOKEN_ADDRESS);
IERC20 private constant REWARD_TOKEN = IERC20(REWARD_TOKEN_ADDRESS);
constructor() {
lastUpdate = block.timestamp;
totalSupply = 0;
stakingAllowed = true;
rewardPerBlock = 0.6808 * 1e18;
}
event Stacked(uint _amount,uint _totalSupply);
event Unstaked(uint _amount);
event Claimed(uint _claimed);
event StakingAllowed(bool _allow);
event Updated(uint _lastupdate);
event AdjustRewardPerBlock(uint _rewardPerBlock);
function allowStaking(bool _allow) external onlyOwner returns (bool allowed) {
emit StakingAllowed(_allow);
return stakingAllowed = _allow;
}
function adjustRewardPerBlock(uint _rewardPerBlock) external onlyOwner returns (uint newRewardPerBlock) {
emit AdjustRewardPerBlock(_rewardPerBlock);
return rewardPerBlock = _rewardPerBlock;
}
function forceUpdatePool() external updatePool nonReentrant returns (bool updated) {
return true;
}
function stake(uint _amount) external updatePool nonReentrant returns (bool staked) {
require(stakingAllowed, "Staking is not enabled");
require(_amount >= MINIMUM_AMOUNT, "Insuficient amount");
require(_amount <= STAKING_TOKEN.balanceOf(msg.sender), "Insuficient balance");
require(STAKING_TOKEN.transferFrom(msg.sender, address(this), _amount), "TransferFrom failed");
stakes.push(Stake(msg.sender, _amount, 0));
ownerStakeIds[msg.sender].push(stakes.length-1);
totalSupply += _amount;
emit Stacked(_amount,totalSupply);
return true;
}
function claim() external updatePool nonReentrant returns(uint amount) {
uint claimed = 0;
uint j;
for(uint i = 0; i < ownerStakeIds[msg.sender].length; i++) {
j = ownerStakeIds[msg.sender][i];
if (stakes[j].unclaimed > 0) {
require(REWARD_TOKEN.balanceOf(address(this)) > stakes[j].unclaimed, "Insuficient contract balance");
require(REWARD_TOKEN.transfer(msg.sender,stakes[j].unclaimed), "Transfer failed");
}
claimed += stakes[j].unclaimed;
stakes[j].unclaimed = 0;
}
emit Claimed(claimed);
return claimed;
}
function unstake() external updatePool nonReentrant returns(uint totalReceived) {
uint stakeId;
uint stakedAmount = 0;
uint unclaimedAmount = 0;
for(uint i = 0; i < ownerStakeIds[msg.sender].length; i++) {
stakeId = ownerStakeIds[msg.sender][i];
stakedAmount += stakes[stakeId].amount;
unclaimedAmount += stakes[stakeId].unclaimed;
require(STAKING_TOKEN.balanceOf(address(this)) > stakes[stakeId].amount, "Insuficient staking contract balance");
require(REWARD_TOKEN.balanceOf(address(this)) > stakes[stakeId].unclaimed, "Insuficient reward contract balance");
require(STAKING_TOKEN.transfer(msg.sender,stakes[stakeId].amount), "Staking transfer failed");
require(REWARD_TOKEN.transfer(msg.sender,stakes[stakeId].unclaimed), "Reward transfer failed");
totalSupply -= stakes[stakeId].amount;
stakes[stakeId] = stakes[stakes.length -1];
for(uint k = 0; k < ownerStakeIds[stakes[stakeId].user].length; k++) {
if (ownerStakeIds[stakes[stakeId].user][k] == stakes.length -1) {
ownerStakeIds[stakes[stakeId].user][k] = stakeId;
}
}
stakes.pop();
ownerStakeIds[msg.sender][i] = ownerStakeIds[msg.sender][ownerStakeIds[msg.sender].length -1];
ownerStakeIds[msg.sender].pop();
}
require(stakedAmount > 0, "Nothing to unstake");
emit Unstaked(stakedAmount);
emit Claimed(unclaimedAmount);
return stakedAmount + unclaimedAmount;
}
function getUserStakesIds(address _user) external view returns (uint[] memory) {
return ownerStakeIds[_user];
}
modifier updatePool() {
for(uint i = 0; i < stakes.length; i++) {
stakes[i].unclaimed += stakes[i].amount * (block.timestamp - lastUpdate) * rewardPerBlock / totalSupply;
}
lastUpdate = block.timestamp;
emit Updated(lastUpdate);
_;
}
}