From c5b03be849490c08e6e4ccd92621da4f18004a0a Mon Sep 17 00:00:00 2001 From: Ramana Kumar Date: Mon, 14 Nov 2022 21:42:00 +0000 Subject: [PATCH 1/2] Add depositAndMint --- contracts/contract/node/RocketNodeDeposit.sol | 32 +++++++++++++++++-- .../node/RocketNodeDepositInterface.sol | 1 + 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/contracts/contract/node/RocketNodeDeposit.sol b/contracts/contract/node/RocketNodeDeposit.sol index 67c5beb14..8fbb03a7e 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,45 @@ 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 { + // Save current rETH balance (for calculating how much rETH is minted) + RocketTokenRETHInterface rocketTokenRETH = RocketTokenRETHInterface(getContractAddress("rocketTokenRETH")); + uint256 rETHBefore = rocketTokenRETH.balanceOf(address(this)); + // Deposit ETH to mint rETH + RocketDepositPoolInterface rocketDepositPool = RocketDepositPoolInterface(getContractAddress("rocketDepositPool")); + rocketDepositPool.deposit{value: _mintEthAmount}(); + // Transfer minted rETH back to the caller + rocketTokenRETH.transfer(msg.sender, rocketTokenRETH.balanceOf(address(this)) - rETHBefore); } /// @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; From a744b1c0bdc2492dc8305c638e55d87e0c8cf080 Mon Sep 17 00:00:00 2001 From: Ramana Kumar Date: Mon, 14 Nov 2022 21:54:36 +0000 Subject: [PATCH 2/2] Do not bother with rETHBefore Sending rETH to this contract means sending it to whatever lucky NO calls depositAndMint next. --- contracts/contract/node/RocketNodeDeposit.sol | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/contracts/contract/node/RocketNodeDeposit.sol b/contracts/contract/node/RocketNodeDeposit.sol index 8fbb03a7e..70086422a 100644 --- a/contracts/contract/node/RocketNodeDeposit.sol +++ b/contracts/contract/node/RocketNodeDeposit.sol @@ -88,14 +88,11 @@ contract RocketNodeDeposit is RocketBase, RocketNodeDepositInterface { } function _mint(uint256 _mintEthAmount) private { - // Save current rETH balance (for calculating how much rETH is minted) - RocketTokenRETHInterface rocketTokenRETH = RocketTokenRETHInterface(getContractAddress("rocketTokenRETH")); - uint256 rETHBefore = rocketTokenRETH.balanceOf(address(this)); // Deposit ETH to mint rETH - RocketDepositPoolInterface rocketDepositPool = RocketDepositPoolInterface(getContractAddress("rocketDepositPool")); - rocketDepositPool.deposit{value: _mintEthAmount}(); + RocketDepositPoolInterface(getContractAddress("rocketDepositPool")).deposit{value: _mintEthAmount}(); // Transfer minted rETH back to the caller - rocketTokenRETH.transfer(msg.sender, rocketTokenRETH.balanceOf(address(this)) - rETHBefore); + 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