-
Notifications
You must be signed in to change notification settings - Fork 21
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
Feat/ fee share #96
Merged
Merged
Feat/ fee share #96
Changes from all commits
Commits
Show all changes
17 commits
Select commit
Hold shift + click to select a range
56ab15f
chore: add feeReceipient to lidosplit
samparsky 39f1e30
test: fix lido test cases
samparsky 2947a47
chore: add wstETH check to rescueFunds; use balanceOf wstETH to calcu…
samparsky 43c14c3
test: add lido fee test cases
samparsky 4d60402
test: add fuzz fee share lidoSplit test case
samparsky 7094988
chore: move IwSTETH to a separate file
samparsky 4c8e5e2
chore: rename IwstETH.sol
samparsky 8d2c8db
chore: fix IwstETH.sol path
samparsky 37f3002
chore: fix IwstETH.sol path
samparsky f2690f9
chore: fix IwstETH.sol path
samparsky fd244a0
chore: rename lidosplit => obollidosplit
samparsky b1ffd3a
chore: update obollidosplit audit docs
samparsky f872529
chore: change IMSC license
samparsky d154d83
chore: change obollido licenses
samparsky 0268631
chore: add fuzz fee recipient check to testFuzz_CanDistributeWithFee
samparsky d6886ee
chore: change fuzz runs to 100
samparsky 3c7061c
chore: change test files licenses to gpl
samparsky File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.19; | ||
|
||
interface IwstETH { | ||
function wrap(uint256 amount) external returns (uint256); | ||
function getWstETHByStETH(uint256 _stETHAmount) external view returns (uint256); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,27 +4,26 @@ 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 {IwstETH} from "src/interfaces/IwstETH.sol"; | ||
|
||
interface IwSTETH { | ||
function wrap(uint256 amount) external returns (uint256); | ||
} | ||
|
||
/// @title LidoSplit | ||
/// @title ObolLidoSplit | ||
/// @author Obol | ||
/// @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 ObolLidoSplit is Clone { | ||
error Invalid_Address(); | ||
|
||
error Invalid_FeeShare(uint256 fee); | ||
error Invalid_FeeRecipient(); | ||
|
||
/// ----------------------------------------------------------------------- | ||
/// libraries | ||
/// ----------------------------------------------------------------------- | ||
using SafeTransferLib for ERC20; | ||
using SafeTransferLib for address; | ||
|
||
address internal constant ETH_ADDRESS = address(0); | ||
uint256 internal constant PERCENTAGE_SCALE = 1e5; | ||
|
||
/// ----------------------------------------------------------------------- | ||
/// storage - cwia offsets | ||
|
@@ -34,20 +33,35 @@ 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 fee address | ||
address public immutable feeRecipient; | ||
|
||
/// @notice fee share | ||
uint256 public immutable feeShare; | ||
|
||
/// @notice Constructor | ||
/// @param _feeRecipient address to receive fee | ||
/// @param _feeShare fee share scaled by PERCENTAGE_SCALE | ||
/// @param _stETH stETH address | ||
/// @param _wstETH wstETH address | ||
constructor(address _feeRecipient, uint256 _feeShare, ERC20 _stETH, ERC20 _wstETH) { | ||
samparsky marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if (_feeShare >= PERCENTAGE_SCALE) revert Invalid_FeeShare(_feeShare); | ||
if (_feeShare > 0 && _feeRecipient == address(0)) revert Invalid_FeeRecipient(); | ||
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. Great catch! This would brick the contract because of a revert in the transfer. |
||
|
||
feeRecipient = _feeRecipient; | ||
stETH = _stETH; | ||
wstETH = _wstETH; | ||
feeShare = _feeShare; | ||
} | ||
|
||
/// Address of split wallet to send funds to to | ||
|
@@ -65,17 +79,33 @@ contract LidoSplit is Clone { | |
// approve the wstETH | ||
stETH.approve(address(wstETH), balance); | ||
// wrap into wseth | ||
amount = IwSTETH(address(wstETH)).wrap(balance); | ||
// transfer to split wallet | ||
ERC20(wstETH).safeTransfer(splitWallet(), amount); | ||
// we ignore the return value | ||
IwstETH(address(wstETH)).wrap(balance); | ||
// we use balanceOf here in case some wstETH is stuck in the | ||
// contract we would be able to rescue it | ||
amount = ERC20(wstETH).balanceOf(address(this)); | ||
|
||
if (feeShare > 0) { | ||
uint256 fee = (amount * feeShare) / PERCENTAGE_SCALE; | ||
// transfer to split wallet | ||
// update amount to reflect fee charged | ||
ERC20(wstETH).safeTransfer(splitWallet(), amount -= fee); | ||
// transfer to fee address | ||
ERC20(wstETH).safeTransfer(feeRecipient, fee); | ||
} else { | ||
// transfer to split wallet | ||
ERC20(wstETH).safeTransfer(splitWallet(), amount); | ||
} | ||
} | ||
|
||
/// @notice Rescue stuck ETH and tokens | ||
/// Uses token == address(0) to represent ETH | ||
/// @return balance Amount of ETH or tokens rescued | ||
function rescueFunds(address token) external returns (uint256 balance) { | ||
if (token == address(stETH)) revert Invalid_Address(); | ||
|
||
// we check wstETH here so rescueFunds can't be used | ||
// to bypass fee | ||
if (token == address(stETH) || token == address(wstETH)) revert Invalid_Address(); | ||
samparsky marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
if (token == ETH_ADDRESS) { | ||
balance = address(this).balance; | ||
if (balance > 0) splitWallet().safeTransferETH(balance); | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assume this is an intentional decision, but of course these being immutably set on the implementation means they can't ever be updated. If you wanted the ability to change while still setting immutably on the implementation, you'd need to immutably set an address for another contract that holds and returns the fee info, and allows updates.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, we don't want the fee to change. Changing the fee would require a sign-off from Lido and a lot of discussions and most likely require new deployments.