-
Notifications
You must be signed in to change notification settings - Fork 4
/
sbBTCPool.sol
144 lines (116 loc) Β· 5 KB
/
sbBTCPool.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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
import "./interfaces/IBarn.sol";
import "./interfaces/ISwapContract.sol";
contract sbBTCPool is Ownable {
using SafeMath for uint256;
uint256 constant divisor = 10 ** 27;
uint256 public balanceBefore;
uint256 public currentMultiplier;
uint256 public totalNodeStaked;
mapping(address => uint256) public userMultiplier;
mapping(address => uint256) public owed;
IBarn public barn;
IERC20 public rewardToken;
ISwapContract public swapContract;
event Claim(address indexed user, uint256 amount);
// setBarn sets the address of the BarnBridge Barn into the state variable
function setBarnAndSwap(address _barn, address _swap) public {
require(_barn != address(0), "barn address must not be 0x0");
require(_swap != address(0), "swap contract address must not be 0x0");
require(msg.sender == owner(), "!owner");
swapContract = ISwapContract(_swap);
rewardToken = IERC20(swapContract.lpToken());
barn = IBarn(_barn);
}
// update all node rewards.
function updateAll(uint256 _timestamp) public onlyOwner {
updateStakes(_timestamp);
// Getting rewards
ackFunds();
// Update all distribution.
address[] memory nodes = swapContract.getActiveNodes();
for (uint256 i = 0; i < nodes.length; i++) {
_updateOwed(nodes[i], _timestamp);
}
}
// check all active nodes to calculate current stakes.
function updateStakes(uint256 _timestamp) internal {
address[] memory nodes = swapContract.getActiveNodes();
uint256 newTotalNodeStaked;
for (uint256 i = 0; i < nodes.length; i++) {
newTotalNodeStaked = newTotalNodeStaked.add(
barn.balanceAtTs(nodes[i], _timestamp)
);
if (userMultiplier[nodes[i]] == 0) {
userMultiplier[nodes[i]] = currentMultiplier;
}
}
// only change when stakers had actions.
if (totalNodeStaked != newTotalNodeStaked) {
totalNodeStaked = newTotalNodeStaked;
}
}
function resetUnstakedNode(address _node) public {
require(!swapContract.isNodeStake(_node), "node is staker");
userMultiplier[_node] = 0;
}
// claim calculates the currently owed reward and transfers the funds to the user
function claim() public returns (uint256) {
require(swapContract.isNodeStake(msg.sender), "caller is not node");
updateStakes(block.timestamp);
ackFunds();
_updateOwed(msg.sender, block.timestamp);
uint256 amount = owed[msg.sender];
require(amount > 0, "nothing to claim");
owed[msg.sender] = 0;
rewardToken.transfer(msg.sender, amount);
// acknowledge the amount that was transferred to the user
ackFunds();
emit Claim(msg.sender, amount);
return amount;
}
// ackFunds checks the difference between the last known balance of `token` and the current one
// if it goes up, the multiplier is re-calculated
// if it goes down, it only updates the known balance
function ackFunds() public {
uint256 balanceNow = rewardToken.balanceOf(address(this));
if (balanceNow == 0 || balanceNow <= balanceBefore) {
balanceBefore = balanceNow;
return;
}
if (totalNodeStaked == 0) {
return;
}
uint256 diff = balanceNow.sub(balanceBefore);
uint256 multiplier = currentMultiplier.add(
diff.mul(divisor).div(totalNodeStaked)
);
balanceBefore = balanceNow;
currentMultiplier = multiplier;
}
function emergencyWithdraw() public {
require(msg.sender == owner(), "!owner");
rewardToken.transfer(msg.sender, rewardToken.balanceOf(address(this)));
swapContract = ISwapContract(address(0));
}
// _updateOwed calculates and updates the total amount that is owed to an user and updates the user's multiplier
// to the current value
// it automatically attempts to pull the token from the source and acknowledge the funds
function _updateOwed(address user, uint256 timestamp) internal {
uint256 reward = _userPendingReward(user, timestamp);
owed[user] = owed[user].add(reward);
userMultiplier[user] = currentMultiplier;
}
// _userPendingReward calculates the reward that should be based on the current multiplier / anything that's not included in the `owed[user]` value
// it does not represent the entire reward that's due to the user unless added on top of `owed[user]`
function _userPendingReward(
address user,
uint256 timestamp
) internal view returns (uint256) {
uint256 multiplier = currentMultiplier.sub(userMultiplier[user]);
return barn.balanceAtTs(user, timestamp).mul(multiplier).div(divisor);
}
}