-
Notifications
You must be signed in to change notification settings - Fork 3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Initial setup for testnet-delegation contract #427
base: develop
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Slither found more than 10 potential problems in the proposed changes. Check the Files changed tab for more details.
packages/testnet-delegation/contracts/interfaces/IDelegation.sol
Outdated
Show resolved
Hide resolved
packages/testnet-delegation/contracts/DelegationOrchestrator.sol
Outdated
Show resolved
Hide resolved
packages/testnet-delegation/contracts/DelegationOrchestrator.sol
Outdated
Show resolved
Hide resolved
packages/testnet-delegation/contracts/DelegationOrchestrator.sol
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should also check the internal validators balances before delegation to them. If they already have 2t+1, we don't need to delegate when registering new external validator
function registerValidator( | ||
address validator, | ||
bytes memory proof, | ||
bytes memory vrf_key, |
Check warning
Code scanning / Slither
Conformance to Solidity naming conventions
function cancelUndelegate(address validator) external; | ||
|
||
// Redelegates <amount> of tokens from one validator to the other | ||
function reDelegate(address validator_from, address validator_to, uint256 amount) external; |
Check warning
Code scanning / Slither
Conformance to Solidity naming conventions
function cancelUndelegate(address validator) external; | ||
|
||
// Redelegates <amount> of tokens from one validator to the other | ||
function reDelegate(address validator_from, address validator_to, uint256 amount) external; |
Check warning
Code scanning / Slither
Conformance to Solidity naming conventions
internalStake += internalValidatorInfo.total_stake; | ||
} | ||
if (index < externalValidators.length) { | ||
IDPOS.ValidatorBasicInfo memory externalValidatorInfo = dpos.getValidator(externalValidators[index]); |
Check warning
Code scanning / Slither
Variable names too similar
function _delegate(address implementation) internal virtual returns (bytes memory returnData) { | ||
assembly { | ||
// Copy msg.data. We take full control of memory in this inline assembly | ||
// block because it will not return to Solidity code. We overwrite the | ||
// Solidity scratch pad at memory position 0. | ||
calldatacopy(0, 0, calldatasize()) | ||
|
||
// Call the implementation. | ||
// out and outsize are 0 because we don't know the size yet. | ||
let result := call(gas(), implementation, callvalue(), 0, calldatasize(), 0, 0) | ||
|
||
// Copy the returned data. | ||
returndatacopy(0, 0, returndatasize()) | ||
|
||
switch result | ||
// delegatecall returns 0 on error. | ||
case 0 { | ||
revert(0, returndatasize()) | ||
} | ||
default { | ||
return(0, returndatasize()) | ||
} | ||
} | ||
} |
Check warning
Code scanning / Slither
Assembly usage
// @note registrar of indexes+1 of validators in the internalValidators | ||
mapping(address => uint256) public internalValidatorRegistered; | ||
// @note registrar of indexes+1 of validators in the externalValidators | ||
mapping(address => uint256) public externalValidatorRegistered; |
Check warning
Code scanning / Slither
Variable names too similar
Implement the following shadowings: // Returns validator basic info (everything except list of his delegators)
|
function registerValidator( | ||
address validator, | ||
bytes memory proof, | ||
bytes memory vrfKey, | ||
uint16 commission, | ||
string calldata description, | ||
string calldata endpoint | ||
) external payable override nonReentrant { | ||
uint256 delegationValue = (2 * msg.value) / internalValidators.length; | ||
require( | ||
externalValidatorRegistered[validator] == 0 && internalValidatorRegistered[validator] == 0, | ||
"Validator already registered" | ||
); | ||
require(msg.value >= (MIN_REGISTRATION_DELEGATION), "Sent value less than minimal delegation for registration"); | ||
require( | ||
address(this).balance >= delegationValue * internalValidators.length, | ||
"Insufficient funds in contract for testnet rebalance" | ||
); | ||
uint256 internalStake = 0; | ||
uint256 externalStake = 0; | ||
(internalStake, externalStake) = _calculateStakes(); | ||
require(internalStake != 0 || externalStake != 0, "Calculating current stakes failed!"); | ||
uint256 majorityStake = 2 * externalStake + msg.value + MIN_REGISTRATION_DELEGATION; | ||
if (internalStake < majorityStake) { | ||
// Delegate 2*tokens to our validators | ||
for (uint8 i = 0; i < internalValidators.length; ) { | ||
(bool hasDelegated, ) = address(dpos).call{value: delegationValue}( | ||
abi.encodeWithSignature("delegate(address)", internalValidators[i]) | ||
); | ||
|
||
require(hasDelegated, "Delegate call failed"); | ||
emit InternalValidatorDelegationIncreased(internalValidators[i], delegationValue); | ||
unchecked { | ||
++i; | ||
} | ||
} | ||
} | ||
externalValidatorsByOwners[msg.sender].push(validator); | ||
externalValidators.push(validator); | ||
externalValidatorRegistered[validator] = externalValidators.length; | ||
externalValidatorOwners[validator] = msg.sender; | ||
bytes memory input = abi.encodeWithSelector( | ||
REGISTER_VALIDATOR_SELECTOR, | ||
validator, | ||
proof, | ||
vrfKey, | ||
commission, | ||
description, | ||
endpoint | ||
); | ||
(bool hasRegistered, ) = address(dpos).call{value: msg.value}(input); | ||
|
||
require(hasRegistered, "Register validator call failed"); | ||
|
||
emit ExternalValidatorRegistered(validator, msg.sender, msg.value); | ||
} |
Check failure
Code scanning / Slither
Reentrancy vulnerabilities
function registerValidator( | ||
address validator, | ||
bytes memory proof, | ||
bytes memory vrfKey, | ||
uint16 commission, | ||
string calldata description, | ||
string calldata endpoint | ||
) external payable override nonReentrant { | ||
uint256 delegationValue = (2 * msg.value) / internalValidators.length; | ||
require( | ||
externalValidatorRegistered[validator] == 0 && internalValidatorRegistered[validator] == 0, | ||
"Validator already registered" | ||
); | ||
require(msg.value >= (MIN_REGISTRATION_DELEGATION), "Sent value less than minimal delegation for registration"); | ||
require( | ||
address(this).balance >= delegationValue * internalValidators.length, | ||
"Insufficient funds in contract for testnet rebalance" | ||
); | ||
uint256 internalStake = 0; | ||
uint256 externalStake = 0; | ||
(internalStake, externalStake) = _calculateStakes(); | ||
require(internalStake != 0 || externalStake != 0, "Calculating current stakes failed!"); | ||
uint256 majorityStake = 2 * externalStake + msg.value + MIN_REGISTRATION_DELEGATION; | ||
if (internalStake < majorityStake) { | ||
// Delegate 2*tokens to our validators | ||
for (uint8 i = 0; i < internalValidators.length; ) { | ||
(bool hasDelegated, ) = address(dpos).call{value: delegationValue}( | ||
abi.encodeWithSignature("delegate(address)", internalValidators[i]) | ||
); | ||
|
||
require(hasDelegated, "Delegate call failed"); | ||
emit InternalValidatorDelegationIncreased(internalValidators[i], delegationValue); | ||
unchecked { | ||
++i; | ||
} | ||
} | ||
} | ||
externalValidatorsByOwners[msg.sender].push(validator); | ||
externalValidators.push(validator); | ||
externalValidatorRegistered[validator] = externalValidators.length; | ||
externalValidatorOwners[validator] = msg.sender; | ||
bytes memory input = abi.encodeWithSelector( | ||
REGISTER_VALIDATOR_SELECTOR, | ||
validator, | ||
proof, | ||
vrfKey, | ||
commission, | ||
description, | ||
endpoint | ||
); | ||
(bool hasRegistered, ) = address(dpos).call{value: msg.value}(input); | ||
|
||
require(hasRegistered, "Register validator call failed"); | ||
|
||
emit ExternalValidatorRegistered(validator, msg.sender, msg.value); | ||
} |
Check warning
Code scanning / Slither
Divide before multiply
function registerValidator( | ||
address validator, | ||
bytes memory proof, | ||
bytes memory vrfKey, | ||
uint16 commission, | ||
string calldata description, | ||
string calldata endpoint | ||
) external payable override nonReentrant { | ||
uint256 delegationValue = (2 * msg.value) / internalValidators.length; | ||
require( | ||
externalValidatorRegistered[validator] == 0 && internalValidatorRegistered[validator] == 0, | ||
"Validator already registered" | ||
); | ||
require(msg.value >= (MIN_REGISTRATION_DELEGATION), "Sent value less than minimal delegation for registration"); | ||
require( | ||
address(this).balance >= delegationValue * internalValidators.length, | ||
"Insufficient funds in contract for testnet rebalance" | ||
); | ||
uint256 internalStake = 0; | ||
uint256 externalStake = 0; | ||
(internalStake, externalStake) = _calculateStakes(); | ||
require(internalStake != 0 || externalStake != 0, "Calculating current stakes failed!"); | ||
uint256 majorityStake = 2 * externalStake + msg.value + MIN_REGISTRATION_DELEGATION; | ||
if (internalStake < majorityStake) { | ||
// Delegate 2*tokens to our validators | ||
for (uint8 i = 0; i < internalValidators.length; ) { | ||
(bool hasDelegated, ) = address(dpos).call{value: delegationValue}( | ||
abi.encodeWithSignature("delegate(address)", internalValidators[i]) | ||
); | ||
|
||
require(hasDelegated, "Delegate call failed"); | ||
emit InternalValidatorDelegationIncreased(internalValidators[i], delegationValue); | ||
unchecked { | ||
++i; | ||
} | ||
} | ||
} | ||
externalValidatorsByOwners[msg.sender].push(validator); | ||
externalValidators.push(validator); | ||
externalValidatorRegistered[validator] = externalValidators.length; | ||
externalValidatorOwners[validator] = msg.sender; | ||
bytes memory input = abi.encodeWithSelector( | ||
REGISTER_VALIDATOR_SELECTOR, | ||
validator, | ||
proof, | ||
vrfKey, | ||
commission, | ||
description, | ||
endpoint | ||
); | ||
(bool hasRegistered, ) = address(dpos).call{value: msg.value}(input); | ||
|
||
require(hasRegistered, "Register validator call failed"); | ||
|
||
emit ExternalValidatorRegistered(validator, msg.sender, msg.value); | ||
} |
Check notice
Code scanning / Slither
Calls inside a loop
function registerValidator( | ||
address validator, | ||
bytes memory proof, | ||
bytes memory vrfKey, | ||
uint16 commission, | ||
string calldata description, | ||
string calldata endpoint | ||
) external payable override nonReentrant { | ||
uint256 delegationValue = (2 * msg.value) / internalValidators.length; | ||
require( | ||
externalValidatorRegistered[validator] == 0 && internalValidatorRegistered[validator] == 0, | ||
"Validator already registered" | ||
); | ||
require(msg.value >= (MIN_REGISTRATION_DELEGATION), "Sent value less than minimal delegation for registration"); | ||
require( | ||
address(this).balance >= delegationValue * internalValidators.length, | ||
"Insufficient funds in contract for testnet rebalance" | ||
); | ||
uint256 internalStake = 0; | ||
uint256 externalStake = 0; | ||
(internalStake, externalStake) = _calculateStakes(); | ||
require(internalStake != 0 || externalStake != 0, "Calculating current stakes failed!"); | ||
uint256 majorityStake = 2 * externalStake + msg.value + MIN_REGISTRATION_DELEGATION; | ||
if (internalStake < majorityStake) { | ||
// Delegate 2*tokens to our validators | ||
for (uint8 i = 0; i < internalValidators.length; ) { | ||
(bool hasDelegated, ) = address(dpos).call{value: delegationValue}( | ||
abi.encodeWithSignature("delegate(address)", internalValidators[i]) | ||
); | ||
|
||
require(hasDelegated, "Delegate call failed"); | ||
emit InternalValidatorDelegationIncreased(internalValidators[i], delegationValue); | ||
unchecked { | ||
++i; | ||
} | ||
} | ||
} | ||
externalValidatorsByOwners[msg.sender].push(validator); | ||
externalValidators.push(validator); | ||
externalValidatorRegistered[validator] = externalValidators.length; | ||
externalValidatorOwners[validator] = msg.sender; | ||
bytes memory input = abi.encodeWithSelector( | ||
REGISTER_VALIDATOR_SELECTOR, | ||
validator, | ||
proof, | ||
vrfKey, | ||
commission, | ||
description, | ||
endpoint | ||
); | ||
(bool hasRegistered, ) = address(dpos).call{value: msg.value}(input); | ||
|
||
require(hasRegistered, "Register validator call failed"); | ||
|
||
emit ExternalValidatorRegistered(validator, msg.sender, msg.value); | ||
} |
Check notice
Code scanning / Slither
Reentrancy vulnerabilities
function registerValidator( | ||
address validator, | ||
bytes memory proof, | ||
bytes memory vrfKey, | ||
uint16 commission, | ||
string calldata description, | ||
string calldata endpoint | ||
) external payable override nonReentrant { | ||
uint256 delegationValue = (2 * msg.value) / internalValidators.length; | ||
require( | ||
externalValidatorRegistered[validator] == 0 && internalValidatorRegistered[validator] == 0, | ||
"Validator already registered" | ||
); | ||
require(msg.value >= (MIN_REGISTRATION_DELEGATION), "Sent value less than minimal delegation for registration"); | ||
require( | ||
address(this).balance >= delegationValue * internalValidators.length, | ||
"Insufficient funds in contract for testnet rebalance" | ||
); | ||
uint256 internalStake = 0; | ||
uint256 externalStake = 0; | ||
(internalStake, externalStake) = _calculateStakes(); | ||
require(internalStake != 0 || externalStake != 0, "Calculating current stakes failed!"); | ||
uint256 majorityStake = 2 * externalStake + msg.value + MIN_REGISTRATION_DELEGATION; | ||
if (internalStake < majorityStake) { | ||
// Delegate 2*tokens to our validators | ||
for (uint8 i = 0; i < internalValidators.length; ) { | ||
(bool hasDelegated, ) = address(dpos).call{value: delegationValue}( | ||
abi.encodeWithSignature("delegate(address)", internalValidators[i]) | ||
); | ||
|
||
require(hasDelegated, "Delegate call failed"); | ||
emit InternalValidatorDelegationIncreased(internalValidators[i], delegationValue); | ||
unchecked { | ||
++i; | ||
} | ||
} | ||
} | ||
externalValidatorsByOwners[msg.sender].push(validator); | ||
externalValidators.push(validator); | ||
externalValidatorRegistered[validator] = externalValidators.length; | ||
externalValidatorOwners[validator] = msg.sender; | ||
bytes memory input = abi.encodeWithSelector( | ||
REGISTER_VALIDATOR_SELECTOR, | ||
validator, | ||
proof, | ||
vrfKey, | ||
commission, | ||
description, | ||
endpoint | ||
); | ||
(bool hasRegistered, ) = address(dpos).call{value: msg.value}(input); | ||
|
||
require(hasRegistered, "Register validator call failed"); | ||
|
||
emit ExternalValidatorRegistered(validator, msg.sender, msg.value); | ||
} |
Check warning
Code scanning / Slither
Low-level calls
This pull request sets up GitHub code scanning for this repository. Once the scans have completed and the checks have passed, the analysis results for this pull request branch will appear on this overview. Once you merge this pull request, the 'Security' tab will show more code scanning analysis results (for example, for the default branch). Depending on your configuration and choice of analysis tool, future pull requests will be annotated with code scanning analysis results. For more information about GitHub code scanning, check out the documentation. |
|
No description provided.