Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Additional LidoSplit Functions #92

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions src/interfaces/lido/IEasyTrackMotion.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.19;

interface IEasyTrackMotion {

/// @notice Creates new motion
/// @param _evmScriptFactory Address of EVMScript factory registered in Easy Track
/// @param _evmScriptCallData Encoded call data of EVMScript factory
/// @return _newMotionId Id of created motion
function createMotion(address _evmScriptFactory, bytes calldata _evmScriptCallData) external returns (uint256 _newMotionId);
}
22 changes: 22 additions & 0 deletions src/interfaces/lido/INodeOperatorRegistry.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.19;

interface INodeOperatorRegistry {

/// @notice Add `_quantity` validator signing keys to the keys of the node operator #`_nodeOperatorId`. Concatenated keys are: `_pubkeys`
/// @dev Along with each key the DAO has to provide a signatures for the
/// (pubkey, withdrawal_credentials, 32000000000) message.
/// Given that information, the contract'll be able to call
/// deposit_contract.deposit on-chain.
/// @param _nodeOperatorId Node Operator id
/// @param _keysCount Number of signing keys provided
/// @param _publicKeys Several concatenated validator signing keys
/// @param _signatures Several concatenated signatures for (pubkey, withdrawal_credentials, 32000000000) messages
function addSigningKeys(uint256 _nodeOperatorId, uint256 _keysCount, bytes calldata _publicKeys, bytes calldata _signatures) external;

/// @notice Removes an #`_keysCount` of validator signing keys starting from #`_index` of operator #`_id` usable keys. Executed on behalf of DAO.
/// @param _nodeOperatorId Node Operator id
/// @param _fromIndex Index of the key, starting with 0
/// @param _keysCount Number of keys to remove
function removeSigningKeys(uint256 _nodeOperatorId, uint256 _fromIndex, uint256 _keysCount) external;
}
104 changes: 96 additions & 8 deletions src/lido/LidoSplit.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ pragma solidity 0.8.19;
import {ERC20} from "solmate/tokens/ERC20.sol";
import {SafeTransferLib} from "solmate/utils/SafeTransferLib.sol";
import {Clone} from "solady/utils/Clone.sol";
import {Ownable} from "solady/auth/Ownable.sol";
import {INodeOperatorRegistry} from "src/interfaces/lido/INodeOperatorRegistry.sol";
import {IEasyTrackMotion} from "src/interfaces/lido/IEasyTrackMotion.sol";

interface IwSTETH {
function wrap(uint256 amount) external returns (uint256);
Expand All @@ -14,10 +17,15 @@ interface IwSTETH {
/// @notice A wrapper for 0xsplits/split-contracts SplitWallet that transforms
/// stETH token to wstETH token because stETH is a rebasing token
/// @dev Wraps stETH to wstETH and transfers to defined SplitWallet address
contract LidoSplit is Clone {

contract LidoSplit is Clone, Ownable {
error Invalid_Address();


/// @notice Call
struct Call {
address target;
bytes callData;
}

/// -----------------------------------------------------------------------
/// libraries
/// -----------------------------------------------------------------------
Expand All @@ -34,20 +42,33 @@ contract LidoSplit is Clone {
// 0; first item
uint256 internal constant SPLIT_WALLET_ADDRESS_OFFSET = 0;


/// -----------------------------------------------------------------------
/// storage
/// -----------------------------------------------------------------------

/// @notice stETH token
ERC20 public immutable stETH;

/// @notice wstETH token
ERC20 public immutable wstETH;

constructor(ERC20 _stETH, ERC20 _wstETH) {
/// @notice node operator registry
INodeOperatorRegistry public immutable nosRegistry;

/// @notice Easy track motion contract
IEasyTrackMotion public immutable easyTrackMotion;

constructor(ERC20 _stETH, ERC20 _wstETH, address _nosRegistry, address _etMotion) {
stETH = _stETH;
wstETH = _wstETH;
nosRegistry = INodeOperatorRegistry(_nosRegistry);
easyTrackMotion = IEasyTrackMotion(_etMotion);
}

function intialize(address _owner) external {
if (owner() != address(0)) revert Initialized();

_initializeOwner(_owner);
}

/// Address of split wallet to send funds to to
Expand All @@ -70,12 +91,47 @@ contract LidoSplit is Clone {
ERC20(wstETH).safeTransfer(splitWallet(), amount);
}

/// @notice Add node operator signing keys
/// @param _nodeOperatorId Node Operator id
/// @param _keysCount Number of signing keys provided
/// @param _publicKeys Several concatenated validator signing keys
/// @param _signatures Several concatenated signatures for (pubkey, withdrawal_credentials, 32000000000) messages
function addSigningKeys(
uint256 _nodeOperatorId,
uint256 _keysCount,
bytes calldata _publicKeys,
bytes calldata _signatures
) external onlyOwner {
nos.addSigningKeys(_nodeOperatorId, _keysCount, _publicKeys, _signatures);
}

/// @notice Removes node operator signing keys
/// @param _nodeOperatorId Node Operator id
/// @param _keysCount Number of signing keys provided
/// @param _publicKeys Several concatenated validator signing keys
/// @param _signatures Several concatenated signatures for (pubkey, withdrawal_credentials, 32000000000) messages
function removeSigningKeys(uint256 _nodeOperatorId, uint256 _fromIndex, uint256 _keysCount) external onlyOwner {
nos.removeSigningKeys(_nodeOperatorId, _fromIndex, _keysCount);
}

/// @notice Create easy track motions
/// @param _evmScriptFactory Address of EVMScript factory registered in Easy Track
/// @param _evmScriptCallData Encoded call data of EVMScript factory
/// @return _newMotionId Id of created motion
function createEasyTrackMotion(address _evmScriptFactory, bytes calldata _evmScriptCallData)
external
onlyOwner
returns (uint256 newMotionId)
{
newMotionId = easyTrackMotion.createMotion(_evmScriptFactory, _evmScriptCallData);
}

/// @notice Rescue stuck ETH
/// Uses token == address(0) to represent ETH
/// @return balance Amount of ETH rescued
function rescueFunds(address token) external returns (uint256 balance) {
if (token == address(stETH)) revert Invalid_Address();
if (token == address(stETH)) revert Invalid_Address();

if (token == ETH_ADDRESS) {
balance = address(this).balance;
if (balance > 0) splitWallet().safeTransferETH(balance);
Expand All @@ -84,4 +140,36 @@ contract LidoSplit is Clone {
if (balance > 0) ERC20(token).transfer(splitWallet(), balance);
}
}

/// @notice Execute custom calls
/// @param calls An array of Call structs
/// @return blockNumber The block number where the calls were executed
/// @return returnData An array of bytes containing the responses
function executeCalls(Call[] calldata calls)
public
payable
onlyOwner
returns (uint256 blockNumber, bytes[] memory returnData)
{

blockNumber = block.number;
uint256 length = calls.length;
returnData = new bytes[](length);
Call calldata call;

for (uint256 i = 0; i < length;) {

// prevent calls to stETH address to prevent stealing of user funds
// prevent calls to self
if (call.target == address(stETH) || call.target == address(this)) revert Invalid_Address();

bool success;
call = calls[i];
(success, returnData[i]) = call.target.call(call.callData);
require(success, "executeCalls: call failed");
unchecked {
++i;
}
}
}
}
19 changes: 15 additions & 4 deletions src/lido/LidoSplitFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -36,18 +36,29 @@ contract LidoSplitFactory {
/// @dev lido split implementation
LidoSplit public immutable lidoSplitImpl;

constructor(ERC20 _stETH, ERC20 _wstETH) {
lidoSplitImpl = new LidoSplit(_stETH, _wstETH);
constructor(
ERC20 _stETH,
ERC20 _wstETH,
address _nosRegistry,
address _etMotion
) {
lidoSplitImpl = new LidoSplit(_stETH, _wstETH, _nosRegistry, _etMotion);
// initialize implementation to prevent rogue
// actor initialisation
lidoSplitImpl.intialize(address(1));
}

/// Creates a wrapper for splitWallet that transforms stETH token into
/// wstETH
/// wstETH and can create ET motions
/// @param splitWallet Address of the splitWallet to transfer wstETH to
/// @return lidoSplit Address of the wrappper split
function createSplit(address splitWallet) external returns (address lidoSplit) {
function createSplit(address splitWallet, address owner) external returns (address lidoSplit) {
if (splitWallet == address(0)) revert Invalid_Wallet();
if (owner == address(0)) revert Invalid_Owner();

lidoSplit = address(lidoSplitImpl).clone(abi.encodePacked(splitWallet));
// intialize owner address
LidoSplit(lidoSplit).intialize(owner);

emit CreateLidoSplit(lidoSplit);
}
Expand Down
21 changes: 20 additions & 1 deletion src/test/lido/LidoSplit.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ contract LidoSplitTest is LidoSplitTestHelper, Test {

function test_CanDistribute() public {
// we use a random account on Etherscan to credit the lidoSplit address
// with 10 ether worth of stETH on mainnet
// with 10 ether worth of stETH on mainnet fork
vm.prank(0x2bf3937b8BcccE4B65650F122Bb3f1976B937B2f);
ERC20(STETH_MAINNET_ADDRESS).transfer(address(lidoSplit), 100 ether);

Expand All @@ -80,4 +80,23 @@ contract LidoSplitTest is LidoSplitTestHelper, Test {

assertGe(afterBalance, prevBalance, "after balance greater");
}

function test_CanAddSigningKeys() public {
// we use a random account on Etherscan
// as the node operator on mainnet fork
vm.prank();



}

function test_CanRemoveSigningKeys() public {

}

function test_CanCreateETMotions() public {

}
Comment on lines +87 to +99
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not finished it seems



}
Loading