diff --git a/contracts/contract/node/RocketNodeDeposit.sol b/contracts/contract/node/RocketNodeDeposit.sol index 67c5beb14..70086422a 100644 --- a/contracts/contract/node/RocketNodeDeposit.sol +++ b/contracts/contract/node/RocketNodeDeposit.sol @@ -20,6 +20,7 @@ import "../../types/MinipoolDeposit.sol"; import "../../interface/node/RocketNodeManagerInterface.sol"; import "../../interface/RocketVaultInterface.sol"; import "../../interface/node/RocketNodeStakingInterface.sol"; +import "../../interface/token/RocketTokenRETHInterface.sol"; /// @notice Handles node deposits and minipool creation contract RocketNodeDeposit is RocketBase, RocketNodeDepositInterface { @@ -56,18 +57,42 @@ contract RocketNodeDeposit is RocketBase, RocketNodeDepositInterface { /// @param _salt Salt used to deterministically construct the minipool's address /// @param _expectedMinipoolAddress The expected deterministic minipool address. Will revert if it doesn't match function deposit(uint256 _bondAmount, uint256 _minimumNodeFee, bytes calldata _validatorPubkey, bytes calldata _validatorSignature, bytes32 _depositDataRoot, uint256 _salt, address _expectedMinipoolAddress) override external payable onlyLatestContract("rocketNodeDeposit", address(this)) onlyRegisteredNode(msg.sender) { + // Use credit balance + require(_useCredit(_bondAmount) == 0, "Invalid value"); + // Process the deposit + _deposit(_bondAmount, _minimumNodeFee, _validatorPubkey, _validatorSignature, _depositDataRoot, _salt, _expectedMinipoolAddress); + } + + function _useCredit(uint256 _bondAmount) private returns (uint256 _surplus) { // Query node's deposit credit uint256 credit = getNodeDepositCredit(msg.sender); // Credit balance accounting if (credit < _bondAmount) { uint256 shortFall = _bondAmount.sub(credit); - require(msg.value == shortFall, "Invalid value"); + require(msg.value >= shortFall, "Invalid value"); setUint(keccak256(abi.encodePacked("node.deposit.credit.balance", msg.sender)), 0); + return msg.value.sub(shortFall); } else { subUint(keccak256(abi.encodePacked("node.deposit.credit.balance", msg.sender)), _bondAmount); + return msg.value; } - // Process the deposit + } + + function depositAndMint(uint256 _bondAmount, uint256 _minimumNodeFee, bytes calldata _validatorPubkey, bytes calldata _validatorSignature, bytes32 _depositDataRoot, uint256 _salt, address _expectedMinipoolAddress) override external payable onlyLatestContract("rocketNodeDeposit", address(this)) onlyRegisteredNode(msg.sender) { + // Use credit balance + uint256 surplus = _useCredit(_bondAmount); + // Deposit the minipool _deposit(_bondAmount, _minimumNodeFee, _validatorPubkey, _validatorSignature, _depositDataRoot, _salt, _expectedMinipoolAddress); + // Mint rETH for the caller + _mint(surplus); + } + + function _mint(uint256 _mintEthAmount) private { + // Deposit ETH to mint rETH + RocketDepositPoolInterface(getContractAddress("rocketDepositPool")).deposit{value: _mintEthAmount}(); + // Transfer minted rETH back to the caller + RocketTokenRETHInterface rocketTokenRETH = RocketTokenRETHInterface(getContractAddress("rocketTokenRETH")); + rocketTokenRETH.transfer(msg.sender, rocketTokenRETH.balanceOf(address(this))); } /// @notice Returns true if the given amount is a valid deposit amount diff --git a/contracts/interface/node/RocketNodeDepositInterface.sol b/contracts/interface/node/RocketNodeDepositInterface.sol index 2be10229b..7553de52c 100644 --- a/contracts/interface/node/RocketNodeDepositInterface.sol +++ b/contracts/interface/node/RocketNodeDepositInterface.sol @@ -8,6 +8,7 @@ interface RocketNodeDepositInterface { function getNodeDepositCredit(address _nodeOperator) external view returns (uint256); function increaseDepositCreditBalance(address _nodeOperator, uint256 _amount) external; function deposit(uint256 _depositAmount, uint256 _minimumNodeFee, bytes calldata _validatorPubkey, bytes calldata _validatorSignature, bytes32 _depositDataRoot, uint256 _salt, address _expectedMinipoolAddress) external payable; + function depositAndMint(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) external;