编译器
0.8.18+commit.87f61d96
文件 1 的 31:AddressSetStorageInterface.sol
pragma solidity >0.5.0 <0.9.0;
interface AddressSetStorageInterface {
function getCount(bytes32 _key) external view returns (uint);
function getItem(bytes32 _key, uint _index) external view returns (address);
function getIndexOf(bytes32 _key, address _value) external view returns (int);
function addItem(bytes32 _key, address _value) external;
function removeItem(bytes32 _key, address _value) external;
}
文件 2 的 31:IERC20.sol
pragma solidity >0.5.0 <0.9.0;
interface IERC20 {
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address from, address to, uint256 amount) external returns (bool);
}
文件 3 的 31:IERC20Burnable.sol
import "./IERC20.sol";
pragma solidity >0.5.0 <0.9.0;
interface IERC20Burnable is IERC20 {
function burn(uint256 amount) external;
function burnFrom(address account, uint256 amount) external;
}
文件 4 的 31:Math.sol
pragma solidity ^0.8.0;
library Math {
enum Rounding {
Down,
Up,
Zero
}
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
function average(uint256 a, uint256 b) internal pure returns (uint256) {
return (a & b) + (a ^ b) / 2;
}
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
return a == 0 ? 0 : (a - 1) / b + 1;
}
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
uint256 prod0;
uint256 prod1;
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
if (prod1 == 0) {
return prod0 / denominator;
}
require(denominator > prod1, "Math: mulDiv overflow");
uint256 remainder;
assembly {
remainder := mulmod(x, y, denominator)
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
uint256 twos = denominator & (~denominator + 1);
assembly {
denominator := div(denominator, twos)
prod0 := div(prod0, twos)
twos := add(div(sub(0, twos), twos), 1)
}
prod0 |= prod1 * twos;
uint256 inverse = (3 * denominator) ^ 2;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
result = prod0 * inverse;
return result;
}
}
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 result = 1 << (log2(a) >> 1);
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
}
}
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
}
}
}
文件 5 的 31:MinipoolDeposit.sol
pragma solidity >0.5.0 <0.9.0;
enum MinipoolDeposit {
None,
Full,
Half,
Empty,
Variable
}
文件 6 的 31:MinipoolDetails.sol
pragma solidity >0.5.0 <0.9.0;
import "./MinipoolDeposit.sol";
import "./MinipoolStatus.sol";
struct MinipoolDetails {
bool exists;
address minipoolAddress;
bytes pubkey;
MinipoolStatus status;
uint256 statusBlock;
uint256 statusTime;
bool finalised;
MinipoolDeposit depositType;
uint256 nodeFee;
uint256 nodeDepositBalance;
bool nodeDepositAssigned;
uint256 userDepositBalance;
bool userDepositAssigned;
uint256 userDepositAssignedTime;
bool useLatestDelegate;
address delegate;
address previousDelegate;
address effectiveDelegate;
uint256 penaltyCount;
uint256 penaltyRate;
address nodeAddress;
}
文件 7 的 31:MinipoolStatus.sol
pragma solidity >0.5.0 <0.9.0;
enum MinipoolStatus {
Initialised,
Prelaunch,
Staking,
Withdrawable,
Dissolved
}
文件 8 的 31:NodeDetails.sol
pragma solidity >0.5.0 <0.9.0;
struct NodeDetails {
bool exists;
uint256 registrationTime;
string timezoneLocation;
bool feeDistributorInitialised;
address feeDistributorAddress;
uint256 rewardNetwork;
uint256 rplStake;
uint256 effectiveRPLStake;
uint256 minimumRPLStake;
uint256 maximumRPLStake;
uint256 ethMatched;
uint256 ethMatchedLimit;
uint256 minipoolCount;
uint256 balanceETH;
uint256 balanceRETH;
uint256 balanceRPL;
uint256 balanceOldRPL;
uint256 depositCreditBalance;
uint256 distributorBalanceUserETH;
uint256 distributorBalanceNodeETH;
address withdrawalAddress;
address pendingWithdrawalAddress;
bool smoothingPoolRegistrationState;
uint256 smoothingPoolRegistrationChanged;
address nodeAddress;
}
文件 9 的 31:RocketBase.sol
pragma solidity >0.5.0 <0.9.0;
import "../interface/RocketStorageInterface.sol";
abstract contract RocketBase {
uint256 constant calcBase = 1 ether;
uint8 public version;
RocketStorageInterface rocketStorage = RocketStorageInterface(address(0));
modifier onlyLatestNetworkContract() {
require(getBool(keccak256(abi.encodePacked("contract.exists", msg.sender))), "Invalid or outdated network contract");
_;
}
modifier onlyLatestContract(string memory _contractName, address _contractAddress) {
require(_contractAddress == getAddress(keccak256(abi.encodePacked("contract.address", _contractName))), "Invalid or outdated contract");
_;
}
modifier onlyRegisteredNode(address _nodeAddress) {
require(getBool(keccak256(abi.encodePacked("node.exists", _nodeAddress))), "Invalid node");
_;
}
modifier onlyTrustedNode(address _nodeAddress) {
require(getBool(keccak256(abi.encodePacked("dao.trustednodes.", "member", _nodeAddress))), "Invalid trusted node");
_;
}
modifier onlyRegisteredMinipool(address _minipoolAddress) {
require(getBool(keccak256(abi.encodePacked("minipool.exists", _minipoolAddress))), "Invalid minipool");
_;
}
modifier onlyGuardian() {
require(msg.sender == rocketStorage.getGuardian(), "Account is not a temporary guardian");
_;
}
constructor(RocketStorageInterface _rocketStorageAddress) {
rocketStorage = RocketStorageInterface(_rocketStorageAddress);
}
function getContractAddress(string memory _contractName) internal view returns (address) {
address contractAddress = getAddress(keccak256(abi.encodePacked("contract.address", _contractName)));
require(contractAddress != address(0x0), "Contract not found");
return contractAddress;
}
function getContractAddressUnsafe(string memory _contractName) internal view returns (address) {
address contractAddress = getAddress(keccak256(abi.encodePacked("contract.address", _contractName)));
return contractAddress;
}
function getContractName(address _contractAddress) internal view returns (string memory) {
string memory contractName = getString(keccak256(abi.encodePacked("contract.name", _contractAddress)));
require(bytes(contractName).length > 0, "Contract not found");
return contractName;
}
function getRevertMsg(bytes memory _returnData) internal pure returns (string memory) {
if (_returnData.length < 68) return "Transaction reverted silently";
assembly {
_returnData := add(_returnData, 0x04)
}
return abi.decode(_returnData, (string));
}
function getAddress(bytes32 _key) internal view returns (address) { return rocketStorage.getAddress(_key); }
function getUint(bytes32 _key) internal view returns (uint) { return rocketStorage.getUint(_key); }
function getString(bytes32 _key) internal view returns (string memory) { return rocketStorage.getString(_key); }
function getBytes(bytes32 _key) internal view returns (bytes memory) { return rocketStorage.getBytes(_key); }
function getBool(bytes32 _key) internal view returns (bool) { return rocketStorage.getBool(_key); }
function getInt(bytes32 _key) internal view returns (int) { return rocketStorage.getInt(_key); }
function getBytes32(bytes32 _key) internal view returns (bytes32) { return rocketStorage.getBytes32(_key); }
function setAddress(bytes32 _key, address _value) internal { rocketStorage.setAddress(_key, _value); }
function setUint(bytes32 _key, uint _value) internal { rocketStorage.setUint(_key, _value); }
function setString(bytes32 _key, string memory _value) internal { rocketStorage.setString(_key, _value); }
function setBytes(bytes32 _key, bytes memory _value) internal { rocketStorage.setBytes(_key, _value); }
function setBool(bytes32 _key, bool _value) internal { rocketStorage.setBool(_key, _value); }
function setInt(bytes32 _key, int _value) internal { rocketStorage.setInt(_key, _value); }
function setBytes32(bytes32 _key, bytes32 _value) internal { rocketStorage.setBytes32(_key, _value); }
function deleteAddress(bytes32 _key) internal { rocketStorage.deleteAddress(_key); }
function deleteUint(bytes32 _key) internal { rocketStorage.deleteUint(_key); }
function deleteString(bytes32 _key) internal { rocketStorage.deleteString(_key); }
function deleteBytes(bytes32 _key) internal { rocketStorage.deleteBytes(_key); }
function deleteBool(bytes32 _key) internal { rocketStorage.deleteBool(_key); }
function deleteInt(bytes32 _key) internal { rocketStorage.deleteInt(_key); }
function deleteBytes32(bytes32 _key) internal { rocketStorage.deleteBytes32(_key); }
function addUint(bytes32 _key, uint256 _amount) internal { rocketStorage.addUint(_key, _amount); }
function subUint(bytes32 _key, uint256 _amount) internal { rocketStorage.subUint(_key, _amount); }
}
文件 10 的 31:RocketDAONodeTrustedInterface.sol
pragma solidity >0.5.0 <0.9.0;
interface RocketDAONodeTrustedInterface {
function getBootstrapModeDisabled() external view returns (bool);
function getMemberQuorumVotesRequired() external view returns (uint256);
function getMemberAt(uint256 _index) external view returns (address);
function getMemberCount() external view returns (uint256);
function getMemberMinRequired() external view returns (uint256);
function getMemberIsValid(address _nodeAddress) external view returns (bool);
function getMemberLastProposalTime(address _nodeAddress) external view returns (uint256);
function getMemberID(address _nodeAddress) external view returns (string memory);
function getMemberUrl(address _nodeAddress) external view returns (string memory);
function getMemberJoinedTime(address _nodeAddress) external view returns (uint256);
function getMemberProposalExecutedTime(string memory _proposalType, address _nodeAddress) external view returns (uint256);
function getMemberRPLBondAmount(address _nodeAddress) external view returns (uint256);
function getMemberIsChallenged(address _nodeAddress) external view returns (bool);
function getMemberUnbondedValidatorCount(address _nodeAddress) external view returns (uint256);
function incrementMemberUnbondedValidatorCount(address _nodeAddress) external;
function decrementMemberUnbondedValidatorCount(address _nodeAddress) external;
function bootstrapMember(string memory _id, string memory _url, address _nodeAddress) external;
function bootstrapSettingUint(string memory _settingContractName, string memory _settingPath, uint256 _value) external;
function bootstrapSettingBool(string memory _settingContractName, string memory _settingPath, bool _value) external;
function bootstrapUpgrade(string memory _type, string memory _name, string memory _contractAbi, address _contractAddress) external;
function bootstrapDisable(bool _confirmDisableBootstrapMode) external;
function memberJoinRequired(string memory _id, string memory _url) external;
}
文件 11 的 31:RocketDAOProtocolSettingsMinipoolInterface.sol
pragma solidity >0.5.0 <0.9.0;
import "../../../../types/MinipoolDeposit.sol";
interface RocketDAOProtocolSettingsMinipoolInterface {
function getLaunchBalance() external view returns (uint256);
function getPreLaunchValue() external pure returns (uint256);
function getDepositUserAmount(MinipoolDeposit _depositType) external view returns (uint256);
function getFullDepositUserAmount() external view returns (uint256);
function getHalfDepositUserAmount() external view returns (uint256);
function getVariableDepositAmount() external view returns (uint256);
function getSubmitWithdrawableEnabled() external view returns (bool);
function getBondReductionEnabled() external view returns (bool);
function getLaunchTimeout() external view returns (uint256);
function getMaximumCount() external view returns (uint256);
function isWithinUserDistributeWindow(uint256 _time) external view returns (bool);
function hasUserDistributeWindowPassed(uint256 _time) external view returns (bool);
function getUserDistributeWindowStart() external view returns (uint256);
function getUserDistributeWindowLength() external view returns (uint256);
}
文件 12 的 31:RocketDAOProtocolSettingsNodeInterface.sol
pragma solidity >0.5.0 <0.9.0;
interface RocketDAOProtocolSettingsNodeInterface {
function getRegistrationEnabled() external view returns (bool);
function getSmoothingPoolRegistrationEnabled() external view returns (bool);
function getDepositEnabled() external view returns (bool);
function getVacantMinipoolsEnabled() external view returns (bool);
function getMinimumPerMinipoolStake() external view returns (uint256);
function getMaximumPerMinipoolStake() external view returns (uint256);
function getMaximumStakeForVotingPower() external view returns (uint256);
}
文件 13 的 31:RocketDAOProtocolSettingsRewardsInterface.sol
pragma solidity >0.5.0 <0.9.0;
interface RocketDAOProtocolSettingsRewardsInterface {
function setSettingRewardsClaimers(uint256 _trustedNodePercent, uint256 _protocolPercent, uint256 _nodePercent) external;
function getRewardsClaimerPerc(string memory _contractName) external view returns (uint256);
function getRewardsClaimersPerc() external view returns (uint256 _trustedNodePercent, uint256 _protocolPercent, uint256 _nodePercent);
function getRewardsClaimersTrustedNodePerc() external view returns (uint256);
function getRewardsClaimersProtocolPerc() external view returns (uint256);
function getRewardsClaimersNodePerc() external view returns (uint256);
function getRewardsClaimersTimeUpdated() external view returns (uint256);
function getRewardsClaimIntervalPeriods() external view returns (uint256);
function getRewardsClaimIntervalTime() external view returns (uint256);
}
文件 14 的 31:RocketMinipoolFactoryInterface.sol
pragma solidity >0.5.0 <0.9.0;
import "../../types/MinipoolDeposit.sol";
interface RocketMinipoolFactoryInterface {
function getExpectedAddress(address _nodeAddress, uint256 _salt) external view returns (address);
function deployContract(address _nodeAddress, uint256 _salt) external returns (address);
}
文件 15 的 31:RocketMinipoolInterface.sol
pragma solidity >0.5.0 <0.9.0;
import "../../types/MinipoolDeposit.sol";
import "../../types/MinipoolStatus.sol";
import "../RocketStorageInterface.sol";
interface RocketMinipoolInterface {
function version() external view returns (uint8);
function initialise(address _nodeAddress) external;
function getStatus() external view returns (MinipoolStatus);
function getFinalised() external view returns (bool);
function getStatusBlock() external view returns (uint256);
function getStatusTime() external view returns (uint256);
function getScrubVoted(address _member) external view returns (bool);
function getDepositType() external view returns (MinipoolDeposit);
function getNodeAddress() external view returns (address);
function getNodeFee() external view returns (uint256);
function getNodeDepositBalance() external view returns (uint256);
function getNodeRefundBalance() external view returns (uint256);
function getNodeDepositAssigned() external view returns (bool);
function getPreLaunchValue() external view returns (uint256);
function getNodeTopUpValue() external view returns (uint256);
function getVacant() external view returns (bool);
function getPreMigrationBalance() external view returns (uint256);
function getUserDistributed() external view returns (bool);
function getUserDepositBalance() external view returns (uint256);
function getUserDepositAssigned() external view returns (bool);
function getUserDepositAssignedTime() external view returns (uint256);
function getTotalScrubVotes() external view returns (uint256);
function calculateNodeShare(uint256 _balance) external view returns (uint256);
function calculateUserShare(uint256 _balance) external view returns (uint256);
function preDeposit(uint256 _bondingValue, bytes calldata _validatorPubkey, bytes calldata _validatorSignature, bytes32 _depositDataRoot) external payable;
function deposit() external payable;
function userDeposit() external payable;
function distributeBalance(bool _rewardsOnly) external;
function beginUserDistribute() external;
function userDistributeAllowed() external view returns (bool);
function refund() external;
function slash() external;
function finalise() external;
function canStake() external view returns (bool);
function canPromote() external view returns (bool);
function stake(bytes calldata _validatorSignature, bytes32 _depositDataRoot) external;
function prepareVacancy(uint256 _bondAmount, uint256 _currentBalance) external;
function promote() external;
function dissolve() external;
function close() external;
function voteScrub() external;
function reduceBondAmount() external;
}
文件 16 的 31:RocketMinipoolManager.sol
pragma solidity 0.8.18;
pragma abicoder v2;
import "../RocketBase.sol";
import "../../types/MinipoolStatus.sol";
import "../../types/MinipoolDeposit.sol";
import "../../types/MinipoolDetails.sol";
import "../../interface/dao/node/RocketDAONodeTrustedInterface.sol";
import "../../interface/minipool/RocketMinipoolInterface.sol";
import "../../interface/minipool/RocketMinipoolManagerInterface.sol";
import "../../interface/node/RocketNodeStakingInterface.sol";
import "../../interface/util/AddressSetStorageInterface.sol";
import "../../interface/node/RocketNodeManagerInterface.sol";
import "../../interface/network/RocketNetworkPricesInterface.sol";
import "../../interface/dao/protocol/settings/RocketDAOProtocolSettingsMinipoolInterface.sol";
import "../../interface/dao/protocol/settings/RocketDAOProtocolSettingsNodeInterface.sol";
import "../../interface/dao/protocol/settings/RocketDAOProtocolSettingsNodeInterface.sol";
import "../../interface/minipool/RocketMinipoolFactoryInterface.sol";
import "../../interface/node/RocketNodeDistributorFactoryInterface.sol";
import "../../interface/node/RocketNodeDistributorInterface.sol";
import "../../interface/network/RocketNetworkPenaltiesInterface.sol";
import "../../interface/minipool/RocketMinipoolPenaltyInterface.sol";
import "../../interface/node/RocketNodeDepositInterface.sol";
import "../network/RocketNetworkSnapshots.sol";
import "../node/RocketNodeStaking.sol";
contract RocketMinipoolManager is RocketBase, RocketMinipoolManagerInterface {
event MinipoolCreated(address indexed minipool, address indexed node, uint256 time);
event MinipoolDestroyed(address indexed minipool, address indexed node, uint256 time);
event BeginBondReduction(address indexed minipool, uint256 time);
event CancelReductionVoted(address indexed minipool, address indexed member, uint256 time);
event ReductionCancelled(address indexed minipool, uint256 time);
constructor(RocketStorageInterface _rocketStorageAddress) RocketBase(_rocketStorageAddress) {
version = 5;
}
function getMinipoolCount() override public view returns (uint256) {
AddressSetStorageInterface addressSetStorage = AddressSetStorageInterface(getContractAddress("addressSetStorage"));
return addressSetStorage.getCount(keccak256(bytes("minipools.index")));
}
function getStakingMinipoolCount() override public view returns (uint256) {
return getUint(keccak256(bytes("minipools.staking.count")));
}
function getFinalisedMinipoolCount() override external view returns (uint256) {
return getUint(keccak256(bytes("minipools.finalised.count")));
}
function getActiveMinipoolCount() override public view returns (uint256) {
AddressSetStorageInterface addressSetStorage = AddressSetStorageInterface(getContractAddress("addressSetStorage"));
uint256 total = addressSetStorage.getCount(keccak256(bytes("minipools.index")));
uint256 finalised = getUint(keccak256(bytes("minipools.finalised.count")));
return total - finalised;
}
function getMinipoolRPLSlashed(address _minipoolAddress) override external view returns (bool) {
return getBool(keccak256(abi.encodePacked("minipool.rpl.slashed", _minipoolAddress)));
}
function getMinipoolCountPerStatus(uint256 _offset, uint256 _limit) override external view
returns (uint256 initialisedCount, uint256 prelaunchCount, uint256 stakingCount, uint256 withdrawableCount, uint256 dissolvedCount) {
AddressSetStorageInterface addressSetStorage = AddressSetStorageInterface(getContractAddress("addressSetStorage"));
bytes32 minipoolKey = keccak256(abi.encodePacked("minipools.index"));
uint256 totalMinipools = getMinipoolCount();
uint256 max = _offset + _limit;
if (max > totalMinipools || _limit == 0) { max = totalMinipools; }
for (uint256 i = _offset; i < max; ++i) {
RocketMinipoolInterface minipool = RocketMinipoolInterface(addressSetStorage.getItem(minipoolKey, i));
MinipoolStatus status = minipool.getStatus();
if (status == MinipoolStatus.Initialised) {
initialisedCount++;
}
else if (status == MinipoolStatus.Prelaunch) {
prelaunchCount++;
}
else if (status == MinipoolStatus.Staking) {
stakingCount++;
}
else if (status == MinipoolStatus.Withdrawable) {
withdrawableCount++;
}
else if (status == MinipoolStatus.Dissolved) {
dissolvedCount++;
}
}
}
function getPrelaunchMinipools(uint256 _offset, uint256 _limit) override external view
returns (address[] memory) {
AddressSetStorageInterface addressSetStorage = AddressSetStorageInterface(getContractAddress("addressSetStorage"));
bytes32 minipoolKey = keccak256(abi.encodePacked("minipools.index"));
uint256 totalMinipools = getMinipoolCount();
uint256 max = _offset + _limit;
if (max > totalMinipools || _limit == 0) { max = totalMinipools; }
address[] memory minipools = new address[](max - _offset);
uint256 total = 0;
for (uint256 i = _offset; i < max; ++i) {
RocketMinipoolInterface minipool = RocketMinipoolInterface(addressSetStorage.getItem(minipoolKey, i));
MinipoolStatus status = minipool.getStatus();
if (status == MinipoolStatus.Prelaunch) {
minipools[total] = address(minipool);
total++;
}
}
assembly {
mstore(minipools, total)
}
return minipools;
}
function getMinipoolAt(uint256 _index) override external view returns (address) {
AddressSetStorageInterface addressSetStorage = AddressSetStorageInterface(getContractAddress("addressSetStorage"));
return addressSetStorage.getItem(keccak256(abi.encodePacked("minipools.index")), _index);
}
function getNodeMinipoolCount(address _nodeAddress) override external view returns (uint256) {
AddressSetStorageInterface addressSetStorage = AddressSetStorageInterface(getContractAddress("addressSetStorage"));
return addressSetStorage.getCount(keccak256(abi.encodePacked("node.minipools.index", _nodeAddress)));
}
function getNodeActiveMinipoolCount(address _nodeAddress) override public view returns (uint256) {
bytes32 key = keccak256(abi.encodePacked("minipools.active.count", _nodeAddress));
RocketNetworkSnapshotsInterface rocketNetworkSnapshots = RocketNetworkSnapshotsInterface(getContractAddress("rocketNetworkSnapshots"));
(bool exists,, uint224 count) = rocketNetworkSnapshots.latest(key);
if (!exists){
AddressSetStorageInterface addressSetStorage = AddressSetStorageInterface(getContractAddress("addressSetStorage"));
uint256 finalised = getUint(keccak256(abi.encodePacked("node.minipools.finalised.count", _nodeAddress)));
uint256 total = addressSetStorage.getCount(keccak256(abi.encodePacked("node.minipools.index", _nodeAddress)));
return total - finalised;
}
return uint256(count);
}
function getNodeFinalisedMinipoolCount(address _nodeAddress) override external view returns (uint256) {
return getUint(keccak256(abi.encodePacked("node.minipools.finalised.count", _nodeAddress)));
}
function getNodeStakingMinipoolCount(address _nodeAddress) override public view returns (uint256) {
RocketNodeDepositInterface rocketNodeDeposit = RocketNodeDepositInterface(getContractAddress("rocketNodeDeposit"));
uint256[] memory depositSizes = rocketNodeDeposit.getDepositAmounts();
uint256 total;
for (uint256 i = 0; i < depositSizes.length; ++i){
total = total + getNodeStakingMinipoolCountBySize(_nodeAddress, depositSizes[i]);
}
return total;
}
function getNodeStakingMinipoolCountBySize(address _nodeAddress, uint256 _depositSize) override public view returns (uint256) {
bytes32 nodeKey;
if (_depositSize == 16 ether){
nodeKey = keccak256(abi.encodePacked("node.minipools.staking.count", _nodeAddress));
} else {
nodeKey = keccak256(abi.encodePacked("node.minipools.staking.count", _nodeAddress, _depositSize));
}
return getUint(nodeKey);
}
function getNodeMinipoolAt(address _nodeAddress, uint256 _index) override external view returns (address) {
AddressSetStorageInterface addressSetStorage = AddressSetStorageInterface(getContractAddress("addressSetStorage"));
return addressSetStorage.getItem(keccak256(abi.encodePacked("node.minipools.index", _nodeAddress)), _index);
}
function getNodeValidatingMinipoolCount(address _nodeAddress) override external view returns (uint256) {
AddressSetStorageInterface addressSetStorage = AddressSetStorageInterface(getContractAddress("addressSetStorage"));
return addressSetStorage.getCount(keccak256(abi.encodePacked("node.minipools.validating.index", _nodeAddress)));
}
function getNodeValidatingMinipoolAt(address _nodeAddress, uint256 _index) override external view returns (address) {
AddressSetStorageInterface addressSetStorage = AddressSetStorageInterface(getContractAddress("addressSetStorage"));
return addressSetStorage.getItem(keccak256(abi.encodePacked("node.minipools.validating.index", _nodeAddress)), _index);
}
function getMinipoolByPubkey(bytes memory _pubkey) override public view returns (address) {
return getAddress(keccak256(abi.encodePacked("validator.minipool", _pubkey)));
}
function getMinipoolExists(address _minipoolAddress) override public view returns (bool) {
return getBool(keccak256(abi.encodePacked("minipool.exists", _minipoolAddress)));
}
function getMinipoolDestroyed(address _minipoolAddress) override external view returns (bool) {
return getBool(keccak256(abi.encodePacked("minipool.destroyed", _minipoolAddress)));
}
function getMinipoolPubkey(address _minipoolAddress) override public view returns (bytes memory) {
return getBytes(keccak256(abi.encodePacked("minipool.pubkey", _minipoolAddress)));
}
function getMinipoolWithdrawalCredentials(address _minipoolAddress) override public pure returns (bytes memory) {
return abi.encodePacked(bytes1(0x01), bytes11(0x0), address(_minipoolAddress));
}
function updateNodeStakingMinipoolCount(uint256 _previousBond, uint256 _newBond, uint256 _previousFee, uint256 _newFee) override external onlyLatestContract("rocketMinipoolManager", address(this)) onlyRegisteredMinipool(msg.sender) {
bytes32 nodeKey;
bytes32 numeratorKey;
RocketMinipoolInterface minipool = RocketMinipoolInterface(msg.sender);
address nodeAddress = minipool.getNodeAddress();
_tryDistribute(nodeAddress);
if (_previousBond == 16 ether){
nodeKey = keccak256(abi.encodePacked("node.minipools.staking.count", nodeAddress));
numeratorKey = keccak256(abi.encodePacked("node.average.fee.numerator", nodeAddress));
} else {
nodeKey = keccak256(abi.encodePacked("node.minipools.staking.count", nodeAddress, _previousBond));
numeratorKey = keccak256(abi.encodePacked("node.average.fee.numerator", nodeAddress, _previousBond));
}
subUint(nodeKey, 1);
subUint(numeratorKey, _previousFee);
if (_newBond == 16 ether){
nodeKey = keccak256(abi.encodePacked("node.minipools.staking.count", nodeAddress));
numeratorKey = keccak256(abi.encodePacked("node.average.fee.numerator", nodeAddress));
} else {
nodeKey = keccak256(abi.encodePacked("node.minipools.staking.count", nodeAddress, _newBond));
numeratorKey = keccak256(abi.encodePacked("node.average.fee.numerator", nodeAddress, _newBond));
}
addUint(nodeKey, 1);
addUint(numeratorKey, _newFee);
}
function incrementNodeStakingMinipoolCount(address _nodeAddress) override external onlyLatestContract("rocketMinipoolManager", address(this)) onlyRegisteredMinipool(msg.sender) {
RocketMinipoolInterface minipool = RocketMinipoolInterface(msg.sender);
_tryDistribute(_nodeAddress);
uint256 depositSize = minipool.getNodeDepositBalance();
bytes32 nodeKey;
bytes32 numeratorKey;
if (depositSize == 16 ether){
nodeKey = keccak256(abi.encodePacked("node.minipools.staking.count", _nodeAddress));
numeratorKey = keccak256(abi.encodePacked("node.average.fee.numerator", _nodeAddress));
} else {
nodeKey = keccak256(abi.encodePacked("node.minipools.staking.count", _nodeAddress, depositSize));
numeratorKey = keccak256(abi.encodePacked("node.average.fee.numerator", _nodeAddress, depositSize));
}
uint256 nodeValue = getUint(nodeKey);
setUint(nodeKey, nodeValue + 1);
bytes32 totalKey = keccak256(abi.encodePacked("minipools.staking.count"));
uint256 totalValue = getUint(totalKey);
setUint(totalKey, totalValue + 1);
addUint(numeratorKey, minipool.getNodeFee());
}
function decrementNodeStakingMinipoolCount(address _nodeAddress) override external onlyLatestContract("rocketMinipoolManager", address(this)) onlyRegisteredMinipool(msg.sender) {
RocketMinipoolInterface minipool = RocketMinipoolInterface(msg.sender);
_tryDistribute(_nodeAddress);
uint256 depositSize = minipool.getNodeDepositBalance();
bytes32 nodeKey;
bytes32 numeratorKey;
if (depositSize == 16 ether){
nodeKey = keccak256(abi.encodePacked("node.minipools.staking.count", _nodeAddress));
numeratorKey = keccak256(abi.encodePacked("node.average.fee.numerator", _nodeAddress));
} else {
nodeKey = keccak256(abi.encodePacked("node.minipools.staking.count", _nodeAddress, depositSize));
numeratorKey = keccak256(abi.encodePacked("node.average.fee.numerator", _nodeAddress, depositSize));
}
uint256 nodeValue = getUint(nodeKey);
setUint(nodeKey, nodeValue - 1);
bytes32 totalKey = keccak256(abi.encodePacked("minipools.staking.count"));
uint256 totalValue = getUint(totalKey);
setUint(totalKey, totalValue - 1);
subUint(numeratorKey, minipool.getNodeFee());
}
function tryDistribute(address _nodeAddress) override external {
_tryDistribute(_nodeAddress);
}
function _tryDistribute(address _nodeAddress) internal {
RocketNodeDistributorFactoryInterface rocketNodeDistributorFactory = RocketNodeDistributorFactoryInterface(getContractAddress("rocketNodeDistributorFactory"));
address distributorAddress = rocketNodeDistributorFactory.getProxyAddress(_nodeAddress);
if (distributorAddress.balance > 0) {
RocketNodeManagerInterface rocketNodeManager = RocketNodeManagerInterface(getContractAddress("rocketNodeManager"));
require(rocketNodeManager.getFeeDistributorInitialised(_nodeAddress), "Distributor not initialised");
RocketNodeDistributorInterface distributor = RocketNodeDistributorInterface(distributorAddress);
distributor.distribute();
}
}
function incrementNodeFinalisedMinipoolCount(address _nodeAddress) override external onlyLatestContract("rocketMinipoolManager", address(this)) onlyRegisteredMinipool(msg.sender) {
uint256 activeMinipoolCount = getNodeActiveMinipoolCount(_nodeAddress);
bytes32 finalisedKey = keccak256(abi.encodePacked("node.minipools.finalised", msg.sender));
require(!getBool(finalisedKey), "Minipool has already been finalised");
setBool(finalisedKey, true);
RocketNodeStakingInterface rocketNodeStaking = RocketNodeStakingInterface(getContractAddress("rocketNodeStaking"));
uint256 ethMatched = rocketNodeStaking.getNodeETHMatched(_nodeAddress);
addUint(keccak256(abi.encodePacked("node.minipools.finalised.count", _nodeAddress)), 1);
addUint(keccak256(bytes("minipools.finalised.count")), 1);
RocketNetworkSnapshots rocketNetworkSnapshots = RocketNetworkSnapshots(getContractAddress("rocketNetworkSnapshots"));
ethMatched -= RocketMinipoolInterface(msg.sender).getUserDepositBalance();
bytes32 key = keccak256(abi.encodePacked("eth.matched.node.amount", _nodeAddress));
rocketNetworkSnapshots.push(key, uint224(ethMatched));
key = keccak256(abi.encodePacked("minipools.active.count", _nodeAddress));
rocketNetworkSnapshots.push(key, uint224(activeMinipoolCount - 1));
}
function createMinipool(address _nodeAddress, uint256 _salt) override public onlyLatestContract("rocketMinipoolManager", address(this)) onlyLatestContract("rocketNodeDeposit", msg.sender) returns (RocketMinipoolInterface) {
AddressSetStorageInterface addressSetStorage = AddressSetStorageInterface(getContractAddress("addressSetStorage"));
{
RocketDAOProtocolSettingsMinipoolInterface rocketDAOProtocolSettingsMinipool = RocketDAOProtocolSettingsMinipoolInterface(getContractAddress("rocketDAOProtocolSettingsMinipool"));
uint256 totalActiveMinipoolCount = getActiveMinipoolCount();
require(totalActiveMinipoolCount + 1 <= rocketDAOProtocolSettingsMinipool.getMaximumCount(), "Global minipool limit reached");
}
uint256 activeMinipoolCount = getNodeActiveMinipoolCount(_nodeAddress);
address contractAddress = deployContract(_nodeAddress, _salt);
setBool(keccak256(abi.encodePacked("minipool.exists", contractAddress)), true);
addressSetStorage.addItem(keccak256(abi.encodePacked("minipools.index")), contractAddress);
addressSetStorage.addItem(keccak256(abi.encodePacked("node.minipools.index", _nodeAddress)), contractAddress);
RocketNetworkSnapshots rocketNetworkSnapshots = RocketNetworkSnapshots(getContractAddress("rocketNetworkSnapshots"));
bytes32 key = keccak256(abi.encodePacked("minipools.active.count", _nodeAddress));
rocketNetworkSnapshots.push(key, uint224(activeMinipoolCount + 1));
emit MinipoolCreated(contractAddress, _nodeAddress, block.timestamp);
return RocketMinipoolInterface(contractAddress);
}
function createVacantMinipool(address _nodeAddress, uint256 _salt, bytes calldata _validatorPubkey, uint256 _bondAmount, uint256 _currentBalance) override external onlyLatestContract("rocketMinipoolManager", address(this)) onlyLatestContract("rocketNodeDeposit", msg.sender) returns (RocketMinipoolInterface) {
AddressSetStorageInterface addressSetStorage = AddressSetStorageInterface(getContractAddress("addressSetStorage"));
RocketMinipoolInterface minipool = createMinipool(_nodeAddress, _salt);
minipool.prepareVacancy(_bondAmount, _currentBalance);
_setMinipoolPubkey(address(minipool), _validatorPubkey);
addressSetStorage.addItem(keccak256(abi.encodePacked("minipools.vacant.index")), address(minipool));
return minipool;
}
function removeVacantMinipool() override external onlyLatestContract("rocketMinipoolManager", address(this)) onlyRegisteredMinipool(msg.sender) {
AddressSetStorageInterface addressSetStorage = AddressSetStorageInterface(getContractAddress("addressSetStorage"));
addressSetStorage.removeItem(keccak256(abi.encodePacked("minipools.vacant.index")), msg.sender);
RocketMinipoolInterface minipool = RocketMinipoolInterface(msg.sender);
if (minipool.getStatus() == MinipoolStatus.Dissolved) {
bytes memory pubkey = getMinipoolPubkey(msg.sender);
deleteAddress(keccak256(abi.encodePacked("validator.minipool", pubkey)));
}
}
function getVacantMinipoolCount() override external view returns (uint256) {
AddressSetStorageInterface addressSetStorage = AddressSetStorageInterface(getContractAddress("addressSetStorage"));
return addressSetStorage.getCount(keccak256(abi.encodePacked("minipools.vacant.index")));
}
function getVacantMinipoolAt(uint256 _index) override external view returns (address) {
AddressSetStorageInterface addressSetStorage = AddressSetStorageInterface(getContractAddress("addressSetStorage"));
return addressSetStorage.getItem(keccak256(abi.encodePacked("minipools.vacant.index")), _index);
}
function destroyMinipool() override external onlyLatestContract("rocketMinipoolManager", address(this)) onlyRegisteredMinipool(msg.sender) {
AddressSetStorageInterface addressSetStorage = AddressSetStorageInterface(getContractAddress("addressSetStorage"));
RocketMinipoolInterface minipool = RocketMinipoolInterface(msg.sender);
address nodeAddress = minipool.getNodeAddress();
RocketNodeStakingInterface rocketNodeStaking = RocketNodeStakingInterface(getContractAddress("rocketNodeStaking"));
uint256 ethMatched = rocketNodeStaking.getNodeETHMatched(nodeAddress);
ethMatched = ethMatched - minipool.getUserDepositBalance();
RocketNetworkSnapshots rocketNetworkSnapshots = RocketNetworkSnapshots(getContractAddress("rocketNetworkSnapshots"));
bytes32 key = keccak256(abi.encodePacked("eth.matched.node.amount", nodeAddress));
rocketNetworkSnapshots.push(key, uint224(ethMatched));
setBool(keccak256(abi.encodePacked("minipool.exists", msg.sender)), false);
setBool(keccak256(abi.encodePacked("minipool.destroyed", msg.sender)), true);
uint256 activeMinipoolCount = getNodeActiveMinipoolCount(nodeAddress);
addressSetStorage.removeItem(keccak256(abi.encodePacked("minipools.index")), msg.sender);
addressSetStorage.removeItem(keccak256(abi.encodePacked("node.minipools.index", nodeAddress)), msg.sender);
bytes memory pubkey = getMinipoolPubkey(msg.sender);
deleteBytes(keccak256(abi.encodePacked("minipool.pubkey", msg.sender)));
deleteAddress(keccak256(abi.encodePacked("validator.minipool", pubkey)));
key = keccak256(abi.encodePacked("minipools.active.count", nodeAddress));
rocketNetworkSnapshots.push(key, uint224(activeMinipoolCount - 1));
emit MinipoolDestroyed(msg.sender, nodeAddress, block.timestamp);
}
function setMinipoolPubkey(bytes calldata _pubkey) override public onlyLatestContract("rocketMinipoolManager", address(this)) onlyRegisteredMinipool(msg.sender) {
_setMinipoolPubkey(msg.sender, _pubkey);
}
function _setMinipoolPubkey(address _minipool, bytes calldata _pubkey) private {
require(getMinipoolByPubkey(_pubkey) == address(0x0), "Validator pubkey is in use");
AddressSetStorageInterface addressSetStorage = AddressSetStorageInterface(getContractAddress("addressSetStorage"));
RocketMinipoolInterface minipool = RocketMinipoolInterface(_minipool);
address nodeAddress = minipool.getNodeAddress();
setBytes(keccak256(abi.encodePacked("minipool.pubkey", _minipool)), _pubkey);
setAddress(keccak256(abi.encodePacked("validator.minipool", _pubkey)), _minipool);
addressSetStorage.addItem(keccak256(abi.encodePacked("node.minipools.validating.index", nodeAddress)), _minipool);
}
function getMinipoolDepositType(address _minipoolAddress) external override view returns (MinipoolDeposit) {
RocketMinipoolInterface minipoolInterface = RocketMinipoolInterface(_minipoolAddress);
uint8 version = 1;
try minipoolInterface.version() returns (uint8 tryVersion) {
version = tryVersion;
} catch (bytes memory ) {}
if (version == 1 || version == 2) {
try minipoolInterface.getDepositType{gas: 30000}() returns (MinipoolDeposit depositType) {
return depositType;
} catch (bytes memory ) {
return MinipoolDeposit.Variable;
}
}
return minipoolInterface.getDepositType();
}
function deployContract(address _nodeAddress, uint256 _salt) private returns (address) {
RocketMinipoolFactoryInterface rocketMinipoolFactory = RocketMinipoolFactoryInterface(getContractAddress("rocketMinipoolFactory"));
return rocketMinipoolFactory.deployContract(_nodeAddress, _salt);
}
}
文件 17 的 31:RocketMinipoolManagerInterface.sol
pragma solidity >0.5.0 <0.9.0;
pragma abicoder v2;
import "../../types/MinipoolDeposit.sol";
import "../../types/MinipoolDetails.sol";
import "./RocketMinipoolInterface.sol";
interface RocketMinipoolManagerInterface {
function getMinipoolCount() external view returns (uint256);
function getStakingMinipoolCount() external view returns (uint256);
function getFinalisedMinipoolCount() external view returns (uint256);
function getActiveMinipoolCount() external view returns (uint256);
function getMinipoolRPLSlashed(address _minipoolAddress) external view returns (bool);
function getMinipoolCountPerStatus(uint256 offset, uint256 limit) external view returns (uint256, uint256, uint256, uint256, uint256);
function getPrelaunchMinipools(uint256 offset, uint256 limit) external view returns (address[] memory);
function getMinipoolAt(uint256 _index) external view returns (address);
function getNodeMinipoolCount(address _nodeAddress) external view returns (uint256);
function getNodeActiveMinipoolCount(address _nodeAddress) external view returns (uint256);
function getNodeFinalisedMinipoolCount(address _nodeAddress) external view returns (uint256);
function getNodeStakingMinipoolCount(address _nodeAddress) external view returns (uint256);
function getNodeStakingMinipoolCountBySize(address _nodeAddress, uint256 _depositSize) external view returns (uint256);
function getNodeMinipoolAt(address _nodeAddress, uint256 _index) external view returns (address);
function getNodeValidatingMinipoolCount(address _nodeAddress) external view returns (uint256);
function getNodeValidatingMinipoolAt(address _nodeAddress, uint256 _index) external view returns (address);
function getMinipoolByPubkey(bytes calldata _pubkey) external view returns (address);
function getMinipoolExists(address _minipoolAddress) external view returns (bool);
function getMinipoolDestroyed(address _minipoolAddress) external view returns (bool);
function getMinipoolPubkey(address _minipoolAddress) external view returns (bytes memory);
function updateNodeStakingMinipoolCount(uint256 _previousBond, uint256 _newBond, uint256 _previousFee, uint256 _newFee) external;
function getMinipoolWithdrawalCredentials(address _minipoolAddress) external pure returns (bytes memory);
function createMinipool(address _nodeAddress, uint256 _salt) external returns (RocketMinipoolInterface);
function createVacantMinipool(address _nodeAddress, uint256 _salt, bytes calldata _validatorPubkey, uint256 _bondAmount, uint256 _currentBalance) external returns (RocketMinipoolInterface);
function removeVacantMinipool() external;
function getVacantMinipoolCount() external view returns (uint256);
function getVacantMinipoolAt(uint256 _index) external view returns (address);
function destroyMinipool() external;
function incrementNodeStakingMinipoolCount(address _nodeAddress) external;
function decrementNodeStakingMinipoolCount(address _nodeAddress) external;
function tryDistribute(address _nodeAddress) external;
function incrementNodeFinalisedMinipoolCount(address _nodeAddress) external;
function setMinipoolPubkey(bytes calldata _pubkey) external;
function getMinipoolDepositType(address _minipoolAddress) external view returns (MinipoolDeposit);
}
文件 18 的 31:RocketMinipoolPenaltyInterface.sol
pragma solidity >0.5.0 <0.9.0;
interface RocketMinipoolPenaltyInterface {
function setMaxPenaltyRate(uint256 _rate) external;
function getMaxPenaltyRate() external view returns (uint256);
function setPenaltyRate(address _minipoolAddress, uint256 _rate) external;
function getPenaltyRate(address _minipoolAddress) external view returns(uint256);
}
文件 19 的 31:RocketNetworkPenaltiesInterface.sol
pragma solidity >0.5.0 <0.9.0;
interface RocketNetworkPenaltiesInterface {
function submitPenalty(address _minipoolAddress, uint256 _block) external;
function executeUpdatePenalty(address _minipoolAddress, uint256 _block) external;
function getPenaltyCount(address _minipoolAddress) external view returns (uint256);
}
文件 20 的 31:RocketNetworkPricesInterface.sol
pragma solidity >0.5.0 <0.9.0;
interface RocketNetworkPricesInterface {
function getPricesBlock() external view returns (uint256);
function getRPLPrice() external view returns (uint256);
function submitPrices(uint256 _block, uint256 _slotTimestamp, uint256 _rplPrice) external;
function executeUpdatePrices(uint256 _block, uint256 _slotTimestamp, uint256 _rplPrice) external;
}
文件 21 的 31:RocketNetworkSnapshots.sol
pragma solidity 0.8.18;
import "@openzeppelin4/contracts/utils/math/Math.sol";
import "../RocketBase.sol";
import "../../interface/network/RocketNetworkSnapshotsInterface.sol";
contract RocketNetworkSnapshots is RocketBase, RocketNetworkSnapshotsInterface {
constructor(RocketStorageInterface _rocketStorageAddress) RocketBase(_rocketStorageAddress) {
version = 1;
if (!rocketStorage.getDeployedStatus()) {
_insert(keccak256("network.prices.rpl"), 0.01 ether);
_insert(keccak256("node.voting.power.stake.maximum"), 1.5 ether);
}
}
function push(bytes32 _key, uint224 _value) onlyLatestContract("rocketNetworkSnapshots", address(this)) onlyLatestNetworkContract external {
_insert(_key, _value);
}
function length(bytes32 _key) public view returns (uint256) {
return rocketStorage.getUint(keccak256(abi.encodePacked("snapshot.length", _key)));
}
function latest(bytes32 _key) external view returns (bool, uint32, uint224) {
uint256 len = length(_key);
if (len == 0) {
return (false, 0, 0);
}
Checkpoint224 memory checkpoint = _load(_key, len - 1);
return (true, checkpoint._block, checkpoint._value);
}
function latestBlock(bytes32 _key) external view returns (uint32) {
uint256 len = length(_key);
return len == 0 ? 0 : _blockAt(_key, len - 1);
}
function latestValue(bytes32 _key) external view returns (uint224) {
uint256 len = length(_key);
return len == 0 ? 0 : _valueAt(_key, len - 1);
}
function lookup(bytes32 _key, uint32 _block) external view returns (uint224) {
uint256 len = length(_key);
uint256 pos = _binaryLookup(_key, _block, 0, len);
return pos == 0 ? 0 : _valueAt(_key, pos - 1);
}
function lookupRecent(bytes32 _key, uint32 _block, uint256 _recency) external view returns (uint224) {
uint256 len = length(_key);
uint256 low = 0;
uint256 high = len;
if (len > 5 && len > _recency) {
uint256 mid = len - _recency;
if (_block < _blockAt(_key, mid)) {
high = mid;
} else {
low = mid + 1;
}
}
uint256 pos = _binaryLookup(_key, _block, low, high);
return pos == 0 ? 0 : _valueAt(_key, pos - 1);
}
function _insert(bytes32 _key, uint224 _value) private {
uint32 blockNumber = uint32(block.number);
uint256 pos = length(_key);
if (pos > 0) {
Checkpoint224 memory last = _load(_key, pos - 1);
require (last._block <= blockNumber, "Unordered snapshot insertion");
if (last._block == blockNumber) {
last._value = _value;
_set(_key, pos - 1, last);
} else {
_push(_key, Checkpoint224({_block: blockNumber, _value: _value}));
}
} else {
_push(_key, Checkpoint224({_block: blockNumber, _value: _value}));
}
}
function _binaryLookup(
bytes32 _key,
uint32 _block,
uint256 _low,
uint256 _high
) private view returns (uint256) {
while (_low < _high) {
uint256 mid = Math.average(_low, _high);
if (_blockAt(_key, mid) > _block) {
_high = mid;
} else {
_low = mid + 1;
}
}
return _high;
}
function _load(bytes32 _key, uint256 _pos) private view returns (Checkpoint224 memory) {
bytes32 key = bytes32(uint256(_key) + _pos);
bytes32 raw = rocketStorage.getBytes32(key);
Checkpoint224 memory result;
result._block = uint32(uint256(raw) >> 224);
result._value = uint224(uint256(raw));
return result;
}
function _blockAt(bytes32 _key, uint256 _pos) private view returns (uint32) {
bytes32 key = bytes32(uint256(_key) + _pos);
bytes32 raw = rocketStorage.getBytes32(key);
return uint32(uint256(raw) >> 224);
}
function _valueAt(bytes32 _key, uint256 _pos) private view returns (uint224) {
bytes32 key = bytes32(uint256(_key) + _pos);
bytes32 raw = rocketStorage.getBytes32(key);
return uint224(uint256(raw));
}
function _push(bytes32 _key, Checkpoint224 memory _item) private {
bytes32 lengthKey = keccak256(abi.encodePacked("snapshot.length", _key));
uint256 snapshotLength = rocketStorage.getUint(lengthKey);
bytes32 key = bytes32(uint256(_key) + snapshotLength);
rocketStorage.setUint(lengthKey, snapshotLength + 1);
rocketStorage.setBytes32(key, _encode(_item));
}
function _set(bytes32 _key, uint256 _pos, Checkpoint224 memory _item) private {
bytes32 key = bytes32(uint256(_key) + _pos);
rocketStorage.setBytes32(key, _encode(_item));
}
function _encode(Checkpoint224 memory _item) private pure returns (bytes32) {
return bytes32(
uint256(_item._block) << 224 | uint256(_item._value)
);
}
}
文件 22 的 31:RocketNetworkSnapshotsInterface.sol
pragma solidity >0.5.0 <0.9.0;
struct Checkpoint224 {
uint32 _block;
uint224 _value;
}
interface RocketNetworkSnapshotsInterface {
function push(bytes32 _key, uint224 _value) external;
function length(bytes32 _key) external view returns (uint256);
function latest(bytes32 _key) external view returns (bool, uint32, uint224);
function latestBlock(bytes32 _key) external view returns (uint32);
function latestValue(bytes32 _key) external view returns (uint224);
function lookup(bytes32 _key, uint32 _block) external view returns (uint224);
function lookupRecent(bytes32 _key, uint32 _block, uint256 _recency) external view returns (uint224);
}
文件 23 的 31:RocketNetworkVotingInterface.sol
pragma solidity >0.5.0 <0.9.0;
interface RocketNetworkVotingInterface {
function initialiseVotingFor(address _nodeAddress) external;
function initialiseVoting() external;
function initialiseVotingWithDelegate(address _delegate) external;
function getVotingInitialised(address _nodeAddress) external view returns (bool);
function getNodeCount(uint32 _block) external view returns (uint256);
function getVotingPower(address _nodeAddress, uint32 _block) external view returns (uint256);
function setDelegate(address _newDelegate) external;
function getDelegate(address _nodeAddress, uint32 _block) external view returns (address);
function getCurrentDelegate(address _nodeAddress) external view returns (address);
}
文件 24 的 31:RocketNodeDepositInterface.sol
pragma solidity >0.5.0 <0.9.0;
import "../../types/MinipoolDeposit.sol";
interface RocketNodeDepositInterface {
function getNodeDepositCredit(address _nodeAddress) external view returns (uint256);
function getNodeEthBalance(address _nodeAddress) external view returns (uint256);
function getNodeCreditAndBalance(address _nodeAddress) external view returns (uint256);
function getNodeUsableCreditAndBalance(address _nodeAddress) external view returns (uint256);
function getNodeUsableCredit(address _nodeAddress) external view returns (uint256);
function increaseDepositCreditBalance(address _nodeOperator, uint256 _amount) external;
function depositEthFor(address _nodeAddress) external payable;
function withdrawEth(address _nodeAddress, uint256 _amount) external;
function deposit(uint256 _depositAmount, uint256 _minimumNodeFee, bytes calldata _validatorPubkey, bytes calldata _validatorSignature, bytes32 _depositDataRoot, uint256 _salt, address _expectedMinipoolAddress) external payable;
function depositWithCredit(uint256 _depositAmount, uint256 _minimumNodeFee, bytes calldata _validatorPubkey, bytes calldata _validatorSignature, bytes32 _depositDataRoot, uint256 _salt, address _expectedMinipoolAddress) external payable;
function isValidDepositAmount(uint256 _amount) external pure returns (bool);
function getDepositAmounts() external pure returns (uint256[] memory);
function createVacantMinipool(uint256 _bondAmount, uint256 _minimumNodeFee, bytes calldata _validatorPubkey, uint256 _salt, address _expectedMinipoolAddress, uint256 _currentBalance) external;
function increaseEthMatched(address _nodeAddress, uint256 _amount) external;
}
文件 25 的 31:RocketNodeDistributorFactoryInterface.sol
pragma solidity >0.5.0 <0.9.0;
interface RocketNodeDistributorFactoryInterface {
function getProxyBytecode() external pure returns (bytes memory);
function getProxyAddress(address _nodeAddress) external view returns(address);
function createProxy(address _nodeAddress) external;
}
文件 26 的 31:RocketNodeDistributorInterface.sol
pragma solidity >0.5.0 <0.9.0;
interface RocketNodeDistributorInterface {
function getNodeShare() external view returns (uint256);
function getUserShare() external view returns (uint256);
function distribute() external;
}
文件 27 的 31:RocketNodeManagerInterface.sol
pragma solidity >0.5.0 <0.9.0;
pragma abicoder v2;
import "../../types/NodeDetails.sol";
interface RocketNodeManagerInterface {
struct TimezoneCount {
string timezone;
uint256 count;
}
function getNodeCount() external view returns (uint256);
function getNodeCountPerTimezone(uint256 offset, uint256 limit) external view returns (TimezoneCount[] memory);
function getNodeAt(uint256 _index) external view returns (address);
function getNodeExists(address _nodeAddress) external view returns (bool);
function getNodeWithdrawalAddress(address _nodeAddress) external view returns (address);
function getNodePendingWithdrawalAddress(address _nodeAddress) external view returns (address);
function getNodeRPLWithdrawalAddress(address _nodeAddress) external view returns (address);
function getNodeRPLWithdrawalAddressIsSet(address _nodeAddress) external view returns (bool);
function unsetRPLWithdrawalAddress(address _nodeAddress) external;
function setRPLWithdrawalAddress(address _nodeAddress, address _newRPLWithdrawalAddress, bool _confirm) external;
function confirmRPLWithdrawalAddress(address _nodeAddress) external;
function getNodePendingRPLWithdrawalAddress(address _nodeAddress) external view returns (address);
function getNodeTimezoneLocation(address _nodeAddress) external view returns (string memory);
function registerNode(string calldata _timezoneLocation) external;
function getNodeRegistrationTime(address _nodeAddress) external view returns (uint256);
function setTimezoneLocation(string calldata _timezoneLocation) external;
function setRewardNetwork(address _nodeAddress, uint256 network) external;
function getRewardNetwork(address _nodeAddress) external view returns (uint256);
function getFeeDistributorInitialised(address _nodeAddress) external view returns (bool);
function initialiseFeeDistributor() external;
function getAverageNodeFee(address _nodeAddress) external view returns (uint256);
function setSmoothingPoolRegistrationState(bool _state) external;
function getSmoothingPoolRegistrationState(address _nodeAddress) external returns (bool);
function getSmoothingPoolRegistrationChanged(address _nodeAddress) external returns (uint256);
function getSmoothingPoolRegisteredNodeCount(uint256 _offset, uint256 _limit) external view returns (uint256);
function getNodeDetails(address _nodeAddress) external view returns (NodeDetails memory);
function getNodeAddresses(uint256 _offset, uint256 _limit) external view returns (address[] memory);
}
文件 28 的 31:RocketNodeStaking.sol
pragma solidity 0.8.18;
import "../../interface/util/IERC20.sol";
import "../RocketBase.sol";
import "../../interface/minipool/RocketMinipoolManagerInterface.sol";
import "../../interface/network/RocketNetworkPricesInterface.sol";
import "../../interface/node/RocketNodeStakingInterface.sol";
import "../../interface/dao/protocol/settings/RocketDAOProtocolSettingsRewardsInterface.sol";
import "../../interface/dao/protocol/settings/RocketDAOProtocolSettingsMinipoolInterface.sol";
import "../../interface/dao/protocol/settings/RocketDAOProtocolSettingsNodeInterface.sol";
import "../../interface/RocketVaultInterface.sol";
import "../../interface/util/AddressSetStorageInterface.sol";
import "../../interface/network/RocketNetworkSnapshotsInterface.sol";
import "../network/RocketNetworkSnapshots.sol";
import "../../interface/node/RocketNodeManagerInterface.sol";
import "../../interface/network/RocketNetworkVotingInterface.sol";
contract RocketNodeStaking is RocketBase, RocketNodeStakingInterface {
bytes32 immutable internal totalKey;
event RPLStaked(address indexed from, uint256 amount, uint256 time);
event RPLWithdrawn(address indexed to, uint256 amount, uint256 time);
event RPLSlashed(address indexed node, uint256 amount, uint256 ethValue, uint256 time);
event StakeRPLForAllowed(address indexed node, address indexed caller, bool allowed, uint256 time);
event RPLLockingAllowed(address indexed node, bool allowed, uint256 time);
event RPLLocked(address indexed from, uint256 amount, uint256 time);
event RPLUnlocked(address indexed from, uint256 amount, uint256 time);
event RPLTransferred(address indexed from, address indexed to, uint256 amount, uint256 time);
event RPLBurned(address indexed from, uint256 amount, uint256 time);
modifier onlyRPLWithdrawalAddressOrNode(address _nodeAddress) {
RocketNodeManagerInterface rocketNodeManager = RocketNodeManagerInterface(getContractAddress("rocketNodeManager"));
if (rocketNodeManager.getNodeRPLWithdrawalAddressIsSet(_nodeAddress)) {
address rplWithdrawalAddress = rocketNodeManager.getNodeRPLWithdrawalAddress(_nodeAddress);
require(msg.sender == rplWithdrawalAddress, "Must be called from RPL withdrawal address");
} else {
require(msg.sender == _nodeAddress, "Must be called from node address");
}
_;
}
constructor(RocketStorageInterface _rocketStorageAddress) RocketBase(_rocketStorageAddress) {
version = 6;
totalKey = keccak256(abi.encodePacked("rpl.staked.total.amount"));
}
function getTotalRPLStake() override external view returns (uint256) {
return getUint(totalKey);
}
function increaseTotalRPLStake(uint256 _amount) private {
addUint(totalKey, _amount);
}
function decreaseTotalRPLStake(uint256 _amount) private {
subUint(totalKey, _amount);
}
function getNodeRPLStake(address _nodeAddress) override public view returns (uint256) {
bytes32 key = keccak256(abi.encodePacked("rpl.staked.node.amount", _nodeAddress));
RocketNetworkSnapshotsInterface rocketNetworkSnapshots = RocketNetworkSnapshotsInterface(getContractAddress("rocketNetworkSnapshots"));
(bool exists,, uint224 value) = rocketNetworkSnapshots.latest(key);
uint256 stake = uint256(value);
if (!exists){
stake = getUint(key);
}
return stake;
}
function increaseNodeRPLStake(address _nodeAddress, uint256 _amount) private {
RocketNetworkSnapshotsInterface rocketNetworkSnapshots = RocketNetworkSnapshotsInterface(getContractAddress("rocketNetworkSnapshots"));
bytes32 key = keccak256(abi.encodePacked("rpl.staked.node.amount", _nodeAddress));
(bool exists,, uint224 value) = rocketNetworkSnapshots.latest(key);
if (!exists){
value = uint224(getUint(key));
}
rocketNetworkSnapshots.push(key, value + uint224(_amount));
}
function decreaseNodeRPLStake(address _nodeAddress, uint256 _amount) private {
RocketNetworkSnapshotsInterface rocketNetworkSnapshots = RocketNetworkSnapshotsInterface(getContractAddress("rocketNetworkSnapshots"));
bytes32 key = keccak256(abi.encodePacked("rpl.staked.node.amount", _nodeAddress));
(bool exists,, uint224 value) = rocketNetworkSnapshots.latest(key);
if (!exists){
value = uint224(getUint(key));
}
rocketNetworkSnapshots.push(key, value - uint224(_amount));
}
function getNodeETHMatched(address _nodeAddress) override public view returns (uint256) {
RocketNetworkSnapshotsInterface rocketNetworkSnapshots = RocketNetworkSnapshotsInterface(getContractAddress("rocketNetworkSnapshots"));
bytes32 key = keccak256(abi.encodePacked("eth.matched.node.amount", _nodeAddress));
(bool exists, , uint224 value) = rocketNetworkSnapshots.latest(key);
if (exists) {
return value;
} else {
uint256 ethMatched = getUint(key);
if (ethMatched > 0) {
return ethMatched;
} else {
RocketMinipoolManagerInterface rocketMinipoolManager = RocketMinipoolManagerInterface(getContractAddress("rocketMinipoolManager"));
return rocketMinipoolManager.getNodeActiveMinipoolCount(_nodeAddress) * 16 ether;
}
}
}
function getNodeETHProvided(address _nodeAddress) override public view returns (uint256) {
RocketMinipoolManagerInterface rocketMinipoolManager = RocketMinipoolManagerInterface(getContractAddress("rocketMinipoolManager"));
uint256 activeMinipoolCount = rocketMinipoolManager.getNodeActiveMinipoolCount(_nodeAddress);
uint256 ethMatched = getNodeETHMatched(_nodeAddress);
if (ethMatched > 0) {
RocketDAOProtocolSettingsMinipoolInterface rocketDAOProtocolSettingsMinipool = RocketDAOProtocolSettingsMinipoolInterface(getContractAddress("rocketDAOProtocolSettingsMinipool"));
uint256 launchAmount = rocketDAOProtocolSettingsMinipool.getLaunchBalance();
uint256 totalEthStaked = activeMinipoolCount * launchAmount;
return totalEthStaked - ethMatched;
} else {
return activeMinipoolCount * 16 ether;
}
}
function getNodeETHCollateralisationRatio(address _nodeAddress) override public view returns (uint256) {
uint256 ethMatched = getNodeETHMatched(_nodeAddress);
if (ethMatched == 0) {
return calcBase * 2;
} else {
RocketDAOProtocolSettingsMinipoolInterface rocketDAOProtocolSettingsMinipool = RocketDAOProtocolSettingsMinipoolInterface(getContractAddress("rocketDAOProtocolSettingsMinipool"));
uint256 launchAmount = rocketDAOProtocolSettingsMinipool.getLaunchBalance();
RocketMinipoolManagerInterface rocketMinipoolManager = RocketMinipoolManagerInterface(getContractAddress("rocketMinipoolManager"));
uint256 totalEthStaked = rocketMinipoolManager.getNodeActiveMinipoolCount(_nodeAddress) * launchAmount;
return (totalEthStaked * calcBase) / (totalEthStaked - ethMatched);
}
}
function getNodeRPLStakedTime(address _nodeAddress) override public view returns (uint256) {
return getUint(keccak256(abi.encodePacked("rpl.staked.node.time", _nodeAddress)));
}
function setNodeRPLStakedTime(address _nodeAddress, uint256 _time) private {
setUint(keccak256(abi.encodePacked("rpl.staked.node.time", _nodeAddress)), _time);
}
function getNodeEffectiveRPLStake(address _nodeAddress) override public view returns (uint256) {
RocketNetworkPricesInterface rocketNetworkPrices = RocketNetworkPricesInterface(getContractAddress("rocketNetworkPrices"));
RocketDAOProtocolSettingsNodeInterface rocketDAOProtocolSettingsNode = RocketDAOProtocolSettingsNodeInterface(getContractAddress("rocketDAOProtocolSettingsNode"));
uint256 rplStake = getNodeRPLStake(_nodeAddress);
uint256 matchedETH = getNodeETHMatched(_nodeAddress);
uint256 providedETH = getNodeETHProvided(_nodeAddress);
uint256 rplPrice = rocketNetworkPrices.getRPLPrice();
uint256 maximumStakePercent = rocketDAOProtocolSettingsNode.getMaximumPerMinipoolStake();
uint256 maximumStake = providedETH * maximumStakePercent / rplPrice;
if (rplStake > maximumStake) {
return maximumStake;
}
uint256 minimumStakePercent = rocketDAOProtocolSettingsNode.getMinimumPerMinipoolStake();
uint256 minimumStake = matchedETH * minimumStakePercent / rplPrice;
if (rplStake < minimumStake) {
return 0;
}
return rplStake;
}
function getNodeMinimumRPLStake(address _nodeAddress) override external view returns (uint256) {
RocketNetworkPricesInterface rocketNetworkPrices = RocketNetworkPricesInterface(getContractAddress("rocketNetworkPrices"));
RocketDAOProtocolSettingsNodeInterface rocketDAOProtocolSettingsNode = RocketDAOProtocolSettingsNodeInterface(getContractAddress("rocketDAOProtocolSettingsNode"));
uint256 minimumStakePercent = rocketDAOProtocolSettingsNode.getMinimumPerMinipoolStake();
uint256 matchedETH = getNodeETHMatched(_nodeAddress);
return matchedETH * minimumStakePercent / rocketNetworkPrices.getRPLPrice();
}
function getNodeMaximumRPLStake(address _nodeAddress) override public view returns (uint256) {
RocketNetworkPricesInterface rocketNetworkPrices = RocketNetworkPricesInterface(getContractAddress("rocketNetworkPrices"));
RocketDAOProtocolSettingsNodeInterface rocketDAOProtocolSettingsNode = RocketDAOProtocolSettingsNodeInterface(getContractAddress("rocketDAOProtocolSettingsNode"));
uint256 maximumStakePercent = rocketDAOProtocolSettingsNode.getMaximumPerMinipoolStake();
uint256 providedETH = getNodeETHProvided(_nodeAddress);
return providedETH * maximumStakePercent / rocketNetworkPrices.getRPLPrice();
}
function getNodeETHMatchedLimit(address _nodeAddress) override external view returns (uint256) {
RocketDAOProtocolSettingsNodeInterface rocketDAOProtocolSettingsNode = RocketDAOProtocolSettingsNodeInterface(getContractAddress("rocketDAOProtocolSettingsNode"));
uint256 minimumStakePercent = rocketDAOProtocolSettingsNode.getMinimumPerMinipoolStake();
if (minimumStakePercent == 0) {
return type(uint256).max;
}
RocketNetworkPricesInterface rocketNetworkPrices = RocketNetworkPricesInterface(getContractAddress("rocketNetworkPrices"));
return getNodeRPLStake(_nodeAddress) *rocketNetworkPrices.getRPLPrice() / minimumStakePercent;
}
function getRPLLockingAllowed(address _nodeAddress) external view returns (bool) {
return getBool(keccak256(abi.encodePacked("rpl.locking.allowed", _nodeAddress)));
}
function stakeRPL(uint256 _amount) override external {
stakeRPLFor(msg.sender, _amount);
}
function stakeRPLFor(address _nodeAddress, uint256 _amount) override public onlyLatestContract("rocketNodeStaking", address(this)) onlyRegisteredNode(_nodeAddress) {
if (msg.sender != getAddress(keccak256(abi.encodePacked("contract.address", "rocketMerkleDistributorMainnet")))) {
RocketNodeManagerInterface rocketNodeManager = RocketNodeManagerInterface(getContractAddress("rocketNodeManager"));
bool fromNode = false;
if (rocketNodeManager.getNodeRPLWithdrawalAddressIsSet(_nodeAddress)) {
address rplWithdrawalAddress = rocketNodeManager.getNodeRPLWithdrawalAddress(_nodeAddress);
fromNode = msg.sender == rplWithdrawalAddress;
} else {
address withdrawalAddress = rocketStorage.getNodeWithdrawalAddress(_nodeAddress);
fromNode = (msg.sender == _nodeAddress) || (msg.sender == withdrawalAddress);
}
if (!fromNode) {
require(getBool(keccak256(abi.encodePacked("node.stake.for.allowed", _nodeAddress, msg.sender))), "Not allowed to stake for");
}
}
_stakeRPL(_nodeAddress, _amount);
}
function setRPLLockingAllowed(address _nodeAddress, bool _allowed) override external onlyLatestContract("rocketNodeStaking", address(this)) onlyRPLWithdrawalAddressOrNode(_nodeAddress) {
setBool(keccak256(abi.encodePacked("rpl.locking.allowed", _nodeAddress)), _allowed);
emit RPLLockingAllowed(_nodeAddress, _allowed, block.timestamp);
}
function setStakeRPLForAllowed(address _caller, bool _allowed) override external {
setStakeRPLForAllowed(msg.sender, _caller, _allowed);
}
function setStakeRPLForAllowed(address _nodeAddress, address _caller, bool _allowed) override public onlyLatestContract("rocketNodeStaking", address(this)) onlyRPLWithdrawalAddressOrNode(_nodeAddress) {
setBool(keccak256(abi.encodePacked("node.stake.for.allowed", _nodeAddress, _caller)), _allowed);
emit StakeRPLForAllowed(_nodeAddress, _caller, _allowed, block.timestamp);
}
function _stakeRPL(address _nodeAddress, uint256 _amount) internal {
RocketNetworkVotingInterface rocketNetworkVoting = RocketNetworkVotingInterface(getContractAddress("rocketNetworkVoting"));
rocketNetworkVoting.initialiseVotingFor(_nodeAddress);
address rplTokenAddress = getContractAddress("rocketTokenRPL");
address rocketVaultAddress = getContractAddress("rocketVault");
IERC20 rplToken = IERC20(rplTokenAddress);
RocketVaultInterface rocketVault = RocketVaultInterface(rocketVaultAddress);
require(rplToken.transferFrom(msg.sender, address(this), _amount), "Could not transfer RPL to staking contract");
require(rplToken.approve(rocketVaultAddress, _amount), "Could not approve vault RPL deposit");
rocketVault.depositToken("rocketNodeStaking", rplToken, _amount);
increaseTotalRPLStake(_amount);
increaseNodeRPLStake(_nodeAddress, _amount);
setNodeRPLStakedTime(_nodeAddress, block.timestamp);
emit RPLStaked(_nodeAddress, _amount, block.timestamp);
}
function getNodeRPLLocked(address _nodeAddress) override public view returns (uint256) {
return getUint(keccak256(abi.encodePacked("rpl.locked.node.amount", _nodeAddress)));
}
function lockRPL(address _nodeAddress, uint256 _amount) override external onlyLatestContract("rocketNodeStaking", address(this)) onlyLatestNetworkContract() {
require(getBool(keccak256(abi.encodePacked("rpl.locking.allowed", _nodeAddress))), "Node is not allowed to lock RPL");
uint256 rplStake = getNodeRPLStake(_nodeAddress);
bytes32 lockedStakeKey = keccak256(abi.encodePacked("rpl.locked.node.amount", _nodeAddress));
uint256 lockedStake = getUint(lockedStakeKey);
require(rplStake - lockedStake >= _amount, "Not enough staked RPL");
setUint(lockedStakeKey, lockedStake + _amount);
emit RPLLocked(_nodeAddress, _amount, block.timestamp);
}
function unlockRPL(address _nodeAddress, uint256 _amount) override external onlyLatestContract("rocketNodeStaking", address(this)) onlyLatestNetworkContract() {
bytes32 lockedStakeKey = keccak256(abi.encodePacked("rpl.locked.node.amount", _nodeAddress));
uint256 lockedStake = getUint(lockedStakeKey);
require(_amount <= lockedStake, "Not enough locked RPL");
setUint(lockedStakeKey, lockedStake - _amount);
emit RPLUnlocked(_nodeAddress, _amount, block.timestamp);
}
function transferRPL(address _from, address _to, uint256 _amount) override external onlyLatestContract("rocketNodeStaking", address(this)) onlyLatestNetworkContract() onlyRegisteredNode(_from) {
require(getNodeRPLStake(_from) >= _amount, "Sender has insufficient RPL");
decreaseNodeRPLStake(_from, _amount);
increaseNodeRPLStake(_to, _amount);
emit RPLTransferred(_from, _to, _amount, block.timestamp);
}
function burnRPL(address _from, uint256 _amount) override external onlyLatestContract("rocketNodeStaking", address(this)) onlyLatestNetworkContract() onlyRegisteredNode(_from) {
require(getNodeRPLStake(_from) >= _amount, "Node has insufficient RPL");
decreaseTotalRPLStake(_amount);
decreaseNodeRPLStake(_from, _amount);
IERC20Burnable rplToken = IERC20Burnable(getContractAddress("rocketTokenRPL"));
RocketVaultInterface rocketVault = RocketVaultInterface(getContractAddress("rocketVault"));
rocketVault.withdrawToken(address(this), rplToken, _amount);
rplToken.burn(_amount);
emit RPLBurned(_from, _amount, block.timestamp);
}
function withdrawRPL(uint256 _amount) override external {
withdrawRPL(msg.sender, _amount);
}
function withdrawRPL(address _nodeAddress, uint256 _amount) override public onlyLatestContract("rocketNodeStaking", address(this)) {
require(getBool(keccak256(abi.encodePacked("node.exists", _nodeAddress))), "Invalid node");
RocketNodeManagerInterface rocketNodeManager = RocketNodeManagerInterface(getContractAddress("rocketNodeManager"));
address rplWithdrawalAddress = rocketNodeManager.getNodeRPLWithdrawalAddress(_nodeAddress);
if (rocketNodeManager.getNodeRPLWithdrawalAddressIsSet(_nodeAddress)) {
require(msg.sender == rplWithdrawalAddress, "Invalid caller");
} else {
address withdrawalAddress = rocketStorage.getNodeWithdrawalAddress(_nodeAddress);
require(msg.sender == _nodeAddress || msg.sender == withdrawalAddress, "Invalid caller");
}
RocketDAOProtocolSettingsRewardsInterface rocketDAOProtocolSettingsRewards = RocketDAOProtocolSettingsRewardsInterface(getContractAddress("rocketDAOProtocolSettingsRewards"));
RocketVaultInterface rocketVault = RocketVaultInterface(getContractAddress("rocketVault"));
require(block.timestamp - getNodeRPLStakedTime(_nodeAddress) >= rocketDAOProtocolSettingsRewards.getRewardsClaimIntervalTime(), "The withdrawal cooldown period has not passed");
uint256 rplStake = getNodeRPLStake(_nodeAddress);
uint256 lockedStake = getNodeRPLLocked(_nodeAddress);
require(rplStake - lockedStake >= _amount, "Withdrawal amount exceeds node's staked RPL balance");
require(rplStake - _amount >= getNodeMaximumRPLStake(_nodeAddress) + lockedStake, "Node's staked RPL balance after withdrawal is less than required balance");
decreaseTotalRPLStake(_amount);
decreaseNodeRPLStake(_nodeAddress, _amount);
rocketVault.withdrawToken(rplWithdrawalAddress, IERC20(getContractAddress("rocketTokenRPL")), _amount);
emit RPLWithdrawn(_nodeAddress, _amount, block.timestamp);
}
function slashRPL(address _nodeAddress, uint256 _ethSlashAmount) override external onlyLatestContract("rocketNodeStaking", address(this)) onlyRegisteredMinipool(msg.sender) {
RocketNetworkPricesInterface rocketNetworkPrices = RocketNetworkPricesInterface(getContractAddress("rocketNetworkPrices"));
RocketVaultInterface rocketVault = RocketVaultInterface(getContractAddress("rocketVault"));
uint256 rplSlashAmount = calcBase * _ethSlashAmount / rocketNetworkPrices.getRPLPrice();
uint256 rplStake = getNodeRPLStake(_nodeAddress);
if (rplSlashAmount > rplStake) { rplSlashAmount = rplStake; }
if(rplSlashAmount > 0) rocketVault.transferToken("rocketAuctionManager", IERC20(getContractAddress("rocketTokenRPL")), rplSlashAmount);
decreaseTotalRPLStake(rplSlashAmount);
decreaseNodeRPLStake(_nodeAddress, rplSlashAmount);
setBool(keccak256(abi.encodePacked("minipool.rpl.slashed", msg.sender)), true);
emit RPLSlashed(_nodeAddress, rplSlashAmount, _ethSlashAmount, block.timestamp);
}
}
文件 29 的 31:RocketNodeStakingInterface.sol
pragma solidity >0.5.0 <0.9.0;
interface RocketNodeStakingInterface {
function getTotalRPLStake() external view returns (uint256);
function getNodeRPLStake(address _nodeAddress) external view returns (uint256);
function getNodeETHMatched(address _nodeAddress) external view returns (uint256);
function getNodeETHProvided(address _nodeAddress) external view returns (uint256);
function getNodeETHCollateralisationRatio(address _nodeAddress) external view returns (uint256);
function getNodeRPLStakedTime(address _nodeAddress) external view returns (uint256);
function getNodeEffectiveRPLStake(address _nodeAddress) external view returns (uint256);
function getNodeMinimumRPLStake(address _nodeAddress) external view returns (uint256);
function getNodeMaximumRPLStake(address _nodeAddress) external view returns (uint256);
function getNodeETHMatchedLimit(address _nodeAddress) external view returns (uint256);
function getRPLLockingAllowed(address _nodeAddress) external view returns (bool);
function stakeRPL(uint256 _amount) external;
function stakeRPLFor(address _nodeAddress, uint256 _amount) external;
function setRPLLockingAllowed(address _nodeAddress, bool _allowed) external;
function setStakeRPLForAllowed(address _caller, bool _allowed) external;
function setStakeRPLForAllowed(address _nodeAddress, address _caller, bool _allowed) external;
function getNodeRPLLocked(address _nodeAddress) external view returns (uint256);
function lockRPL(address _nodeAddress, uint256 _amount) external;
function unlockRPL(address _nodeAddress, uint256 _amount) external;
function transferRPL(address _from, address _to, uint256 _amount) external;
function burnRPL(address _from, uint256 _amount) external;
function withdrawRPL(uint256 _amount) external;
function withdrawRPL(address _nodeAddress, uint256 _amount) external;
function slashRPL(address _nodeAddress, uint256 _ethSlashAmount) external;
}
文件 30 的 31:RocketStorageInterface.sol
pragma solidity >0.5.0 <0.9.0;
interface RocketStorageInterface {
function getDeployedStatus() external view returns (bool);
function getGuardian() external view returns(address);
function setGuardian(address _newAddress) external;
function confirmGuardian() external;
function getAddress(bytes32 _key) external view returns (address);
function getUint(bytes32 _key) external view returns (uint);
function getString(bytes32 _key) external view returns (string memory);
function getBytes(bytes32 _key) external view returns (bytes memory);
function getBool(bytes32 _key) external view returns (bool);
function getInt(bytes32 _key) external view returns (int);
function getBytes32(bytes32 _key) external view returns (bytes32);
function setAddress(bytes32 _key, address _value) external;
function setUint(bytes32 _key, uint _value) external;
function setString(bytes32 _key, string calldata _value) external;
function setBytes(bytes32 _key, bytes calldata _value) external;
function setBool(bytes32 _key, bool _value) external;
function setInt(bytes32 _key, int _value) external;
function setBytes32(bytes32 _key, bytes32 _value) external;
function deleteAddress(bytes32 _key) external;
function deleteUint(bytes32 _key) external;
function deleteString(bytes32 _key) external;
function deleteBytes(bytes32 _key) external;
function deleteBool(bytes32 _key) external;
function deleteInt(bytes32 _key) external;
function deleteBytes32(bytes32 _key) external;
function addUint(bytes32 _key, uint256 _amount) external;
function subUint(bytes32 _key, uint256 _amount) external;
function getNodeWithdrawalAddress(address _nodeAddress) external view returns (address);
function getNodePendingWithdrawalAddress(address _nodeAddress) external view returns (address);
function setWithdrawalAddress(address _nodeAddress, address _newWithdrawalAddress, bool _confirm) external;
function confirmWithdrawalAddress(address _nodeAddress) external;
}
文件 31 的 31:RocketVaultInterface.sol
pragma solidity >0.5.0 <0.9.0;
import "./util/IERC20Burnable.sol";
interface RocketVaultInterface {
function balanceOf(string memory _networkContractName) external view returns (uint256);
function depositEther() external payable;
function withdrawEther(uint256 _amount) external;
function depositToken(string memory _networkContractName, IERC20 _tokenAddress, uint256 _amount) external;
function withdrawToken(address _withdrawalAddress, IERC20 _tokenAddress, uint256 _amount) external;
function balanceOfToken(string memory _networkContractName, IERC20 _tokenAddress) external view returns (uint256);
function transferToken(string memory _networkContractName, IERC20 _tokenAddress, uint256 _amount) external;
function burnToken(IERC20Burnable _tokenAddress, uint256 _amount) external;
}
{
"compilationTarget": {
"contracts/contract/minipool/RocketMinipoolManager.sol": "RocketMinipoolManager"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 15000
},
"remappings": []
}
[{"inputs":[{"internalType":"contract RocketStorageInterface","name":"_rocketStorageAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"minipool","type":"address"},{"indexed":false,"internalType":"uint256","name":"time","type":"uint256"}],"name":"BeginBondReduction","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"minipool","type":"address"},{"indexed":true,"internalType":"address","name":"member","type":"address"},{"indexed":false,"internalType":"uint256","name":"time","type":"uint256"}],"name":"CancelReductionVoted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"minipool","type":"address"},{"indexed":true,"internalType":"address","name":"node","type":"address"},{"indexed":false,"internalType":"uint256","name":"time","type":"uint256"}],"name":"MinipoolCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"minipool","type":"address"},{"indexed":true,"internalType":"address","name":"node","type":"address"},{"indexed":false,"internalType":"uint256","name":"time","type":"uint256"}],"name":"MinipoolDestroyed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"minipool","type":"address"},{"indexed":false,"internalType":"uint256","name":"time","type":"uint256"}],"name":"ReductionCancelled","type":"event"},{"inputs":[{"internalType":"address","name":"_nodeAddress","type":"address"},{"internalType":"uint256","name":"_salt","type":"uint256"}],"name":"createMinipool","outputs":[{"internalType":"contract RocketMinipoolInterface","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_nodeAddress","type":"address"},{"internalType":"uint256","name":"_salt","type":"uint256"},{"internalType":"bytes","name":"_validatorPubkey","type":"bytes"},{"internalType":"uint256","name":"_bondAmount","type":"uint256"},{"internalType":"uint256","name":"_currentBalance","type":"uint256"}],"name":"createVacantMinipool","outputs":[{"internalType":"contract RocketMinipoolInterface","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_nodeAddress","type":"address"}],"name":"decrementNodeStakingMinipoolCount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"destroyMinipool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getActiveMinipoolCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getFinalisedMinipoolCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"getMinipoolAt","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"_pubkey","type":"bytes"}],"name":"getMinipoolByPubkey","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMinipoolCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_offset","type":"uint256"},{"internalType":"uint256","name":"_limit","type":"uint256"}],"name":"getMinipoolCountPerStatus","outputs":[{"internalType":"uint256","name":"initialisedCount","type":"uint256"},{"internalType":"uint256","name":"prelaunchCount","type":"uint256"},{"internalType":"uint256","name":"stakingCount","type":"uint256"},{"internalType":"uint256","name":"withdrawableCount","type":"uint256"},{"internalType":"uint256","name":"dissolvedCount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_minipoolAddress","type":"address"}],"name":"getMinipoolDepositType","outputs":[{"internalType":"enum MinipoolDeposit","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_minipoolAddress","type":"address"}],"name":"getMinipoolDestroyed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_minipoolAddress","type":"address"}],"name":"getMinipoolExists","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_minipoolAddress","type":"address"}],"name":"getMinipoolPubkey","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_minipoolAddress","type":"address"}],"name":"getMinipoolRPLSlashed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_minipoolAddress","type":"address"}],"name":"getMinipoolWithdrawalCredentials","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"_nodeAddress","type":"address"}],"name":"getNodeActiveMinipoolCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_nodeAddress","type":"address"}],"name":"getNodeFinalisedMinipoolCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_nodeAddress","type":"address"},{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"getNodeMinipoolAt","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_nodeAddress","type":"address"}],"name":"getNodeMinipoolCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_nodeAddress","type":"address"}],"name":"getNodeStakingMinipoolCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_nodeAddress","type":"address"},{"internalType":"uint256","name":"_depositSize","type":"uint256"}],"name":"getNodeStakingMinipoolCountBySize","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_nodeAddress","type":"address"},{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"getNodeValidatingMinipoolAt","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_nodeAddress","type":"address"}],"name":"getNodeValidatingMinipoolCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_offset","type":"uint256"},{"internalType":"uint256","name":"_limit","type":"uint256"}],"name":"getPrelaunchMinipools","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStakingMinipoolCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"getVacantMinipoolAt","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getVacantMinipoolCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_nodeAddress","type":"address"}],"name":"incrementNodeFinalisedMinipoolCount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_nodeAddress","type":"address"}],"name":"incrementNodeStakingMinipoolCount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"removeVacantMinipool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"_pubkey","type":"bytes"}],"name":"setMinipoolPubkey","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_nodeAddress","type":"address"}],"name":"tryDistribute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_previousBond","type":"uint256"},{"internalType":"uint256","name":"_newBond","type":"uint256"},{"internalType":"uint256","name":"_previousFee","type":"uint256"},{"internalType":"uint256","name":"_newFee","type":"uint256"}],"name":"updateNodeStakingMinipoolCount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"}]