Skip to content

Commit

Permalink
Release (#747)
Browse files Browse the repository at this point in the history
* Increased Coverage on CollectionManager (#715)

* moved from weighted mean to weighted median (#710)

* Natspec added to parameters and random manager (#712)

* natspec changes to randomManager

* natspec added to parameters

* linting fixes

* natspec fixes

* natspec added to internal functions

* lint fixes

* spelling fix

* test: increased test coverage (#725)

* test: increased Coverage on StakeManager and MerklePos (#730)

* docs: natspec added to delegator, block manager and vote manager (#729)

* docs: natspec added to delegator, block manager and vote manager

* docs: natspec fix

* docs: natspec added to events

* docs: natspec fix

* docs: lint fix

* docs: natspec added to staked token contracts (#734)

* feat: add docgen to the project from natspec (#731)

* feat: add docgen to the project from natspec

* fix: fix package.json versions

* fix: fix tests

* chore: fix locks

Co-authored-by: SkandaBhat <[email protected]>

* fix: removed require statement from BlockManager (#740)

* test: increased coverage on BlockManager and RandomNoManager (#733)

* test: increased coverage on BlockManager and RandomNoManager

* test: increased coverage on BlockManager added test case

* test: increased coverage on blockManager

* feat: merged from master

* fix: fixed gascompare error

* fix: clean up docgen (#743)

Co-authored-by: SkandaBhat <[email protected]>

* fix: only propose revealed assets of epoch (#726)

* fix: only propose revealed assets of epoch

* chore: lint

* fix: medianIndex renamed to activeCollectionIndex

* chore: slither and lint

* chore: silly slither

* fix: scenarios failing

* fix: disputes optimised and one bug with penalties fixed

* docs: added natspec comments

* chore: cleanup

* fix: reveal event updated for node needs

* fix: scenarios test failing

* fix: activeCollectionIndex renamed to leafId

* fix: optmized for calls in loop : slither warning (#745)

Co-authored-by: Gaurav Jain <[email protected]>
Co-authored-by: SamAg19 <[email protected]>
Co-authored-by: SkandaBhat <[email protected]>
Co-authored-by: Abhishek Vispute <[email protected]>
  • Loading branch information
5 people authored Mar 15, 2022
1 parent 9b0bb18 commit 14d2b0c
Show file tree
Hide file tree
Showing 55 changed files with 1,864 additions and 26,486 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@ deployments
deployed/local
deployments
gasReporterOutput.json
.vscode/
.vscode/
docs
341 changes: 249 additions & 92 deletions contracts/Core/BlockManager.sol

Large diffs are not rendered by default.

66 changes: 46 additions & 20 deletions contracts/Core/CollectionManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -153,9 +153,10 @@ contract CollectionManager is Initializable, CollectionStorage, StateManager, Co
require(assetStatus != collections[id].active, "status not being changed");

uint32 epoch = _getEpoch();

// slither-disable-next-line incorrect-equality
if (updateRegistryEpoch <= epoch) {
_updateRegistry();
_updateDelayedRegistry();
}

if (!collections[id].active) {
Expand All @@ -166,6 +167,8 @@ contract CollectionManager is Initializable, CollectionStorage, StateManager, Co

collections[id].active = assetStatus;
updateRegistryEpoch = epoch + 1;
_updateRegistry();

emit CollectionActivityStatus(collections[id].active, id, epoch, block.timestamp);
voteManager.storeDepth(_getDepth()); // update depth now only, as from next epoch's commit it starts
}
Expand Down Expand Up @@ -193,15 +196,18 @@ contract CollectionManager is Initializable, CollectionStorage, StateManager, Co

// slither-disable-next-line incorrect-equality
if (updateRegistryEpoch <= epoch) {
_updateRegistry();
_updateDelayedRegistry();
}

numCollections = numCollections + 1;

collections[numCollections] = Structs.Collection(true, numCollections, power, tolerance, aggregationMethod, jobIDs, name);

numActiveCollections = numActiveCollections + 1;

updateRegistryEpoch = epoch + 1;
_updateRegistry();

emit CollectionCreated(numCollections, block.timestamp);

_setIDName(name, numCollections);
Expand Down Expand Up @@ -235,8 +241,8 @@ contract CollectionManager is Initializable, CollectionStorage, StateManager, Co
}

/// @inheritdoc ICollectionManager
function updateRegistry() external override onlyRole(REGISTRY_MODIFIER_ROLE) {
_updateRegistry();
function updateDelayedRegistry() external override onlyRole(REGISTRY_MODIFIER_ROLE) {
_updateDelayedRegistry();
}

/**
Expand Down Expand Up @@ -269,14 +275,12 @@ contract CollectionManager is Initializable, CollectionStorage, StateManager, Co

/// @inheritdoc ICollectionManager
function getCollectionStatus(uint16 id) external view override returns (bool) {
require(id <= numCollections, "ID does not exist");

return collections[id].active;
}

/// @inheritdoc ICollectionManager
function getCollectionTolerance(uint16 i) external view override returns (uint32) {
return collections[indexToIdRegistry[i]].tolerance;
return collections[leafIdToCollectionIdRegistry[i]].tolerance;
}

/// @inheritdoc ICollectionManager
Expand Down Expand Up @@ -314,19 +318,24 @@ contract CollectionManager is Initializable, CollectionStorage, StateManager, Co
}

/// @inheritdoc ICollectionManager
function getIdToIndexRegistryValue(uint16 id) external view override returns (uint16) {
return idToIndexRegistry[id];
function getLeafIdOfCollection(uint16 id) external view override returns (uint16) {
return collectionIdToLeafIdRegistry[id];
}

/// @inheritdoc ICollectionManager
function getActiveCollectionsHash() external view override returns (bytes32 hash) {
hash = keccak256(abi.encodePacked(getActiveCollections()));
function getLeafIdOfCollectionForLastEpoch(uint16 id) external view override returns (uint16) {
return collectionIdToLeafIdRegistryOfLastEpoch[id];
}

/// @inheritdoc ICollectionManager
function getCollectionIdFromLeafId(uint16 leafId) external view override returns (uint16) {
return leafIdToCollectionIdRegistry[leafId];
}

/**
* @return array of active collections
*/
function getActiveCollections() public view returns (uint16[] memory) {
function getActiveCollections() external view returns (uint16[] memory) {
uint16[] memory result = new uint16[](numActiveCollections);
uint16 j = 0;
for (uint16 i = 1; i <= numCollections; i++) {
Expand All @@ -340,32 +349,49 @@ contract CollectionManager is Initializable, CollectionStorage, StateManager, Co

/// @inheritdoc ICollectionManager
function getResultFromID(uint16 _id) public view override returns (uint32, int8) {
uint16 index = idToIndexRegistry[_id];
uint32 epoch = _getEpoch();
uint32[] memory medians = blockManager.getBlock(epoch - 1).medians;
int8 power = collections[_id].power;
return (medians[index], power);
return (blockManager.getLatestResults(_id), collections[_id].power);
}

/**
* @dev updates the collectionIdToLeafIdRegistry and leafIdToCollectionIdRegistry everytime a collection has been activated/deactivated/created
*/
function _updateRegistry() internal {
uint16 j = 0;
for (uint16 i = 1; i <= numCollections; i++) {
if (collections[i].active) {
idToIndexRegistry[i] = j;
indexToIdRegistry[j] = i;
collectionIdToLeafIdRegistry[i] = j;
leafIdToCollectionIdRegistry[j] = i;
j = j + 1;
} else {
collectionIdToLeafIdRegistry[i] = 0;
}
}
}

function _updateDelayedRegistry() internal {
uint16 j = 0;
for (uint16 i = 1; i <= numCollections; i++) {
if (collections[i].active) {
collectionIdToLeafIdRegistryOfLastEpoch[i] = j;
j = j + 1;
} else {
idToIndexRegistry[i] = 0;
collectionIdToLeafIdRegistryOfLastEpoch[i] = 0;
}
}
}

/**
* @dev hashes the name of the collection and the hashed value is mapped to its corresponding collection ID
*/
function _setIDName(string calldata name, uint16 _id) internal {
bytes32 _name = keccak256(abi.encodePacked(name));
require(ids[_name] == 0, "Collection exists with same name");
ids[_name] = _id;
}

/**
* @dev calculates the current depth of the merkle tree that stakers have to submit at the time of commit/reveal
*/
function _getDepth() internal view returns (uint256 n) {
// numActiveCollection is uint16, so further range not needed
// Inspired and modified from : https://medium.com/coinmonks/math-in-solidity-part-5-exponent-and-logarithm-9aef8515136e
Expand Down
28 changes: 21 additions & 7 deletions contracts/Core/RewardManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,11 @@ contract RewardManager is Initializable, Constants, RewardManagerParams, IReward
IBlockManager public blockManager;
ICollectionManager public collectionManager;

/** @param stakeManagerAddress The address of the VoteManager contract
/**
* @param stakeManagerAddress The address of the StakeManager contract
* @param voteManagersAddress The address of the VoteManager contract
* @param blockManagerAddress The address of the BlockManager contract
* @param collectionManagerAddress The address of the CollectionManager contract
*/
function initialize(
address stakeManagerAddress,
Expand Down Expand Up @@ -53,6 +55,11 @@ contract RewardManager is Initializable, Constants, RewardManagerParams, IReward
_giveInactivityPenalties(epoch, stakerId);
}

/**
* @dev inactivity penalties are given to stakers if they have been inactive for more than the grace period.
* For each inactive epoch, stakers lose their age by 1*10000 and their stake by penaltyNotRevealNum.
* Activity is calculated based on the epoch the staker last revealed in.
*/
function _giveInactivityPenalties(uint32 epoch, uint32 stakerId) internal {
uint32 epochLastRevealed = voteManager.getEpochLastRevealed(stakerId);
Structs.Staker memory thisStaker = stakeManager.getStaker(stakerId);
Expand Down Expand Up @@ -81,6 +88,12 @@ contract RewardManager is Initializable, Constants, RewardManagerParams, IReward
}
}

/**
* @dev Penalties are given to stakers based their activity if they have been inactive for more than the grace period
* and their votes in the previous epoch compared to the medians confirmed. Penalties on votes depend upon how far were
* the staker's votes from the median value. There is tolerance being added for each collection thereby not penalizing
* stakers of their vote was within the tolerance limits of the collection
*/
function _givePenalties(uint32 epoch, uint32 stakerId) internal {
_giveInactivityPenalties(epoch, stakerId);
Structs.Staker memory thisStaker = stakeManager.getStaker(stakerId);
Expand All @@ -94,19 +107,21 @@ contract RewardManager is Initializable, Constants, RewardManagerParams, IReward

Structs.Block memory _block = blockManager.getBlock(epochLastRevealed);

uint16[] memory idsRevealedLastEpoch = _block.ids;
uint32[] memory mediansLastEpoch = _block.medians;

if (mediansLastEpoch.length == 0) return;
if (idsRevealedLastEpoch.length == 0) return;
uint64 penalty = 0;
for (uint16 i = 0; i < mediansLastEpoch.length; i++) {
for (uint16 i = 0; i < idsRevealedLastEpoch.length; i++) {
// get leaf id from collection id, as voting happens w.r.t leaf ids
// slither-disable-next-line calls-loop
uint64 voteValueLastEpoch = voteManager.getVoteValue(epoch - 1, stakerId, i);

uint16 leafId = collectionManager.getLeafIdOfCollectionForLastEpoch(idsRevealedLastEpoch[i]);
// slither-disable-next-line calls-loop
uint64 voteValueLastEpoch = voteManager.getVoteValue(epoch - 1, stakerId, leafId);
if (
voteValueLastEpoch != 0
) // Only penalise if given asset revealed, please note here again revealed value of asset cant be zero
{
// uint32 voteWeightLastEpoch = voteManager.getVoteWeight(thisStaker.id, i);
uint32 medianLastEpoch = mediansLastEpoch[i];
if (medianLastEpoch == 0) continue;
uint64 prod = age * voteValueLastEpoch;
Expand All @@ -123,7 +138,6 @@ contract RewardManager is Initializable, Constants, RewardManagerParams, IReward
}
}
}

age = penalty > age ? 0 : age - uint32(penalty);

stakeManager.setStakerAge(epoch, thisStaker.id, uint32(age), AgeChanged.VotingRewardOrPenalty);
Expand Down
23 changes: 18 additions & 5 deletions contracts/Core/StakeManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,8 @@ contract StakeManager is Initializable, StakeStorage, StateManager, Pause, Stake
stakedTokenFactory = IStakedTokenFactory(stakedTokenFactoryAddress);
}

/** @notice stake during commit state only
/**
* @notice stake during commit state only
* we check epoch during every transaction to avoid withholding and rebroadcasting attacks
* @dev An ERC20 token corresponding to each new staker is created called sRZRs.
* For a new staker, amount of sRZR minted is equal to amount of RAZOR staked.
Expand All @@ -220,6 +221,7 @@ contract StakeManager is Initializable, StakeStorage, StateManager, Pause, Stake
stakers[numStakers] = Structs.Staker(false, false, 0, numStakers, 10000, msg.sender, address(sToken), epoch, 0, amount);
_setupRole(STOKEN_ROLE, address(sToken));
// Minting
// Ignoring below line for testing as this is standard erc20 function
require(sToken.mint(msg.sender, amount, amount), "tokens not minted"); // as 1RZR = 1 sRZR
totalSupply = amount;
} else {
Expand All @@ -232,6 +234,7 @@ contract StakeManager is Initializable, StakeStorage, StateManager, Pause, Stake
stakers[stakerId].stake = stakers[stakerId].stake + (amount);

// Mint sToken as Amount * (totalSupplyOfToken/previousStake)
// Ignoring below line for testing as this is standard erc20 function
require(sToken.mint(msg.sender, toMint, amount), "tokens not minted");
totalSupply = totalSupply + toMint;
}
Expand All @@ -246,10 +249,12 @@ contract StakeManager is Initializable, StakeStorage, StateManager, Pause, Stake
totalSupply,
block.timestamp
);
// Ignoring below line for testing as this is standard erc20 function
require(razor.transferFrom(msg.sender, address(this), amount), "razor transfer failed");
}

/** @notice Delegation
/**
* @notice delegators can delegate their funds to staker if they do not have the adequate resources to start a node
* @dev the delegator receives the sRZR for the stakerID to which he/she delegates.
* The amount of sRZR minted depends on depends on sRZR:(RAZOR staked) valuation at the time of delegation
* @param amount The amount in RZR
Expand All @@ -269,13 +274,15 @@ contract StakeManager is Initializable, StakeStorage, StateManager, Pause, Stake
stakers[stakerId].stake = stakers[stakerId].stake + (amount);

// Step 3: Mint sToken as Amount * (totalSupplyOfToken/previousStake)
// Ignoring below line for testing as this is standard erc20 function
require(sToken.mint(msg.sender, toMint, amount), "tokens not minted");
totalSupply = totalSupply + toMint;

// slither-disable-next-line reentrancy-events
emit Delegated(msg.sender, epoch, stakerId, amount, stakers[stakerId].stake, totalSupply, block.timestamp);

// Step 4: Razor Token Transfer : Amount
// Ignoring below line for testing as this is standard erc20 function
require(razor.transferFrom(msg.sender, address(this), amount), "RZR token transfer failed");
}

Expand Down Expand Up @@ -304,6 +311,7 @@ contract StakeManager is Initializable, StakeStorage, StateManager, Pause, Stake
sToken.getRZRDeposited(msg.sender, sAmount)
);
emit Unstaked(msg.sender, epoch, stakerId, sAmount, staker.stake, block.timestamp);
// Ignoring below line for testing as this is standard erc20 function
require(sToken.transferFrom(msg.sender, address(this), sAmount), "sToken transfer failed");
}

Expand Down Expand Up @@ -334,6 +342,7 @@ contract StakeManager is Initializable, StakeStorage, StateManager, Pause, Stake
staker.stake = staker.stake - rAmount;

locks[msg.sender][staker.tokenAddress][LockType.Withdraw] = Structs.Lock(rAmount, epoch + withdrawLockPeriod, lock.initial);
// Ignoring below line for testing as this is standard erc20 function
require(sToken.burn(address(this), lock.amount), "Token burn Failed");
//emit event here
emit WithdrawInitiated(msg.sender, epoch, stakerId, rAmount, staker.stake, sToken.totalSupply(), block.timestamp);
Expand Down Expand Up @@ -373,14 +382,17 @@ contract StakeManager is Initializable, StakeStorage, StateManager, Pause, Stake
_resetLock(stakerId);

emit Withdrew(msg.sender, epoch, stakerId, withdrawAmount, staker.stake, block.timestamp);
// Ignoring below line for testing as this is standard erc20 function
require(razor.transfer(staker._address, commission), "couldnt transfer");
//Transfer Razor Back
// Ignoring below line for testing as this is standard erc20 function
require(razor.transfer(msg.sender, withdrawAmount), "couldnt transfer");
}

/// @inheritdoc IStakeManager
function escape(address _address) external override initialized onlyRole(ESCAPE_HATCH_ROLE) whenPaused {
if (escapeHatchEnabled) {
// Ignoring below line for testing as this is standard erc20 function
require(razor.transfer(_address, razor.balanceOf(address(this))), "razor transfer failed");
} else {
revert("escape hatch is disabled");
Expand Down Expand Up @@ -449,6 +461,7 @@ contract StakeManager is Initializable, StakeStorage, StateManager, Pause, Stake
staker.stake = staker.stake - rPenalty;
lock.unlockAfter = epoch;
emit ExtendUnstakeLock(stakerId, msg.sender, _getEpoch());
// Ignoring below line for testing as this is standard erc20 function
require(sToken.burn(address(this), penalty), "Token burn Failed");
}

Expand Down Expand Up @@ -498,6 +511,7 @@ contract StakeManager is Initializable, StakeStorage, StateManager, Pause, Stake
//please note that since slashing is a critical part of consensus algorithm,
//the following transfers are not `reuquire`d. even if the transfers fail, the slashing
//tx should complete.
// Ignoring below line for testing as this is standard erc20 function
// slither-disable-next-line unchecked-transfer
razor.transfer(BURN_ADDRESS, amountToBeBurned);
}
Expand All @@ -512,6 +526,7 @@ contract StakeManager is Initializable, StakeStorage, StateManager, Pause, Stake
require(msg.sender == bountyLocks[bountyId].bountyHunter, "Incorrect Caller");
require(bountyLocks[bountyId].redeemAfter <= epoch, "Redeem epoch not reached");
delete bountyLocks[bountyId];
// Ignoring below line for testing as this is standard erc20 function
require(razor.transfer(msg.sender, bounty), "couldnt transfer");
}

Expand Down Expand Up @@ -568,9 +583,7 @@ contract StakeManager is Initializable, StakeStorage, StateManager, Pause, Stake
return stakers[stakerId].epochFirstStakedOrLastPenalized;
}

/**
* @return length of maturities array
*/
/// @inheritdoc IStakeManager
function maturitiesLength() external view override returns (uint32) {
return uint32(maturities.length);
}
Expand Down
Loading

0 comments on commit 14d2b0c

Please sign in to comment.