Skip to content

Commit

Permalink
Merge pull request #10 from Nexus-2023/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
RohitAudit authored Jan 7, 2024
2 parents dd11bed + 9d433ed commit df3f520
Show file tree
Hide file tree
Showing 13 changed files with 256 additions and 20 deletions.
5 changes: 3 additions & 2 deletions contracts/Nexus.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,15 @@ import {BytesArrayLibrary} from "./libraries/BytesArrayLibrary.sol";

/**
* @title Nexus Core Contract
* @author RohitAudit
* @dev This contract is heart and soul of Nexus Network and is used for Operations like
* 1. Onboarding of rollup to Nexus Network
* 2. Change in staking limit for rollup
* 2. Change parameters for rollup
* 3. Whitelisting rollup address
* 4. Submitting keys to rollup bridge
* 5. Submitting keyshares to SSV contract
* 6. Recharge funds in SSV contract for validator operation
* 7. Reward distribution for rollup to DAO and Nexus Fee Contract
* 7. Keep track of validator status and exits
*/
contract Nexus is INexusInterface, Ownable, Proxiable {
using EnumerableSet for EnumerableSet.AddressSet;
Expand Down
30 changes: 30 additions & 0 deletions contracts/NodeOperator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,22 @@ import {Ownable} from "./utils/NexusOwnable.sol";
import {Proxiable} from "./utils/UUPSUpgreadable.sol";
import {INodeOperator} from "./interfaces/INodeOperator.sol";

/**
* @title Nexus Node Operator Contract
* @author RohitAudit
* @dev This contract handles the Node Operator operations which includes:
* 1. Registration of node operators
* 2. Updation of node operators
* 3. Creation of SSV clusters
*
* In future, we will also introduce scoring in the contract itself.
*/
contract NodeOperator is Ownable, Proxiable, INodeOperator{

// This stores the DKG ip needed for DKG ceremony
mapping(uint64=>string) public ssvDKGIP;

// This stores the id of operators in a particular cluster
mapping (uint64=>uint64[]) public ssvClusters;

function initialize() public initilizeOnce {
Expand All @@ -17,20 +30,37 @@ contract NodeOperator is Ownable, Proxiable, INodeOperator{
updateCodeAddress(newImplemetation);
}

/**
* This function is used to register node operators
* @param _operator_id: Operator ID as registered with SSV
* @param _pub_key: Operator public key used for key share creation
* @param _ip_address: DKG IP used for DKG ceremony
* @param name: Name of the operator registered with SSV
*/
function registerSSVOperator(uint64 _operator_id, string calldata _pub_key, string calldata _ip_address, string calldata name) external onlyOwner{
bytes memory ip = bytes(ssvDKGIP[_operator_id]);
if (ip.length != 0) revert OperatorAlreadyRegistered();
ssvDKGIP[_operator_id] = _ip_address;
emit SSVOperatorRegistered(name,_operator_id,_pub_key,_ip_address);
}

/**
* This function is used to update the DKG IP for node operator
* @param _operator_id: Operator ID as registered with SSV
* @param _ip_address: DKG IP used for DKG ceremony
*/
function updateSSVOperatorIP(uint64 _operator_id,string calldata _ip_address) external onlyOwner{
bytes memory ip = bytes(ssvDKGIP[_operator_id]);
if (ip.length == 0) revert OperatorNotRegistered();
ssvDKGIP[_operator_id] = _ip_address;
emit SSVOperatorUpdated(_operator_id,_ip_address);
}

/**
* This function is used to create clusters using node operators
* @param operatorIds: Operator IDs as registered with SSV
* @param clusterId: Cluster ID associated with the cluster
*/
function addCluster(
uint64[] calldata operatorIds,
uint64 clusterId
Expand Down
15 changes: 14 additions & 1 deletion contracts/ValidatorExecutionRewards.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import {Ownable} from "./utils/NexusOwnable.sol";

/**
* @title Validator Execution Reward Contract
* @author RohitAudit
* @dev This contract handles the proposer awards for the validators. As the rewards are associated with particular
* validator one needs to update it in the contract as to who can claim those rewards. The reward bot performs that
* functionality by tracking proposer of the block
*/
contract ValidatorExecutionRewards is Ownable{
struct RollupExecutionReward{
address rollupAdmin;
Expand Down Expand Up @@ -40,6 +46,10 @@ contract ValidatorExecutionRewards is Ownable{
emit ExecutionRewardsReceived(msg.value);
}

/**
* Used for updation of rewards for a particular rollup
* @param rewards: Array of rollups and their rewards earned by their validators
*/
function updateRewardsRollup(RollupExecutionReward[] calldata rewards) external onlyRewardBot {
uint256 total_rewards;
for(uint i=0;i<rewards.length;i++){
Expand All @@ -50,6 +60,9 @@ contract ValidatorExecutionRewards is Ownable{
if (total_rewards>(rewardsEarned-rewardsClaimed)) revert IncorrectRewards();
}

/**
* This function can be used by rollupAdmin to claim the proposer rewards asscociated with their validators
*/
function claimRewards() external {
if (executionRewards[msg.sender] == 0) revert RewardNotPresent();
uint256 amount_to_send = executionRewards[msg.sender];
Expand Down
7 changes: 7 additions & 0 deletions contracts/libraries/BytesArrayLibrary.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

/**
* @title BytesArray Library
* @author RohitAudit
* @dev This library is used for managing bytes array by providing following functionality:
* 1. Removing element from the array
* 2. Adding element to the array
*/
library BytesArrayLibrary {
function addElement(bytes[] storage arr, bytes memory data) internal {
arr.push(data);
Expand Down
1 change: 1 addition & 0 deletions contracts/nexus_bridge/NexusBaseBridge.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {INexusBridge} from "../interfaces/INexusBridge.sol";

/**
* @title Nexus Bridge Contract
* @author RohitAudit
* @dev This contract is used to enable eth staking via native bridge ontract of any rollup. It
* enables the integration with Nexus Network. It also gives permission to Nexus contract to submit
* keys using the unique withdrawal credentials for rollup.
Expand Down
13 changes: 5 additions & 8 deletions contracts/nexus_bridge/NexusBridgeDAO.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,10 @@ pragma solidity ^0.8.19;
import {NexusBaseBridge} from "./NexusBaseBridge.sol";

/**
* @title Nexus Bridge Contract
* @dev This contract is used to enable eth staking via native bridge ontract of any rollup. It
* enables the integration with Nexus Network. It also gives permission to Nexus contract to submit
* keys using the unique withdrawal credentials for rollup.
*
* The staking ratio is maintained by the Nexus Contract and is set during the registration.It
* can be changed anytime by rollup while doing a transaction to the Nexus Contract.
* @title Nexus Bridge DAO Contract
* @author RohitAudit
* @dev This contract enables DAO governing body of the rollup to claim the staking rewards
* from the bridge contract and use it for Ecosystem incentives etc.
*/
abstract contract NexusBridgeDAO is NexusBaseBridge {
uint256 public rewardsClaimed;
Expand All @@ -22,7 +19,7 @@ abstract contract NexusBridgeDAO is NexusBaseBridge {
if (msg.sender != DAO) revert NotDAO();
_;
}

function updateExitedValidators() external override onlyNexus {
if(getRewards() < VALIDATOR_DEPOSIT) revert ValidatorNotExited();
validatorCount -= 1;
Expand Down
11 changes: 4 additions & 7 deletions contracts/nexus_bridge/NexusBridgeUserCValue.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,10 @@ pragma solidity ^0.8.19;
import {NexusBaseBridge} from "./NexusBaseBridge.sol";

/**
* @title Nexus Bridge Contract
* @dev This contract is used to enable eth staking via native bridge ontract of any rollup. It
* enables the integration with Nexus Network. It also gives permission to Nexus contract to submit
* keys using the unique withdrawal credentials for rollup.
*
* The staking ratio is maintained by the Nexus Contract and is set during the registration.It
* can be changed anytime by rollup while doing a transaction to the Nexus Contract.
* @title Nexus Bridge User C value Contract
* @author RohitAudi
* @dev This contract is used to distribute the rewards back to the users by changing the
* token value depending on the rewards earned.
*/
abstract contract NexusBridgeUserCValue is NexusBaseBridge {
uint256 public cValue;
Expand Down
2 changes: 1 addition & 1 deletion contracts/nexus_bridge/NexusBridgeUserRebase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ pragma solidity ^0.8.19;
import {NexusBaseBridge} from "./NexusBaseBridge.sol";

/**
* @title Nexus Bridge Contract
* @title Nexus Bridge Rebase Contract
* @dev This contract is used to enable eth staking via native bridge ontract of any rollup. It
* enables the integration with Nexus Network. It also gives permission to Nexus contract to submit
* keys using the unique withdrawal credentials for rollup.
Expand Down
6 changes: 5 additions & 1 deletion contracts/nexus_bridge/NexusDAIBridge.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@ interface IERC20 {

function approve(address spender, uint256 value) external returns (bool);
}

/**
* @title Nexus DAI contract
* @author RohitAudit
* @dev
*/
abstract contract NexusDai {
uint256 public DAIDeposited;
uint256 public DAIRedeemed;
Expand Down
166 changes: 166 additions & 0 deletions contracts/nexus_bridge/nexusLibrary.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import {IDepositContract} from "../interfaces/IDepositContract.sol";
import {INexusInterface} from "../interfaces/INexusInterface.sol";
import {INexusBridge} from "../interfaces/INexusBridge.sol";

/**
* @title Nexus Tangible Library
* @author RohitAudit
* @dev This is the library contract used by any bridge contract to integrate with Nexus Network without
* adding addittional size to already contract
*/
contract NexusLibrary {
address public constant NEXUS_NETWORK =
0x7610dd2DE44aA3c03313b4c2812C482D86F3a9e7;
address public constant NEXUS_FEE_ADDRESS =
0x735bf02E4435dFADfE47a5FE5FBD42Ef375864A9;

// slot to be calculated = keccak256("NAME_VARIABLE")
bytes32 public constant AMOUNT_DEPOSITED_SLOT =
0xca4e9536f4b6163e8b3c485d13888b64170049f120695cca4a7920674f669123;
bytes32 public constant AMOUNT_WITHDRAWN_SLOT =
0x0727682b75deaf0886514bd82c90f1c6e80521cdb4aeb9ed6f2ada2d5f20f112;
bytes32 public constant AMOUNT_SLASHED_SLOT =
0x67a602d91fdafa346635ea0b2cfecfa87c6c87b3eb52ac04414bcb5fffd82e5f;
bytes32 public constant VALIDATOR_COUNT_SLOT =
0x2d5a8d8ceecd33ab6923979e59fb92c16d966ad0b4d5ecdfb4adac6bafdd0ae5;
bytes32 public constant NEXUS_FEE_PERCENTAGE_SLOT =
0xac871e33a0d6f83ef496541ab4d2cb28c9c72346647360c557889bbd13ec109d;
bytes32 public constant REWARDS_CLAIMED_SLOT =
0x9fbc0f1af8e544d8995616c6f64d9fc6ca8bf8885fb0f08f57738b97334c0f73;

// To be changed to the respective network addresses:
address public constant DAO = 0x14630e0428B9BbA12896402257fa09035f9F7447;
address public constant DEPOSIT_CONTRACT =
0xff50ed3d0ec03aC01D4C79aAd74928BFF48a7b2b;

uint256 public constant VALIDATOR_DEPOSIT = 32 ether;
uint256 public constant BASIS_POINT = 10000;
error NotNexus();
error IncorrectWithdrawalCredentials();
error StakingLimitExceeding();
error IncorrectNexusFee();
error ValidatorNotExited();
error WaitingForValidatorExits();
error NotDAO();

event RewardsRedeemed(uint256 amount);
event SlashingUpdated(uint256 amount);
event NexusFeeChanged(uint256 _nexus_fee);
event NexusRewardsRedeemed(uint256 amount);

modifier onlyNexus() {
if (msg.sender != NEXUS_NETWORK) revert NotNexus();
_;
}

modifier onlyDAO() {
if (msg.sender != DAO) revert NotDAO();
_;
}

function setVariable(bytes32 _slot, uint256 amount) public {
assembly {
sstore(_slot, amount)
}
}

function getVariable(bytes32 _slot) public view returns (uint256) {
uint256 variableValue;
assembly {
variableValue := sload(_slot)
}
return variableValue;
}

function updateExitedValidators() external onlyNexus {
if (getRewards() < VALIDATOR_DEPOSIT) revert ValidatorNotExited();
uint256 validatorCount = getVariable(VALIDATOR_COUNT_SLOT);
validatorCount -= 1;
setVariable(VALIDATOR_COUNT_SLOT,validatorCount);
}

function setNexusFee(uint256 _nexus_fee) external onlyNexus {
if (_nexus_fee > (BASIS_POINT) / 10) revert IncorrectNexusFee();
setVariable(NEXUS_FEE_PERCENTAGE_SLOT, _nexus_fee);
emit NexusFeeChanged(_nexus_fee);
}

function depositValidatorNexus(
INexusInterface.Validator[] calldata _validators,
uint256 stakingLimit
) external onlyNexus {
for (uint i = 0; i < _validators.length; i++) {
bytes memory withdrawalFromCred = _validators[i]
.withdrawalAddress[12:];
if (
keccak256(withdrawalFromCred) !=
keccak256(abi.encodePacked(address(this)))
) revert IncorrectWithdrawalCredentials();
}
uint256 validatorCount = getVariable(VALIDATOR_COUNT_SLOT);
if (
(((validatorCount + _validators.length) *
(VALIDATOR_DEPOSIT) *
BASIS_POINT) /
(address(this).balance +
(validatorCount + _validators.length) *
(VALIDATOR_DEPOSIT))) > stakingLimit
) revert StakingLimitExceeding();

for (uint i = 0; i < _validators.length; i++) {
IDepositContract(DEPOSIT_CONTRACT).deposit{
value: VALIDATOR_DEPOSIT
}(
_validators[i].pubKey,
_validators[i].withdrawalAddress,
_validators[i].signature,
_validators[i].depositRoot
);
}
validatorCount += _validators.length;
}

function validatorsSlashed(uint256 amount) external onlyNexus {
setVariable(AMOUNT_SLASHED_SLOT, amount);
emit SlashingUpdated(amount);
}

function getRewards() public view returns (uint256) {
uint256 validatorCount = getVariable(VALIDATOR_COUNT_SLOT);
uint256 amountDeposited = getVariable(AMOUNT_DEPOSITED_SLOT);
uint256 amountWithdrawn = getVariable(AMOUNT_WITHDRAWN_SLOT);
uint256 slashedAmount = getVariable(AMOUNT_SLASHED_SLOT);
return
(address(this).balance + (validatorCount * VALIDATOR_DEPOSIT)) -
(amountDeposited - amountWithdrawn) -
slashedAmount;
}

function redeemRewards(address reward_account) external onlyDAO {
uint256 total_rewards = getRewards();
if (total_rewards > VALIDATOR_DEPOSIT)
revert WaitingForValidatorExits();
uint256 NexusFeePercentage = getVariable(NEXUS_FEE_PERCENTAGE_SLOT);
uint256 _nexus_rewards = (NexusFeePercentage * total_rewards) /
BASIS_POINT;
(bool nexus_success, bytes memory nexus_data) = NEXUS_FEE_ADDRESS.call{
value: _nexus_rewards,
gas: 5000
}("");
if (nexus_success) {
emit NexusRewardsRedeemed(_nexus_rewards);
}
(bool dao_success, bytes memory dao_data) = reward_account.call{
value: (total_rewards - _nexus_rewards),
gas: 5000
}("");
uint256 rewardsClaimed = getVariable(REWARDS_CLAIMED_SLOT);
rewardsClaimed += total_rewards;
setVariable(REWARDS_CLAIMED_SLOT, rewardsClaimed);
if (dao_success) {
emit RewardsRedeemed((total_rewards - _nexus_rewards));
}
}
}
9 changes: 9 additions & 0 deletions contracts/utils/NexusOwnable.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

/**
* @title Ownable Contract
* @author RohitAudit
* @dev This contract is used to implement ownable features to the contracts
*/
contract Ownable {
address private owner;
bool private initialized = false;
Expand All @@ -27,6 +32,10 @@ contract Ownable {
initialized = true;
}

/**
* This function transfers the ownership of the contract
* @param newOwner New Owner of the contract
*/
function transferOwnership(address newOwner) external onlyOwner{
emit OwnerChanged(owner, newOwner);
owner = newOwner;
Expand Down
Loading

0 comments on commit df3f520

Please sign in to comment.