Skip to content

Commit 2ec78fa

Browse files
Update
1 parent e3e5cda commit 2ec78fa

File tree

4 files changed

+152
-279
lines changed

4 files changed

+152
-279
lines changed

contracts/staking/token/LimitedTokenPool.sol

Lines changed: 10 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,12 @@ contract LimitedTokenPool is Initializable, AccessControl, IOnBlockListener {
1717
address limitsMultiplierToken;
1818
address profitableToken;
1919
address rewardToken;
20-
uint rewardTokenPrice;
21-
uint interest;
22-
uint interestRate;
2320
}
2421

2522
struct LimitsConfig {
23+
uint rewardTokenPrice;
24+
uint interest;
25+
uint interestRate;
2626
uint minDepositValue;
2727
uint minStakeValue;
2828
uint fastUnstakePenalty;
@@ -66,21 +66,11 @@ contract LimitedTokenPool is Initializable, AccessControl, IOnBlockListener {
6666

6767
event Deactivated();
6868
event Activated();
69-
event RewardTokenPriceChanged(uint price);
70-
event InterestChanged(uint interest);
71-
event InterestRateChanged(uint interestRate);
72-
event MinDepositValueChanged(uint minDepositValue);
73-
event MinStakeValueChanged(uint minStakeValue);
74-
event FastUnstakePenaltyChanged(uint penalty);
75-
event UnstakeLockPeriodChanged(uint period);
76-
event StakeLockPeriodChanged(uint period);
77-
event MaxTotalStakeValueChanged(uint poolMaxStakeValue);
78-
event MaxStakePerUserValueChanged(uint maxStakePerUserValue);
79-
event StakeLimitsMultiplierChanged(uint value);
69+
event LimitsConfigChanged(LimitsConfig config);
8070

8171
event Deposited(address indexed user, uint amount);
8272
event Withdrawn(address indexed user, uint amount);
83-
event Staked(address indexed user, uint amount);
73+
event Staked(address indexed user, uint amount, uint timestamp);
8474
event Claim(address indexed user, uint amount);
8575
event Interest(uint amount);
8676
event UnstakeLocked(address indexed user, uint amount, uint unlockTime, uint creationTime);
@@ -103,6 +93,7 @@ contract LimitedTokenPool is Initializable, AccessControl, IOnBlockListener {
10393

10494
function setLimitsConfig(LimitsConfig calldata config) public onlyRole(DEFAULT_ADMIN_ROLE) {
10595
limitsConfig = config;
96+
emit LimitsConfigChanged(config);
10697
}
10798

10899
function activate() public onlyRole(DEFAULT_ADMIN_ROLE) {
@@ -117,61 +108,6 @@ contract LimitedTokenPool is Initializable, AccessControl, IOnBlockListener {
117108
emit Deactivated();
118109
}
119110

120-
// SETTERS FOR PARAMS
121-
122-
function setRewardTokenPrice(uint price) public onlyRole(DEFAULT_ADMIN_ROLE) {
123-
mainConfig.rewardTokenPrice = price;
124-
emit RewardTokenPriceChanged(price);
125-
}
126-
127-
function setInterest(uint _interest, uint _interestRate) public onlyRole(DEFAULT_ADMIN_ROLE) {
128-
mainConfig.interest = _interest;
129-
mainConfig.interestRate = _interestRate;
130-
131-
emit InterestRateChanged(_interestRate);
132-
emit InterestChanged(_interest);
133-
}
134-
135-
function setMinDepositValue(uint value) public onlyRole(DEFAULT_ADMIN_ROLE) {
136-
limitsConfig.minDepositValue = value;
137-
emit MinStakeValueChanged(value);
138-
}
139-
140-
function setMinStakeValue(uint value) public onlyRole(DEFAULT_ADMIN_ROLE) {
141-
limitsConfig.minStakeValue = value;
142-
emit MinDepositValueChanged(value);
143-
}
144-
145-
function setFastUnstakePenalty(uint penalty) public onlyRole(DEFAULT_ADMIN_ROLE) {
146-
limitsConfig.fastUnstakePenalty = penalty;
147-
emit FastUnstakePenaltyChanged(penalty);
148-
}
149-
150-
function setUnstakeLockPeriod(uint period) public onlyRole(DEFAULT_ADMIN_ROLE) {
151-
limitsConfig.unstakeLockPeriod = period;
152-
emit UnstakeLockPeriodChanged(period);
153-
}
154-
155-
function setStakeLockPeriod(uint period) public onlyRole(DEFAULT_ADMIN_ROLE) {
156-
limitsConfig.stakeLockPeriod = period;
157-
emit StakeLockPeriodChanged(period);
158-
}
159-
160-
function setMaxTotalStakeValue(uint value) public onlyRole(DEFAULT_ADMIN_ROLE) {
161-
limitsConfig.maxTotalStakeValue = value;
162-
emit MaxTotalStakeValueChanged(value);
163-
}
164-
165-
function setMaxStakePerUserValue(uint value) public onlyRole(DEFAULT_ADMIN_ROLE) {
166-
limitsConfig.maxStakePerUserValue = value;
167-
emit MaxStakePerUserValueChanged(value);
168-
}
169-
170-
function setStakeLimitsMultiplier(uint value) public onlyRole(DEFAULT_ADMIN_ROLE) {
171-
limitsConfig.stakeLimitsMultiplier = value;
172-
emit StakeLimitsMultiplierChanged(value);
173-
}
174-
175111
// PUBLIC METHODS
176112

177113
function deposit(uint amount) public payable {
@@ -230,7 +166,7 @@ contract LimitedTokenPool is Initializable, AccessControl, IOnBlockListener {
230166
require(stakers[msg.sender].stake <= limitsConfig.maxStakePerUserValue, "Pool: max stake per user exceeded");
231167

232168
_updateRewardsDebt(msg.sender, _calcRewards(stakers[msg.sender].stake));
233-
emit Staked(msg.sender, amount);
169+
emit Staked(msg.sender, amount, block.timestamp);
234170
}
235171

236172
function unstake(uint amount) public {
@@ -339,9 +275,9 @@ contract LimitedTokenPool is Initializable, AccessControl, IOnBlockListener {
339275

340276
// INTERNAL METHODS
341277
function _addInterest() internal {
342-
if (info.lastInterestUpdate + mainConfig.interestRate > block.timestamp) return;
278+
if (info.lastInterestUpdate + limitsConfig.interestRate > block.timestamp) return;
343279
uint timePassed = block.timestamp - info.lastInterestUpdate;
344-
uint newRewards = info.totalStake * mainConfig.interest * timePassed / BILLION / mainConfig.interestRate;
280+
uint newRewards = info.totalStake * limitsConfig.interest * timePassed / BILLION / limitsConfig.interestRate;
345281

346282
info.totalRewards += newRewards;
347283
info.lastInterestUpdate = block.timestamp;
@@ -368,7 +304,7 @@ contract LimitedTokenPool is Initializable, AccessControl, IOnBlockListener {
368304
stakers[user].claimableRewards = 0;
369305

370306
// TODO: Use decimals for reward token price
371-
uint rewardTokenAmount = amount * mainConfig.rewardTokenPrice;
307+
uint rewardTokenAmount = amount * limitsConfig.rewardTokenPrice;
372308
if (mainConfig.rewardToken == address(0)) {
373309
rewardsBank.withdrawAmb(payable(user), amount);
374310
} else {
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// SPDX-License-Identifier: UNLICENSED
2+
pragma solidity ^0.8.0;
3+
4+
import "@openzeppelin/contracts/access/AccessControl.sol";
5+
import "@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol";
6+
import "@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol";
7+
import "./LimitedTokenPool.sol";
8+
import "../../funds/RewardsBank.sol";
9+
import "../../LockKeeper.sol";
10+
11+
contract LimitedTokenPoolsManager is AccessControl {
12+
LockKeeper lockKeeper;
13+
RewardsBank public bank;
14+
UpgradeableBeacon public limitedTokenPoolBeacon;
15+
16+
address[] public pools;
17+
18+
constructor(RewardsBank bank_, LockKeeper lockKeeper_, UpgradeableBeacon doubleSideBeacon_) {
19+
lockKeeper = lockKeeper_;
20+
bank = bank_;
21+
limitedTokenPoolBeacon = doubleSideBeacon_;
22+
_setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
23+
}
24+
25+
event LimitedPoolCreated(address pool);
26+
event LimitedPoolConfigured(address pool, LimitedTokenPool.LimitsConfig params);
27+
event LimitedPoolDeactivated(address pool);
28+
event LimitedPoolActivated(address pool);
29+
30+
// LIMITED POOL METHODS
31+
function createPool(LimitedTokenPool.MainConfig calldata params) public onlyRole(DEFAULT_ADMIN_ROLE) returns (address) {
32+
bytes memory data = abi.encodeWithSignature(
33+
"initialize(address,address,(string,address,address,address))",
34+
bank, lockKeeper, params);
35+
address pool = address(new BeaconProxy(address(limitedTokenPoolBeacon), data));
36+
pools.push(pool);
37+
bank.grantRole(bank.DEFAULT_ADMIN_ROLE(), address(pool));
38+
emit LimitedPoolCreated(pool);
39+
return pool;
40+
}
41+
42+
function configurePool(address _pool, LimitedTokenPool.LimitsConfig calldata params) public onlyRole(DEFAULT_ADMIN_ROLE) {
43+
require(_isPool(_pool),"Pool does not exist");
44+
LimitedTokenPool pool = LimitedTokenPool(_pool);
45+
pool.setLimitsConfig(params);
46+
emit LimitedPoolConfigured(_pool, params);
47+
}
48+
49+
function deactivatePool(address _pool) public onlyRole(DEFAULT_ADMIN_ROLE) {
50+
require(_isPool(_pool),"Pool does not exist");
51+
LimitedTokenPool pool = LimitedTokenPool(_pool);
52+
pool.deactivate();
53+
emit LimitedPoolDeactivated(_pool);
54+
}
55+
56+
function activatePool(address _pool) public onlyRole(DEFAULT_ADMIN_ROLE) {
57+
require(_isPool(_pool),"Pool does not exist");
58+
LimitedTokenPool pool = LimitedTokenPool(_pool);
59+
pool.activate();
60+
emit LimitedPoolActivated(_pool);
61+
}
62+
63+
function _isPool(address pool) internal view returns (bool) {
64+
for (uint i = 0; i < pools.length; i++) {
65+
if (pools[i] == pool) {
66+
return true;
67+
}
68+
}
69+
return false;
70+
}
71+
72+
}
73+

contracts/staking/token/TokenPool.sol

Lines changed: 35 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,13 @@ import "../../LockKeeper.sol";
1010

1111
contract TokenPool is Initializable, AccessControl, IOnBlockListener {
1212

13-
struct Config {
13+
struct MainConfig {
1414
IERC20 token;
1515
string name;
1616
address rewardToken;
17+
}
18+
19+
struct LimitsConfig {
1720
uint rewardTokenPrice; // The coefficient to calculate the reward token amount
1821
uint minStakeValue;
1922
uint fastUnstakePenalty;
@@ -42,7 +45,8 @@ contract TokenPool is Initializable, AccessControl, IOnBlockListener {
4245
RewardsBank rewardsBank;
4346
LockKeeper lockKeeper;
4447

45-
Config public config;
48+
MainConfig public mainConfig; // immutable
49+
LimitsConfig public limitsConfig; // mutable
4650
Info public info;
4751

4852
mapping(address => Staker) public stakers;
@@ -51,21 +55,19 @@ contract TokenPool is Initializable, AccessControl, IOnBlockListener {
5155

5256
event Deactivated();
5357
event Activated();
54-
event MinStakeValueChanged(uint minStakeValue);
55-
event InterestRateChanged(uint interest, uint interestRate);
56-
event LockPeriodChanged(uint period);
57-
event RewardTokenPriceChanged(uint price);
58-
event FastUnstakePenaltyChanged(uint penalty);
58+
event LimitsConfigChanged(LimitsConfig limitsConfig);
5959
event StakeChanged(address indexed user, uint amount);
6060
event Claim(address indexed user, uint amount);
6161
event Interest(uint amount);
6262
event UnstakeLocked(address indexed user, uint amount, uint unlockTime, uint creationTime);
6363
event UnstakeFast(address indexed user, uint amount, uint penalty);
6464

65-
function initialize(RewardsBank bank_, LockKeeper keeper_, Config calldata config_) public initializer {
65+
function initialize(RewardsBank bank_, LockKeeper keeper_, MainConfig calldata mainConfig_, LimitsConfig calldata limitsConfig_) public initializer {
66+
//TODO: Should validate input params
6667
rewardsBank = bank_;
6768
lockKeeper = keeper_;
68-
config = config_;
69+
mainConfig = mainConfig_;
70+
limitsConfig = limitsConfig_;
6971

7072
info.lastInterestUpdate = block.timestamp;
7173

@@ -76,6 +78,12 @@ contract TokenPool is Initializable, AccessControl, IOnBlockListener {
7678

7779
// OWNER METHODS
7880

81+
function setLimitsConfig(LimitsConfig calldata _limitsConfig) public onlyRole(DEFAULT_ADMIN_ROLE) {
82+
//TODO: Validate input params
83+
limitsConfig = _limitsConfig;
84+
emit LimitsConfigChanged(_limitsConfig);
85+
}
86+
7987
function activate() public onlyRole(DEFAULT_ADMIN_ROLE) {
8088
require(!active, "Pool is already active");
8189
active = true;
@@ -88,39 +96,12 @@ contract TokenPool is Initializable, AccessControl, IOnBlockListener {
8896
emit Deactivated();
8997
}
9098

91-
function setMinStakeValue(uint value) public onlyRole(DEFAULT_ADMIN_ROLE) {
92-
config.minStakeValue = value;
93-
emit MinStakeValueChanged(value);
94-
}
95-
96-
function setInterest(uint _interest, uint _interestRate) public onlyRole(DEFAULT_ADMIN_ROLE) {
97-
_addInterest();
98-
config.interest = _interest;
99-
config.interestRate = _interestRate;
100-
emit InterestRateChanged(config.interest, config.interestRate);
101-
}
102-
103-
function setLockPeriod(uint period) public onlyRole(DEFAULT_ADMIN_ROLE) {
104-
config.lockPeriod = period;
105-
emit LockPeriodChanged(period);
106-
}
107-
108-
function setRewardTokenPrice(uint price) public onlyRole(DEFAULT_ADMIN_ROLE) {
109-
config.rewardTokenPrice = price;
110-
emit RewardTokenPriceChanged(price);
111-
}
112-
113-
function setFastUnstakePenalty(uint penalty) public onlyRole(DEFAULT_ADMIN_ROLE) {
114-
config.fastUnstakePenalty = penalty;
115-
emit FastUnstakePenaltyChanged(penalty);
116-
}
117-
11899
// PUBLIC METHODS
119100

120101
function stake(uint amount) public {
121102
require(active, "Pool is not active");
122-
require(amount >= config.minStakeValue, "Pool: stake value is too low");
123-
require(config.token.transferFrom(msg.sender, address(this), amount), "Transfer failed");
103+
require(amount >= limitsConfig.minStakeValue, "Pool: stake value is too low");
104+
require(mainConfig.token.transferFrom(msg.sender, address(this), amount), "Transfer failed");
124105

125106
_stake(msg.sender, amount);
126107

@@ -137,17 +118,17 @@ contract TokenPool is Initializable, AccessControl, IOnBlockListener {
137118
if (lockKeeper.getLock(stakers[msg.sender].lockedWithdrawal).totalClaims > 0) // prev lock exists
138119
canceledAmount = lockKeeper.cancelLock(stakers[msg.sender].lockedWithdrawal);
139120

140-
config.token.approve(address(lockKeeper), amount + canceledAmount);
121+
mainConfig.token.approve(address(lockKeeper), amount + canceledAmount);
141122

142123
// lock funds
143124
stakers[msg.sender].lockedWithdrawal = lockKeeper.lockSingle(
144-
msg.sender, address(config.token), uint64(block.timestamp + config.lockPeriod), amount + canceledAmount,
145-
string(abi.encodePacked("TokenStaking unstake: ", _addressToString(address(config.token))))
125+
msg.sender, address(mainConfig.token), uint64(block.timestamp + limitsConfig.lockPeriod), amount + canceledAmount,
126+
string(abi.encodePacked("TokenStaking unstake: ", _addressToString(address(mainConfig.token))))
146127
);
147128

148129
_claimRewards(msg.sender);
149130

150-
emit UnstakeLocked(msg.sender, amount + canceledAmount, block.timestamp + config.lockPeriod, block.timestamp);
131+
emit UnstakeLocked(msg.sender, amount + canceledAmount, block.timestamp + limitsConfig.lockPeriod, block.timestamp);
151132
emit StakeChanged(msg.sender, stakers[msg.sender].stake);
152133
}
153134

@@ -156,8 +137,8 @@ contract TokenPool is Initializable, AccessControl, IOnBlockListener {
156137

157138
_unstake(msg.sender, amount);
158139

159-
uint penalty = amount * config.fastUnstakePenalty / BILLION;
160-
SafeERC20.safeTransfer(config.token, msg.sender, amount - penalty);
140+
uint penalty = amount * limitsConfig.fastUnstakePenalty / BILLION;
141+
SafeERC20.safeTransfer(mainConfig.token, msg.sender, amount - penalty);
161142

162143
_claimRewards(msg.sender);
163144

@@ -176,8 +157,12 @@ contract TokenPool is Initializable, AccessControl, IOnBlockListener {
176157

177158
// VIEW METHODS
178159

179-
function getConfig() public view returns (Config memory) {
180-
return config;
160+
function getMainConfig() public view returns (MainConfig memory) {
161+
return mainConfig;
162+
}
163+
164+
function getLimitsConfig() public view returns (LimitsConfig memory) {
165+
return limitsConfig;
181166
}
182167

183168
function getInfo() public view returns (Info memory) {
@@ -208,9 +193,9 @@ contract TokenPool is Initializable, AccessControl, IOnBlockListener {
208193
}
209194

210195
function _addInterest() internal {
211-
if (info.lastInterestUpdate + config.interestRate > block.timestamp) return;
196+
if (info.lastInterestUpdate + limitsConfig.interestRate > block.timestamp) return;
212197
uint timePassed = block.timestamp - info.lastInterestUpdate;
213-
uint newRewards = info.totalStake * config.interest * timePassed / BILLION / config.interestRate;
198+
uint newRewards = info.totalStake * limitsConfig.interest * timePassed / BILLION / limitsConfig.interestRate;
214199

215200
info.totalRewards += newRewards;
216201
info.lastInterestUpdate = block.timestamp;
@@ -251,8 +236,8 @@ contract TokenPool is Initializable, AccessControl, IOnBlockListener {
251236

252237
stakers[user].claimableRewards = 0;
253238

254-
uint rewardTokenAmount = amount * config.rewardTokenPrice;
255-
rewardsBank.withdrawErc20(config.rewardToken, payable(user), rewardTokenAmount);
239+
uint rewardTokenAmount = amount * limitsConfig.rewardTokenPrice;
240+
rewardsBank.withdrawErc20(mainConfig.rewardToken, payable(user), rewardTokenAmount);
256241
emit Claim(user, rewardTokenAmount);
257242
}
258243

0 commit comments

Comments
 (0)