Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ node_modules
package-lock.json
package.json
typechain
tsconfig.json
2 changes: 2 additions & 0 deletions .solhintignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
contracts/libraries/*.sol
contracts/tokens/*.sol
contracts/Guardian.sol
contracts/Token.sol
53 changes: 7 additions & 46 deletions abi/Ask.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,52 +72,6 @@
"stateMutability": "pure",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint72",
"name": "identityId",
"type": "uint72"
},
{
"internalType": "uint96",
"name": "oldAsk",
"type": "uint96"
},
{
"internalType": "uint96",
"name": "newAsk",
"type": "uint96"
}
],
"name": "onAskChanged",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint72",
"name": "identityId",
"type": "uint72"
},
{
"internalType": "uint96",
"name": "oldStake",
"type": "uint96"
},
{
"internalType": "uint96",
"name": "newStake",
"type": "uint96"
}
],
"name": "onStakeChanged",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "parametersStorage",
Expand All @@ -144,6 +98,13 @@
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "recalculateActiveSet",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
Expand Down
123 changes: 29 additions & 94 deletions contracts/Ask.sol
Original file line number Diff line number Diff line change
Expand Up @@ -41,114 +41,49 @@ contract Ask is INamed, IVersioned, ContractStatus, IInitializable {
return _VERSION;
}

function onStakeChanged(uint72 identityId, uint96 oldStake, uint96 newStake) external onlyContracts {
ParametersStorage params = parametersStorage;
function recalculateActiveSet() external onlyContracts {
AskStorage ass = askStorage;

uint96 nodeAsk = profileStorage.getAsk(identityId);

uint96 minimumStake = params.minimumStake();
uint96 maximumStake = params.maximumStake();

uint96 oldStakeAdj = oldStake <= maximumStake ? oldStake : maximumStake;
uint96 newStakeAdj = newStake <= maximumStake ? newStake : maximumStake;

uint256 oldWeightedAsk = uint256(nodeAsk) * oldStakeAdj;
uint256 newWeightedAsk = uint256(nodeAsk) * newStakeAdj;

bool wasInShardingTable = oldStake >= minimumStake;

if (wasInShardingTable && newStake < minimumStake) {
ass.decreaseWeightedActiveAskSum(oldWeightedAsk);
ass.setPrevTotalActiveStake(ass.totalActiveStake());
ass.decreaseTotalActiveStake(oldStake);
return;
}

if (oldStake >= maximumStake && newStake >= maximumStake) {
return;
}

uint256 weightedActiveAskSum = ass.weightedActiveAskSum();
if (weightedActiveAskSum == 0) {
ass.setPrevWeightedActiveAskSum(newWeightedAsk);
ass.setPrevTotalActiveStake(newStakeAdj);
ass.setTotalActiveStake(newStakeAdj);
ass.setWeightedActiveAskSum(newWeightedAsk);
return;
}

ass.setPrevTotalActiveStake(newStakeAdj);
ass.setPrevWeightedActiveAskSum(weightedActiveAskSum);
if (wasInShardingTable) {
ass.decreaseTotalActiveStake(oldStake);
ass.decreaseWeightedActiveAskSum(oldWeightedAsk);
}
ass.increaseTotalActiveStake(newStake);
ass.increaseWeightedActiveAskSum(newWeightedAsk);
}

function onAskChanged(uint72 identityId, uint96 oldAsk, uint96 newAsk) external onlyContracts {
ShardingTableStorage sts = shardingTableStorage;
StakingStorage ss = stakingStorage;
ParametersStorage params = parametersStorage;
ShardingTableStorage sts = shardingTableStorage;
ProfileStorage ps = profileStorage;
AskStorage ass = askStorage;

uint96 currentStake = stakingStorage.getNodeStake(identityId);

if (currentStake < params.minimumStake()) {
return;
}
ass.setPrevWeightedActiveAskSum(ass.weightedActiveAskSum());
ass.setPrevTotalActiveStake(ass.totalActiveStake());

uint96 minimumStake = params.minimumStake();
uint96 maximumStake = params.maximumStake();
uint96 stake = currentStake <= maximumStake ? currentStake : maximumStake;
uint256 newWeightedAsk = uint256(stake) * newAsk;

uint256 weightedActiveAskSum = ass.weightedActiveAskSum();
if (weightedActiveAskSum == 0) {
ass.setWeightedActiveAskSum(newWeightedAsk);
ass.setPrevWeightedActiveAskSum(newWeightedAsk);
ass.setPrevTotalActiveStake(stake);
ass.setTotalActiveStake(stake);
return;
}

(uint256 oldLowerBound, uint256 oldUpperBound) = ass.getAskBounds();

bool isActive = false;
if (uint256(newAsk) * 1e18 <= oldUpperBound && uint256(newAsk) * 1e18 >= oldLowerBound) {
ass.setPrevWeightedActiveAskSum(weightedActiveAskSum);
isActive = true;
} else if (uint256(oldAsk) * 1e18 <= oldUpperBound && uint256(oldAsk) * 1e18 >= oldLowerBound) {
ass.setPrevTotalActiveStake(stake);
ass.setPrevWeightedActiveAskSum(weightedActiveAskSum);
ass.decreaseTotalActiveStake(stake);
ass.decreaseWeightedActiveAskSum(uint256(oldAsk) * stake);
}

if (isActive) {
ass.setPrevTotalActiveStake(ass.totalActiveStake());
uint256 askLowerBound;
uint256 askUpperBound;

uint256 newWeightedActiveAskSum = 0;
uint96 newTotalActiveStake = 0;
if (ass.prevTotalActiveStake() > 0 && ass.prevWeightedActiveAskSum() > 0) {
(askLowerBound, askUpperBound) = ass.getAskBounds();
} else {
(askLowerBound, askUpperBound) = (0, type(uint256).max);
}

(uint256 newLowerBound, uint256 newUpperBound) = ass.getAskBounds();
uint256 newWeightedActiveAskSum;
uint96 newTotalActiveStake;

uint72 nodesCount = shardingTableStorage.nodesCount();
for (uint72 i; i < nodesCount; i++) {
uint72 nextIdentityId = sts.indexToIdentityId(i);
uint256 nodeAsk = uint256(ps.getAsk(nextIdentityId));
uint72 count = sts.nodesCount();
for (uint72 i; i < count; i++) {
uint72 nodeIdentityId = sts.indexToIdentityId(i);
uint96 stake = ss.getNodeStake(nodeIdentityId);

if (nodeAsk * 1e18 <= newUpperBound && nodeAsk * 1e18 >= newLowerBound) {
uint96 nodeStake = ss.getNodeStake(nextIdentityId);
newWeightedActiveAskSum += (nodeAsk * nodeStake);
newTotalActiveStake += nodeStake;
}
if (stake < minimumStake) {
continue;
}

ass.setWeightedActiveAskSum(newWeightedActiveAskSum);
ass.setTotalActiveStake(newTotalActiveStake);
stake = stake > maximumStake ? maximumStake : stake;
uint256 nodeAskScaled = uint256(ps.getAsk(nodeIdentityId)) * 1e18;
if (nodeAskScaled >= askLowerBound && nodeAskScaled <= askUpperBound) {
newWeightedActiveAskSum += (nodeAskScaled / 1e18) * stake;
newTotalActiveStake += stake;
}
}

ass.setWeightedActiveAskSum(newWeightedActiveAskSum);
ass.setTotalActiveStake(newTotalActiveStake);
}
}
3 changes: 1 addition & 2 deletions contracts/Profile.sol
Original file line number Diff line number Diff line change
Expand Up @@ -119,10 +119,9 @@ contract Profile is INamed, IVersioned, ContractStatus, IInitializable {
revert ProfileLib.AskUpdateOnCooldown(identityId, ps.askUpdateCooldown(identityId));
}

uint96 oldAsk = ps.getAsk(identityId);
ps.setAsk(identityId, ask);
ps.setAskUpdateCooldown(identityId, block.timestamp + parametersStorage.nodeAskUpdateDelay());
askContract.onAskChanged(identityId, oldAsk, ask);
askContract.recalculateActiveSet();
}

function updateOperatorFee(uint72 identityId, uint16 newOperatorFee) external onlyAdmin(identityId) {
Expand Down
14 changes: 7 additions & 7 deletions contracts/Staking.sol
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ contract Staking is INamed, IVersioned, ContractStatus, IInitializable {

_addNodeToShardingTable(identityId, totalNodeStakeAfter);

askContract.onStakeChanged(identityId, totalNodeStakeBefore, totalNodeStakeAfter);
askContract.recalculateActiveSet();

token.transferFrom(msg.sender, address(ss), addedStake);
}
Expand Down Expand Up @@ -155,7 +155,7 @@ contract Staking is INamed, IVersioned, ContractStatus, IInitializable {

_removeNodeFromShardingTable(fromIdentityId, totalFromNodeStakeAfter);

ask.onStakeChanged(fromIdentityId, totalFromNodeStakeBefore, totalFromNodeStakeAfter);
ask.recalculateActiveSet();

if (stakeAmount > delegatorStakeIndexed) {
ss.increaseDelegatorStakeBase(toIdentityId, delegatorKey, (delegatorStakeBase - newDelegatorStakeBase));
Expand All @@ -169,7 +169,7 @@ contract Staking is INamed, IVersioned, ContractStatus, IInitializable {

_addNodeToShardingTable(toIdentityId, totalToNodeStakeAfter);

ask.onStakeChanged(toIdentityId, totalToNodeStakeBefore, totalToNodeStakeAfter);
ask.recalculateActiveSet();
}

function requestWithdrawal(uint72 identityId, uint96 removedStake) external profileExists(identityId) {
Expand Down Expand Up @@ -210,7 +210,7 @@ contract Staking is INamed, IVersioned, ContractStatus, IInitializable {

_removeNodeFromShardingTable(identityId, totalNodeStakeAfter);

askContract.onStakeChanged(identityId, totalNodeStakeBefore, totalNodeStakeAfter);
askContract.recalculateActiveSet();

if (totalNodeStakeAfter >= parametersStorage.maximumStake()) {
ss.addDelegatorCumulativePaidOutRewards(
Expand Down Expand Up @@ -312,7 +312,7 @@ contract Staking is INamed, IVersioned, ContractStatus, IInitializable {

_addNodeToShardingTable(identityId, totalNodeStakeAfter);

askContract.onStakeChanged(identityId, totalNodeStakeBefore, totalNodeStakeAfter);
askContract.recalculateActiveSet();
}

function distributeRewards(
Expand Down Expand Up @@ -353,7 +353,7 @@ contract Staking is INamed, IVersioned, ContractStatus, IInitializable {

_addNodeToShardingTable(identityId, totalNodeStakeAfter);

askContract.onStakeChanged(identityId, totalNodeStakeBefore, totalNodeStakeAfter);
askContract.recalculateActiveSet();
}

function restakeOperatorFee(uint72 identityId, uint96 addedStake) external onlyAdmin(identityId) {
Expand Down Expand Up @@ -390,7 +390,7 @@ contract Staking is INamed, IVersioned, ContractStatus, IInitializable {

_addNodeToShardingTable(identityId, totalNodeStakeAfter);

askContract.onStakeChanged(identityId, totalNodeStakeBefore, totalNodeStakeAfter);
askContract.recalculateActiveSet();
}

function requestOperatorFeeWithdrawal(uint72 identityId, uint96 withdrawalAmount) external onlyAdmin(identityId) {
Expand Down
75 changes: 46 additions & 29 deletions contracts/paranets/ParanetNeuroIncentivesPool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -224,21 +224,30 @@ contract ParanetNeuroIncentivesPool is INamed, IVersioned {
return voters.length;
}

function removeVoters(uint256 limit) external onlyVotersRegistrar {
require(voters.length >= limit, "Limit exceeds the num of voters");
function removeVoters(uint256 limit) external onlyVotersRegistrar {
require(voters.length >= limit, "Limit exceeds the num of voters");

for (uint256 i; i < limit; ) {
cumulativeVotersWeight -= uint16(voters[voters.length - 1 - i].weight);
for (uint256 i; i < limit; ) {
uint256 lastIndex = voters.length - 1 - i;
address voterToRemove = voters[lastIndex].addr;

delete votersIndexes[voters[voters.length - 1 - i].addr];
voters.pop();
cumulativeVotersWeight -= uint16(voters[lastIndex].weight);

unchecked {
i++;
}
// If the voter to remove is not the last one, swap it with the last one
if (lastIndex != voters.length - 1) {
voters[lastIndex] = voters[voters.length - 1];
votersIndexes[voters[lastIndex].addr] = lastIndex;
}
}

// Remove the last voter
voters.pop();
delete votersIndexes[voterToRemove];

unchecked {
i++;
}
}
}
function isKnowledgeMiner(address addr) public view returns (bool) {
return paranetsRegistry.isKnowledgeMinerRegistered(parentParanetId, addr);
}
Expand Down Expand Up @@ -268,29 +277,37 @@ contract ParanetNeuroIncentivesPool is INamed, IVersioned {
return neuroEmissionMultipliers[0].multiplier;
}

function initiateNeuroEmissionMultiplierUpdate(uint256 newMultiplier) external onlyVotersRegistrar {
if (!neuroEmissionMultipliers[neuroEmissionMultipliers.length - 1].finalized) {
neuroEmissionMultipliers[neuroEmissionMultipliers.length - 1].multiplier = newMultiplier;
neuroEmissionMultipliers[neuroEmissionMultipliers.length - 1].timestamp =
block.timestamp +
neuroEmissionMultiplierUpdateDelay;
} else {
neuroEmissionMultipliers.push(
ParanetLib.NeuroEmissionMultiplier({
multiplier: newMultiplier,
timestamp: block.timestamp + neuroEmissionMultiplierUpdateDelay,
finalized: false
})
);
}
function initiateNeuroEmissionMultiplierUpdate(uint256 newMultiplier) external onlyVotersRegistrar {
// Define reasonable bounds for the multiplier
uint256 MIN_MULTIPLIER = 1; // Example minimum value
uint256 MAX_MULTIPLIER = 10**18; // Example maximum value, adjust as needed

emit NeuroEmissionMultiplierUpdateInitiated(
neuroEmissionMultipliers[neuroEmissionMultipliers.length - 2].multiplier,
newMultiplier,
block.timestamp + neuroEmissionMultiplierUpdateDelay
// Validate the new multiplier
require(newMultiplier >= MIN_MULTIPLIER, "Multiplier must be greater than or equal to minimum value");
require(newMultiplier <= MAX_MULTIPLIER, "Multiplier exceeds maximum allowed value");

if (!neuroEmissionMultipliers[neuroEmissionMultipliers.length - 1].finalized) {
neuroEmissionMultipliers[neuroEmissionMultipliers.length - 1].multiplier = newMultiplier;
neuroEmissionMultipliers[neuroEmissionMultipliers.length - 1].timestamp =
block.timestamp +
neuroEmissionMultiplierUpdateDelay;
} else {
neuroEmissionMultipliers.push(
ParanetLib.NeuroEmissionMultiplier({
multiplier: newMultiplier,
timestamp: block.timestamp + neuroEmissionMultiplierUpdateDelay,
finalized: false
})
);
}

emit NeuroEmissionMultiplierUpdateInitiated(
neuroEmissionMultipliers[neuroEmissionMultipliers.length - 2].multiplier,
newMultiplier,
block.timestamp + neuroEmissionMultiplierUpdateDelay
);
}

function finalizeNeuroEmissionMultiplierUpdate() external onlyVotersRegistrar {
require(neuroEmissionMultipliers.length > 0, "No emission multiplier updates");
require(
Expand Down
Loading