Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@tbssajal
Copy link
Contributor

@tbssajal tbssajal commented Feb 13, 2025

This PR addresses the following issues:

  • The runtime complexity of staking operations in finalize() is O(number of staking requests)
  • Users' balances are updated at protocol level contract call

The PR introduces the following changes:

  • Introduced staking pool as an additional layer between autonity and liquid contract
    • All accounting related to staking is done in staking pool, delegators take their share (liquid, released stake or atn rewards) from the pool
    • All stakes bonded or going under bonding or unbonding period can be accounted by the newton balance of staking pool contract
  • Users don't need to be aware of the staking pool contract.

Additional changes done in the PR:

  • Refactored how commission rate is updated: no need to iterate the queue in finalize() call.
  • Refactored how newton balances are updated in autonity contract: now we only use _transfer, _mint and _burn methods to update the balance.

@codecov
Copy link

codecov bot commented Feb 13, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 74.90%. Comparing base (6ef2894) to head (36abb30).
Report is 143 commits behind head on develop.

Additional details and impacted files
@@             Coverage Diff             @@
##           develop    #1144      +/-   ##
===========================================
+ Coverage    72.97%   74.90%   +1.93%     
===========================================
  Files           27       29       +2     
  Lines         3281     4629    +1348     
===========================================
+ Hits          2394     3467    +1073     
- Misses         692      859     +167     
- Partials       195      303     +108     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@tbssajal tbssajal force-pushed the staking-pool branch 9 times, most recently from b6ee9f6 to 1ab7a9e Compare February 26, 2025 10:37
@tbssajal tbssajal marked this pull request as ready for review February 26, 2025 14:12
Copy link
Contributor

@Jason-Zhangxin-Chen Jason-Zhangxin-Chen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a few comments and questions left, thank you, Tariq. The structure looks better. However, if we can add a README.md for this feature in our contract directory would be better. In the README, you can high light the state machine transitions for the staking tasks and the asset steaming in those pools. For the other reviews, please start with the data models in IStakingPool.sol first, that would help a lots.

curCommittee.push(committee[i].addr);
allowedReporters[committee[i].addr] = true;
function finalizeInitialization(Autonity.CommitteeMember[] memory _committee) external onlyAutonity {
delete curCommittee;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In reality, this delete statement should not be required as we deploy and initialize it in genesis block setup, but I think this would help the testing be easier. Please add a comment here, otherwise it can confuse teammates a little bit.

event MintedStake(address indexed addr, uint256 amount);
event BurnedStake(address indexed addr, uint256 amount);
event CommissionRateChange(address indexed validator, uint256 rate);
event CommissionRateChange(address indexed validator, uint256 rate, uint256 activeBlock, bool overridePendingRate);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just curious, what is a overridePendingRate typed in boolean?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, you return a flag to let user to know an un applied rate is overwrite.

stakeSupply += _bondedStake;
stakeCirculating += _bondedStake;
_bond(_validators[i].nodeAddress, _bondedStake, payable(_validators[i].treasury));
_mint(_validators[i].treasury, _validators[i].bondedStake);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just curious, why the self bonding is removed here?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I see you have a function to mange the genesis bonding.

commissionRateChangeQueue[commissionRateChangeQueueLast] = _newRequest;
commissionRateChangeQueueLast += 1;
emit CommissionRateChange(_validator, _rate);
_applyNewCommissionRate(_validator);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_applyNewCommissionRate is called at the end of each epoch, just curious, why do we need call it at here? Is there any edge case need to be handled by this?

return (_oracleVoters, _afdReporters, _treasuries);
}

function autobond(address _validator, uint256 _selfBond, uint256 _delegated) external virtual onlyAtEpochEnd onlyRewardDistributor(_validator) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Coud rename autobond to autoBond() as we are here.

// this library is not for general queue operation
// a general-purpose queue library may be implemented later
library UintQueueLib {
function enqueue(UintQueue storage _queue, uint256 _item) internal {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

    /**
     * @dev Adds an item to the end of the queue.
     * @param _queue The queue to modify.
     * @param _item The item to enqueue.
     */

function enqueue(UintQueue storage _queue, uint256 _item) internal {
_queue.array.push(_item);
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

    /**
     * @dev Removes up to _deleteCount elements from the front of the queue.
     * @param _queue The queue to modify.
     * @param _deleteCount The number of elements to remove.
     */


function balanceInPool(address _account) public virtual view returns (uint256) {
IStakingPool _stakingPool = IStakingPool(autonityContract.getStakingPool());
return _stakingPool.calculateLiquidBurning(_account, validator) + _stakingPool.calculateLiquidMinted(_account, validator);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At first galance, the naming of function calculateLiquidBurning is a little bit confused. However I can understand it after dive into the staking pool contract. Can we add a comment here, as the burning here is about the ongoing unbonding assets.

uint256 _liquidBalance = _liquidContracts[i].balanceInContract(address(this));
if (_liquidBalance > 0) {
_liquidContracts[i].claimRewards();
lastFeeFactor[_validators[i]] += (address(this).balance - _atnBalance) * FEE_FACTOR_UNIT_RECIP / _liquidBalance;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, in this case, when one claim rewards, the lastFeeFactor will be decreasing, right? The _liquidContracts[i].claimRewards(); will update the atn balance saved in the staking pool contract. Can we add more comments in this function to let it be clearly understand. Thanks, Tariq.

*/
function collectRewards(address[] memory _validators, ILiquid[] memory _liquidContracts) external onlyAutonity {
uint256 _count = _validators.length;
require(_count == _liquidContracts.length, "invalid inputs");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This error message should be refined to add more specific info.

@Jason-Zhangxin-Chen
Copy link
Contributor

@tbssajal @yazzaoui @lorenzo-dev1 @vpiyush @ScottRMalley , ever thought to cap the pending queues of bonding and unboding request? In edge case, if there are too much accumulating requests, some of them might be malicious with dust weighted bonding, will we spend a lot of effort to process them at Epoch rotation which is critical for us.

@tbssajal tbssajal marked this pull request as draft April 7, 2025 13:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants