-
Notifications
You must be signed in to change notification settings - Fork 24
Feat/safe module #107
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
base: main
Are you sure you want to change the base?
Feat/safe module #107
Changes from all commits
35d5ad8
4970baf
a5eef60
5b26779
a96702c
e8c73d9
8a219a6
f976d07
2c7df8a
3dde397
765d974
c224748
dea7cb1
a6bb0da
784ab37
7181fef
03d831c
65cf91d
7590760
84e6025
1cee2cd
aab0b55
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| // SPDX-License-Identifier: MIT | ||
| pragma solidity ^0.8.19; | ||
|
|
||
| interface IETH2DepositContract { | ||
| /// @notice A processed deposit event. | ||
| event DepositEvent( | ||
| bytes pubkey, | ||
| bytes withdrawal_credentials, | ||
| bytes amount, | ||
| bytes signature, | ||
| bytes index | ||
| ); | ||
|
|
||
| /// @notice Submit a Phase 0 DepositData object. | ||
| /// @param pubkey A BLS12-381 public key. | ||
| /// @param withdrawal_credentials Commitment to a public key for withdrawals. | ||
| /// @param signature A BLS12-381 signature. | ||
| /// @param deposit_data_root The SHA-256 hash of the SSZ-encoded DepositData object. | ||
| /// Used as a protection against malformed input. | ||
| function deposit( | ||
| bytes calldata pubkey, | ||
| bytes calldata withdrawal_credentials, | ||
| bytes calldata signature, | ||
| bytes32 deposit_data_root | ||
| ) external payable; | ||
|
|
||
| /// @notice Query the current deposit root hash. | ||
| /// @return The deposit root hash. | ||
| function get_deposit_root() external view returns (bytes32); | ||
|
|
||
| /// @notice Query the current deposit count. | ||
| /// @return The deposit count encoded as a little endian 64-bit number. | ||
| function get_deposit_count() external view returns (bytes memory); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,148 @@ | ||
| // SPDX-License-Identifier: GPL-3.0-or-later | ||
| pragma solidity 0.8.19; | ||
|
|
||
| import {ERC20} from "solady/tokens/ERC20.sol"; | ||
| import {SafeTransferLib} from "solady/utils/SafeTransferLib.sol"; | ||
| import {IETH2DepositContract} from "../interfaces/IETH2DepositContract.sol"; | ||
|
|
||
| contract SimpleETHContributionVault { | ||
| using SafeTransferLib for address; | ||
|
|
||
| /// @notice unathorised user | ||
| /// @param user address of unauthorized user | ||
| error Unauthorized(address user); | ||
|
|
||
| /// @notice cannot rage quit | ||
| error CannotRageQuit(); | ||
|
|
||
| /// @notice incomplete contribution | ||
| error IncompleteContribution(uint256 actual, uint256 expected); | ||
|
|
||
| /// @notice invalid deposit data | ||
| error Invalid__DepositData(); | ||
|
|
||
| /// @notice Invalid Address | ||
| error Invalid__Address(); | ||
|
|
||
| /// @notice Emitted on deposit ETH | ||
| /// @param to address the credited ETH | ||
| /// @param amount Amount of ETH deposit | ||
| event Deposit(address to, uint256 amount); | ||
|
|
||
| /// @notice Emitted on user rage quit | ||
| /// @param to address that received amount | ||
| /// @param amount amount rage quitted | ||
| event RageQuit(address to, uint256 amount); | ||
|
|
||
| /// @notice Emitted on rescue funds | ||
| /// @param amount amount of funds rescued | ||
| event RescueFunds(uint256 amount); | ||
|
|
||
| /// @notice Amount of ETH validator stake | ||
| uint256 internal constant ETH_STAKE = 32 ether; | ||
|
|
||
| /// @notice ETH2 deposit contract | ||
| IETH2DepositContract public immutable depositContract; | ||
|
|
||
| /// @notice Address of gnosis safe | ||
| address public immutable safe; | ||
|
|
||
| /// @notice adress => amount deposited | ||
| mapping(address => uint256) public userBalances; | ||
|
|
||
| /// @notice tracks if validator have been activated | ||
| bool public activated; | ||
|
|
||
| modifier onlySafe() { | ||
| if (msg.sender != safe) revert Unauthorized(msg.sender); | ||
| _; | ||
| } | ||
|
|
||
| constructor(address _safe, address eth2DepositContract) { | ||
| safe = _safe; | ||
| depositContract = IETH2DepositContract(eth2DepositContract); | ||
| } | ||
|
|
||
| receive() external payable { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we calculate at how many contributors might this break with 2100 gas, because the free gas in a We don't have to worry about fallback() when receive() is set, yes?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. not we don't have to worry about fallback()
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The 2100 gas limit doesn't hold here. Any interaction via |
||
| _deposit(msg.sender, msg.value); | ||
| } | ||
|
|
||
| /// @notice deposit ether into the contract | ||
| /// @param to address to credit | ||
| function deposit( | ||
| address to | ||
| ) external payable { | ||
| if (to == address(0)) revert Invalid__Address(); | ||
| _deposit(to, msg.value); | ||
| } | ||
|
|
||
| /// @notice Deposit ETH into ETH2 deposit contract | ||
| /// @param pubkeys Array of validator pub keys | ||
| /// @param withdrawal_credentials Array of validator withdrawal credentials | ||
| /// @param signatures Array of validator signatures | ||
| /// @param deposit_data_roots Array of validator deposit data roots | ||
| function depositValidator( | ||
| bytes[] calldata pubkeys, | ||
| bytes[] calldata withdrawal_credentials, | ||
| bytes[] calldata signatures, | ||
| bytes32[] calldata deposit_data_roots | ||
| ) external onlySafe { | ||
| uint256 size = pubkeys.length; | ||
samparsky marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| if ( | ||
| (withdrawal_credentials.length != size) || | ||
| (signatures.length != size) || | ||
| (deposit_data_roots.length != size) | ||
| ) { | ||
| revert Invalid__DepositData(); | ||
| } | ||
|
|
||
|
|
||
| if (address(this).balance < size * ETH_STAKE) { | ||
| revert IncompleteContribution(address(this).balance, ETH_STAKE * size); | ||
| } | ||
|
|
||
| activated = true; | ||
|
|
||
| for (uint256 i = 0; i < size;) { | ||
| depositContract.deposit{value: ETH_STAKE}( | ||
| pubkeys[i], withdrawal_credentials[i], signatures[i], deposit_data_roots[i] | ||
| ); | ||
|
|
||
| unchecked { | ||
| i++; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /// @notice Exit contribution vault prior to deposit starts | ||
| /// It allows a contributor to exit the vault before any validator is | ||
| /// activated | ||
| /// @param to Address to send funds to | ||
| /// @param amount balance to withdraw | ||
| function rageQuit(address to, uint256 amount) external { | ||
| if (to == address(0)) revert Invalid__Address(); | ||
| if (activated == true) revert CannotRageQuit(); | ||
|
|
||
| userBalances[msg.sender] -= amount; | ||
| to.safeTransferETH(amount); | ||
|
|
||
| emit RageQuit(to, amount); | ||
| } | ||
|
|
||
| /// @notice Rescue non-ETH tokens stuck to the safe | ||
| /// @param token Token address | ||
| /// @param amount amount of balance to transfer to Safe | ||
| function rescueFunds(address token, uint256 amount) external { | ||
samparsky marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| token.safeTransfer(safe, amount); | ||
| emit RescueFunds(amount); | ||
| } | ||
|
|
||
| /// @notice a user deposit | ||
| /// @param to address to receive the deposit | ||
| /// @param amount amount of deposit | ||
| function _deposit(address to, uint256 amount) internal { | ||
| userBalances[to] += amount; | ||
| emit Deposit(to, amount); | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.