Giter Site home page Giter Site logo

ronin-dpos-contracts's Introduction

Ronin DPoS Contracts

The collections of smart contracts that power the Ronin Delegated Proof of Stake (DPoS) network.

Development

Requirement

  • Node@>=14 + Solc@^0.8.0

Compile & test

  • Add Github NPM token to install packages, and then replace {YOUR_TOKEN} in .npmrc file by any arbitrary Github token with read:packages permission.

    Note: To create a new token, please refer to this article. The token must have read:packages permission.

    cp .npmrc.example .npmrc && vim .npmrc
  • Install packages

    $ yarn --frozen-lockfile
  • Install foundry libs

    $ git submodule add -b release-v0 https://github.com/PaulRBerg/prb-test lib/prb-test
    $ git submodule add -b release-v4 https://github.com/PaulRBerg/prb-math lib/prb-math
    
  • Compile contracts

    $ yarn compile
  • Run test

    $ yarn test
  • Extract storage layout

    $ yarn plugin:storage-layout [--destination <output-path>] [--override <true|false>]
    • <output-path> (optional): The path to store generated storage layout file. If not provided, the default path is layout/storage.txt.
    • --override (optional): Indicates whether to override the destination file at <output-path> if it already exists. By default, it is set to false.

Target chain to deploy

This repo contains source code of contracts that will be either deployed on the mainchains, or on Ronin chain.

  • On mainchains:
    • Governance contract: MainchainGovernanceAdmin
    • Bridge contract: MainchainGatewayV3
    • Trusted orgs contract: RoninTrustedOrganization
  • On Ronin chain:
    • Governance contract: RoninGovernanceAdmin
    • Bridge operation: RoninGatewayV3
    • Trusted orgs contract: RoninTrustedOrganization
    • DPoS contracts

Upgradeability & Governance mechanism

Except for the governance contracts and vault forwarder contracts, all other contracts are deployed following the proxy pattern for upgradeability. The TransparentUpgradeableProxyV2, an extended version of OpenZeppelin's, is used for deploying the proxies.

To comply with the governance process, in which requires all modifications to a contract must be approved by a set of governors, the admin role of all proxies must be granted for the governance contract address.

Deployment steps

  • Init the environment variables

    $ cp .env.example .env && vim .env
  • Update the contract configuration in config.ts file

  • Deploy the contracts

    $ yarn hardhat deploy --network <local|ronin-devnet|ronin-mainnet|ronin-testnet>

Documentation

See docs/README.md for the documentation of the contracts.

See docs/HACK.md for the structure of the repo.

For the contract interaction flow, please refer to DPoS Contract: Interaction Flow.

For the whitepaper, please refer to Ronin Whitepaper.

ronin-dpos-contracts's People

Contributors

dependabot[bot] avatar ducthotran2010 avatar huyhuynh3103 avatar huyngopt1994 avatar minh-bq avatar nxqbao avatar tudo1403 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ronin-dpos-contracts's Issues

Comment issues

    I think we need a more detailed explanation for these three functions, in order to differentiate the usage of these three.

Originally posted by @nxqbao in #22 (comment)

/**
* @dev Deprecates the pool.
*
* Requirements:
* - The method caller is validator contract.
*
* Emits the event `PoolsDeprecated` and `Unstaked` events.
* Emits the event `StakedAmountDeprecated` if the contract cannot transfer RON back to the pool admin.
*
*/
function deprecatePools(address[] calldata _pools) external;

Delegator still able to delegate to not-kicked-yet under balance validator

When a validator is slashed and gets deducted a staked amount to make his balance is under the minimum required, and he will be kicked in the next period, we expect no delegators can top-up to this validator.

The current implementation allows both delegators and validators can top-up, and the following side-effects may get broken.

[Maintenance] The validator candidates may schedule too far in the future

require(block.number + minOffset <= _startedAtBlock, "Maintenance: invalid offset size");

We don't have any restrictions to prevent the validator candidates from scheduling too far in the future.

For example, we only allow 5 maintenance at a time, and these 5 slots of maintenance are filled up to far in the future. A validator suddenly crashes, and needs emergency go into maintenance, but he cannot since there is no slot of maintenance available.

We need to set a furthest time restriction that allows a validator to set a schedule of maintenance.

Related to the post by @nxqbao in #22 (comment)
Related to the post by @nxqbao in #22 (comment)

The candidates can share the same bridge operator and other data

    We should not allow validators to share the same admin, treasury, or bridge operator

Originally posted by @ducthotran2010 in #22 (comment)

uint256 _length = _candidates.length;
require(_length < maxValidatorCandidate(), "CandidateManager: exceeds maximum number of candidates");
require(!isValidatorCandidate(_consensusAddr), "CandidateManager: query for already existent candidate");
require(_commissionRate <= _MAX_PERCENTAGE, "CandidateManager: invalid comission rate");
_candidateIndex[_consensusAddr] = ~_length;
_candidates.push(_consensusAddr);
_candidateInfo[_consensusAddr] = ValidatorCandidate(
_admin,
_consensusAddr,
_treasuryAddr,
_bridgeOperatorAddr,
_commissionRate,
type(uint256).max,
new bytes(0)
);
emit CandidateGranted(_consensusAddr, _treasuryAddr, _admin, _bridgeOperatorAddr);

Duplicated functions to get credit configuration

We already have the function to get the credit score configuration here:

/**
* @inheritdoc ICreditScore
*/
function getCreditScoreConfigs()
external
view
override
returns (
uint256 _gainCreditScore,
uint256 _maxCreditScore,
uint256 _bailOutCostMultiplier,
uint256 _cutOffPercentageAfterBailout
)
{
_gainCreditScore = gainCreditScore;
_maxCreditScore = maxCreditScore;
_bailOutCostMultiplier = bailOutCostMultiplier;
_cutOffPercentageAfterBailout = cutOffPercentageAfterBailout;
}

Because these variables are public, it is also exposed in the ABI:

/// @dev The max gained number of credit score per period.
uint256 public gainCreditScore;
/// @dev The max number of credit score that a validator can hold.
uint256 public maxCreditScore;
/// @dev The number that will be multiplied with the remaining jailed time to get the cost of bailing out.
uint256 public bailOutCostMultiplier;
/// @dev The percentage of reward to be cut off from the validator in the rest of the period after bailed out.
uint256 public cutOffPercentageAfterBailout;

The ABI consumers may be confused

Potential bugs in `isValidator` callers

Potential problems in calling isValidator.

contracts/ronin/Maintenance.sol:

  • Does we allow a candidate to schedule maintenance? Because an arbitrary candidate may not know if they will be picked to become a validator in the future. In the current implementation, we don't have any time restriction on the _startedAtBlock.

contracts/ronin/SlashIndicator.sol:

  • Same for the Maintenance contract. In case a misbehaved ex-validator becomes a candidate, we cannot slash him since he is not a validator anymore.

Originally posted by @nxqbao in #32 (comment)

Confusing variable name in Staking contract

Multiple meanings of staking amount

Recommend

Delegate -> Stake; Stake -> Self-Staking

Revamps `deprecated` mappings

https://skymavis.atlassian.net/browse/PSC-131?atlOrigin=eyJpIjoiY2FiYjYxMzM3NGJlNDRhM2FjZjk0ZmUzYmU4NDY2OGYiLCJwIjoiaiJ9
I guess we can clear these mappings since the reward amount is stored in decimal number:

/// @dev Mapping from consensus address => period number => block producer has no pending reward
mapping(address => mapping(uint256 => bool)) internal _miningRewardDeprecatedAtPeriod;

/// @dev Mapping from consensus address => period number => block operator has no pending reward
mapping(address => mapping(uint256 => bool)) internal _bridgeRewardDeprecatedAtPeriod;

Waiting time of renouncing can be cheated

A validator who requests to renounce has to wait at least 7 days before the request takes effect.

He can skip the waiting time by unstaking his self-staking amount to the required minimum balance, and intentionally getting slashed. Once slashed, and becoming under-balance, he will be kicked in the next period, which means the waiting time for renouncing is less than 1 day.

We should kick the validator after 7 days when he becomes under-balance.

Set of bridge operator mismatched

The check of if (isBlockProducer(_validators[_i])) should be if (isValidator(_validators[_i])), since a validator can hold only one of the two roles at a time. Current check requires an operator to be a block producer, which might yield incorrect results.

function getBridgeOperators() public view override returns (address[] memory _result) {
_result = new address[](validatorCount);
uint256 _count = 0;
for (uint _i = 0; _i < _result.length; _i++) {
if (isBlockProducer(_validators[_i])) {
_result[_count++] = _bridgeOperatorOf(_validators[_i]);
}
}
assembly {
mstore(_result, _count)
}
}

Support Ronin voting without signatures

AFAIK the primary purpose of requiring the governor's signatures is to relay on mainchains. Therefore, the contract on mainchain MainchainGovernanceAdmin can verify whether the relayed proposal is accurate, based on the submitted signatures.

The signatures are required while casting votes:

/**
* @dev See `GovernanceProposal-_proposeProposalStructAndCastVotes`.
*
* Requirements:
* - The method caller is governor.
*
*/
function proposeProposalStructAndCastVotes(
Proposal.ProposalDetail calldata _proposal,
Ballot.VoteType[] calldata _supports,
Signature[] calldata _signatures
) external onlyGovernor {
_proposeProposalStructAndCastVotes(_proposal, _supports, _signatures, DOMAIN_SEPARATOR, msg.sender);
}
/**
* @dev See `GovernanceProposal-_castProposalBySignatures`.
*/
function castProposalBySignatures(
Proposal.ProposalDetail calldata _proposal,
Ballot.VoteType[] calldata _supports,
Signature[] calldata _signatures
) external {
_castProposalBySignatures(_proposal, _supports, _signatures, DOMAIN_SEPARATOR);
}

After that it's relayed on the mainchain network:
/**
* @dev See `GovernanceRelay-_relayProposal`.
*
* Requirements:
* - The method caller is relayer.
*
*/
function relayProposal(
Proposal.ProposalDetail calldata _proposal,
Ballot.VoteType[] calldata _supports,
Signature[] calldata _signatures
) external onlyRole(RELAYER_ROLE) {
_relayProposal(_proposal, _supports, _signatures, DOMAIN_SEPARATOR, msg.sender);
}

But the per-chain proposal on the Ronin network is not being relayed anywhere and I guess we can support voting on the Ronin network (chainId = 2020 | 2021 | 2022) without requiring any signatures.

[Maintenance] Confusing name `_minMaintenanceBlockPeriod`

The name _minMaintenanceBlockPeriod and _maxMaintenanceBlockPeriod seem confusing since they conflict with period in the ValidatorSet contract. These two values are counted in the number of blocks, but the name can confuse them to be counted in the number of periods.

They could be changed to
minMaintenanceBlockPeriod -> minMaintenanceDurationInBlock
maxMaintenanceBlockPeriod -> maxMaintenanceDurationInBlock

/// @dev The min block period to maintenance
uint256 public minMaintenanceBlockPeriod;
/// @dev The max block period to maintenance
uint256 public maxMaintenanceBlockPeriod;

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.