Skip to content

Commit

Permalink
Merge pull request #20 from ambrosus/staking-part2
Browse files Browse the repository at this point in the history
Staking part2
  • Loading branch information
SvineruS authored Oct 23, 2023
2 parents 7dfbb69 + d394b05 commit 4fa2de2
Show file tree
Hide file tree
Showing 22 changed files with 991 additions and 274 deletions.
56 changes: 29 additions & 27 deletions contracts/consensus/ValidatorSet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,9 @@ contract ValidatorSet is UUPSUpgradeable, OnBlockNotifier, AccessControlEnumerab
uint public topStakesCount; // max validators count

uint public baseReward; // base reward for validators; updated by reward oracle

uint64[5] internal _baseRewardSettings; // settings for base reward oracle: [0] - isEnabled
// [1] - min %, [2] - max % (bips),
// [3] - min reward, [4] - max reward (bips of amb)

// NOTE: nodeAddresses here
address[] internal finalizedValidators; // consensus validators
Expand All @@ -55,7 +57,7 @@ contract ValidatorSet is UUPSUpgradeable, OnBlockNotifier, AccessControlEnumerab
uint internal _latestRewardBlock; // block when reward was called last time (to prevent call more then once)
uint internal _latestRemoveFromTopBlock; // block when node was removed from top list last time (to prevent call more then once per finalization)

uint256[19] private __gap;
uint256[20] private __gap;

event InitiateChange(bytes32 indexed parentHash, address[] newSet); // emitted when topStakes changes and need to be finalized
event ValidatorSetFinalized(address[] newSet); // emitted when topStakes finalized to finalizedValidators
Expand All @@ -71,17 +73,12 @@ contract ValidatorSet is UUPSUpgradeable, OnBlockNotifier, AccessControlEnumerab
event TopListNodeRemoved(address indexed nodeAddress);

event Report(address indexed nodeAddress, uint malisciousType);
event Reward(
address indexed manager,
address indexed nodeAddress,
address indexed rewardReceiver,
address nodeOwner,
address tokenAddress,
uint256 amount
);
event Reward(address indexed manager, address indexed nodeAddress, address indexed rewardReceiver,
address nodeOwner, address tokenAddress, uint256 amount);

event RewardError(address stakingManager, string errorText);


function initialize(
address _rewardOracle,
uint _baseReward,
Expand All @@ -90,6 +87,8 @@ contract ValidatorSet is UUPSUpgradeable, OnBlockNotifier, AccessControlEnumerab
baseReward = _baseReward;
topStakesCount = _topStakesCount;

_baseRewardSettings = [1, 16.6 * 10000, 100 * 10000, 14 * 10000, 60.8 * 10000]; // default settings: enabled, 16.6% = 14 amb, 100% = 60.8 amb

_setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
_setupRole(REWARD_ORACLE_ROLE, _rewardOracle);
}
Expand Down Expand Up @@ -132,7 +131,6 @@ contract ValidatorSet is UUPSUpgradeable, OnBlockNotifier, AccessControlEnumerab
return result;
}


// STAKING POOL METHODS

function newStake(address nodeAddress, uint amount, bool isAlwaysTop) external onlyRole(STAKING_MANAGER_ROLE) {
Expand Down Expand Up @@ -169,7 +167,7 @@ contract ValidatorSet is UUPSUpgradeable, OnBlockNotifier, AccessControlEnumerab
totalStakeAmount -= amount;
stake.amount -= amount;

emit StakeChanged(nodeAddress, msg.sender, -int(amount));
emit StakeChanged(nodeAddress, msg.sender, - int(amount));

if (stake.amount == 0) {
_removeStake(nodeAddress, isInTopStakes);
Expand All @@ -186,15 +184,13 @@ contract ValidatorSet is UUPSUpgradeable, OnBlockNotifier, AccessControlEnumerab
emit Reward(msg.sender, nodeAddress, rewardReceiver, nodeOwner, tokenAddress, amount);
}



// ADMIN METHODS


function changeTopStakesCount(uint newTopStakesCount) public onlyRole(DEFAULT_ADMIN_ROLE) {
require(newTopStakesCount > 0, "newTopStakesCount must be > 0");
if (newTopStakesCount < topStakesCount)
require(newTopStakesCount + (topStakesCount / 8) >= topStakesCount, "decrease of more than 12.5% is not allowed");
if (newTopStakesCount < queuedStakes.length)
require(newTopStakesCount + (queuedStakes.length / 8) >= queuedStakes.length, "decrease of more than 12.5% is not allowed");

topStakesCount = newTopStakesCount;
}
Expand All @@ -207,9 +203,25 @@ contract ValidatorSet is UUPSUpgradeable, OnBlockNotifier, AccessControlEnumerab
_removeListener(listener);
}

function setRewardSettings(uint64[5] memory newSettings) public onlyRole(DEFAULT_ADMIN_ROLE) {
_baseRewardSettings = newSettings;
}


function _authorizeUpgrade(address) internal override onlyRole(DEFAULT_ADMIN_ROLE) {}


// ORACLE METHODS

function getRewardSettings() public view returns (uint64[5] memory){
return _baseRewardSettings;
}

function setReward(uint _baseReward) public onlyRole(REWARD_ORACLE_ROLE) {
baseReward = _baseReward;
}


// SUPERUSER (NODE) METHODS


Expand All @@ -231,16 +243,6 @@ contract ValidatorSet is UUPSUpgradeable, OnBlockNotifier, AccessControlEnumerab
_tryMoveFromQueue();
}


// ORACLE METHODS

function setReward(uint _baseReward) public onlyRole(REWARD_ORACLE_ROLE) {
baseReward = _baseReward;
}




// PRIVATE METHODS

function _topValidatorsChanged() internal {
Expand All @@ -264,7 +266,6 @@ contract ValidatorSet is UUPSUpgradeable, OnBlockNotifier, AccessControlEnumerab
}
}


// HELPERS


Expand Down Expand Up @@ -334,6 +335,7 @@ contract ValidatorSet is UUPSUpgradeable, OnBlockNotifier, AccessControlEnumerab
}

}

function _tryMoveToQueue() internal {
if (topStakes.length <= topStakesCount) return;
if (block.number < _latestRemoveFromTopBlock + finalizedValidators.length) return; // no more than once per round
Expand Down
27 changes: 27 additions & 0 deletions contracts/finance/Treasury.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

import "./Finance.sol";


contract Treasury is Finance {

uint public fee; // in base points (1/10000)

constructor(address owner, uint _fee) Finance(owner) {
require(_fee <= 10000, "fee is too big");
fee = _fee;
}

function setFee(uint _fee) public onlyOwner {
require(_fee <= 10000, "fee is too big");
fee = _fee;
}

function calcFee(uint amount) public view returns (uint) {
return amount * fee / 10000;
}


// receive and withdraw functions are in Finance contract
}
10 changes: 9 additions & 1 deletion contracts/staking/BaseNodes_Manager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,23 @@ import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol"
import "./IStakeManager.sol";
import "../consensus/IValidatorSet.sol";
import "../funds/RewardsBank.sol";
import "../finance/Treasury.sol";

// Manager, that can add and remove nodes from validator set TOP list (controlled by multisig)

contract BaseNodes_Manager is UUPSUpgradeable, IStakeManager, AccessControlUpgradeable {
IValidatorSet public validatorSet; // contract that manages validator set
RewardsBank public rewardsBank;
Treasury public treasury;

uint256[20] private __gap;

function initialize(
IValidatorSet _validatorSet, RewardsBank _rewardsBank
IValidatorSet _validatorSet, RewardsBank _rewardsBank, Treasury _treasury
) public initializer {
validatorSet = _validatorSet;
rewardsBank = _rewardsBank;
treasury = _treasury;

_setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
}
Expand All @@ -44,6 +47,11 @@ contract BaseNodes_Manager is UUPSUpgradeable, IStakeManager, AccessControlUpgra

function reward(address nodeAddress, uint amount) external {
require(msg.sender == address(validatorSet), "Only validatorSet can call reward()");

uint treasuryAmount = treasury.calcFee(amount);
rewardsBank.withdrawAmb(payable(address(treasury)), treasuryAmount);
amount -= treasuryAmount;

rewardsBank.withdrawAmb(payable(nodeAddress), amount);
validatorSet.emitReward(nodeAddress, nodeAddress, nodeAddress, address(0), amount);
}
Expand Down
17 changes: 9 additions & 8 deletions contracts/staking/ServerNodes_Manager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import "../consensus/IValidatorSet.sol";
import {IOnBlockListener} from "../consensus/OnBlockNotifier.sol";
import "../LockKeeper.sol";
import "../funds/RewardsBank.sol";
import "../finance/Treasury.sol";

// Manager, that allows users to register their nodes in validator set

Expand All @@ -23,9 +24,9 @@ contract ServerNodes_Manager is UUPSUpgradeable, IStakeManager, IOnBlockListener

IValidatorSet public validatorSet; // contract that manages validator set
LockKeeper public lockKeeper; // contract that locks stakes

RewardsBank public rewardsBank;
address public airBond;
Treasury public treasury;

uint public onboardingDelay; // time that new node will be in queueStakes even if it has enough stake (only affects nodes without FLAG_ALWAYS_IN_TOP)
uint public unstakeLockTime; // time that funds will be locked after unstake
Expand All @@ -43,13 +44,14 @@ contract ServerNodes_Manager is UUPSUpgradeable, IStakeManager, IOnBlockListener
uint256[20] private __gap;

function initialize(
IValidatorSet _validatorSet, LockKeeper _lockKeeper, RewardsBank _rewardsBank, address _airBond,
IValidatorSet _validatorSet, LockKeeper _lockKeeper, RewardsBank _rewardsBank, address _airBond, Treasury _treasury,
uint _onboardingDelay, uint _unstakeLockTime, uint _minStakeAmount
) public initializer {
validatorSet = _validatorSet;
lockKeeper = _lockKeeper;
rewardsBank = _rewardsBank;
airBond = _airBond;
treasury = _treasury;

onboardingDelay = _onboardingDelay;
unstakeLockTime = _unstakeLockTime;
Expand All @@ -58,7 +60,6 @@ contract ServerNodes_Manager is UUPSUpgradeable, IStakeManager, IOnBlockListener
_setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
}


// USER METHODS

function newStake(address nodeAddress, address rewardAddress) payable public whenNotPaused {
Expand Down Expand Up @@ -98,7 +99,6 @@ contract ServerNodes_Manager is UUPSUpgradeable, IStakeManager, IOnBlockListener
if (validatorSet.getNodeStake(nodeAddress) > 0) // only if node already validator
validatorSet.unstake(nodeAddress, amount);


// cancel previous lock (if exists). canceledAmount will be added to new lock
uint canceledAmount;
if (lockKeeper.getLock(lockedWithdraws[nodeAddress]).totalClaims > 0) // prev lock exists
Expand All @@ -111,7 +111,7 @@ contract ServerNodes_Manager is UUPSUpgradeable, IStakeManager, IOnBlockListener
string(abi.encodePacked("ServerNodes unstake: ", nodeAddress))
);

emit StakeChanged(nodeAddress, msg.sender, -int(amount));
emit StakeChanged(nodeAddress, msg.sender, - int(amount));
}

// unlock latest withdraw to stake
Expand Down Expand Up @@ -148,14 +148,17 @@ contract ServerNodes_Manager is UUPSUpgradeable, IStakeManager, IOnBlockListener
return result;
}


// VALIDATOR SET METHODS

function reward(address nodeAddress, uint amount) external {
require(msg.sender == address(validatorSet), "Only validatorSet can call reward()");
Stake memory stakeStruct = stakes[nodeAddress];
require(stakeStruct.stake > 0, "nodeAddress not in stakes");

uint treasuryAmount = treasury.calcFee(amount);
rewardsBank.withdrawAmb(payable(address(treasury)), treasuryAmount);
amount -= treasuryAmount;

uint bondsReward = amount * _getBondsPercent(stakeStruct.timestampStake) / 100;
uint nativeReward = amount - bondsReward;

Expand Down Expand Up @@ -185,7 +188,6 @@ contract ServerNodes_Manager is UUPSUpgradeable, IStakeManager, IOnBlockListener
// todo
}


// MULTISIG METHODS

function changeMinStakeAmount(uint newMinStakeAmount) public onlyRole(DEFAULT_ADMIN_ROLE) {
Expand Down Expand Up @@ -257,7 +259,6 @@ contract ServerNodes_Manager is UUPSUpgradeable, IStakeManager, IOnBlockListener
}
}


// move nodes from onboardingWaitingList to topStakes
function _checkOnboardingWaitingList() internal {
uint minTimestampForOnboarding = block.timestamp - onboardingDelay;
Expand Down
Loading

0 comments on commit 4fa2de2

Please sign in to comment.