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

weETH withdrawal: Instant withdrawal with Fee + Implicit withdrawal fee handling #207

Open
wants to merge 99 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
99 commits
Select commit Hold shift + click to select a range
d356cc9
init. Instant Withdrawal via Buffer
seongyun-ko Dec 6, 2024
82fab2e
implemented instant fee mechanism, handling of the implicit fee
seongyun-ko Dec 9, 2024
0f13953
fix scripts
seongyun-ko Dec 12, 2024
0b68310
add role registry, consider eth amount locked for withdrawal in liqui…
seongyun-ko Dec 17, 2024
c9fd604
use setter for 'shareRemainderSplitToTreasuryInBps', add more fuzz te…
seongyun-ko Dec 19, 2024
c377e8e
handle issues in calculating the dust shares
seongyun-ko Dec 20, 2024
a3aeac9
improve comments
seongyun-ko Dec 20, 2024
57bd0fc
add sorted & unique constraints + type change to reduce gas
seongyun-ko Dec 24, 2024
b6100b6
update 'handleAccumulatedShareRemainder' to be callable by admin
seongyun-ko Dec 24, 2024
e8734d6
Certora audit: (1) add {aggregateSumEEthShareAmount}, (2) fix {_claim…
seongyun-ko Dec 26, 2024
71ffa8d
wip: to be amended
seongyun-ko Dec 30, 2024
9e0fb99
add simplified {invalidate, validate} request, fix unit tests
seongyun-ko Dec 30, 2024
98f483a
rename EtherFiWithdrawBuffer -> EtherFiRedemptionManager
seongyun-ko Dec 30, 2024
bcc1184
fix the logic to check the aggr calls
seongyun-ko Dec 30, 2024
1f85fb6
Update test/WithdrawRequestNFT.t.sol
jtfirek Dec 30, 2024
bdee463
reduce gas spending for 'call', update the upgrade init function, rem…
seongyun-ko Dec 30, 2024
d40a117
apply gas opt for BucketLimiter
seongyun-ko Dec 30, 2024
f4f2ffd
improve assetion tsets, apply design pattern, function rename
seongyun-ko Dec 30, 2024
5069c14
apply CEI pattern to 'handleRemainder'
seongyun-ko Dec 30, 2024
2e13202
apply CEI pattern to 'redeem'
seongyun-ko Dec 31, 2024
b18bd18
use 'totalRemainderEEthShares' instead of locked share
seongyun-ko Dec 31, 2024
1e12673
initializeOnUpgrade cant be called twice
seongyun-ko Dec 31, 2024
c14c348
initializeOnUpgrade onlyOnce
seongyun-ko Dec 31, 2024
35fba66
use uint256 instead of uint32
seongyun-ko Dec 31, 2024
e95cfc0
revert
seongyun-ko Dec 31, 2024
bbf2d83
improve the fuzz test
seongyun-ko Dec 31, 2024
2cbbc04
(1) pause the contract on upgrade, (2) prevent from calling 'aggregat…
seongyun-ko Jan 1, 2025
1482cb0
only owner of the funds can call {redeemEEth, redeemWeEth}
seongyun-ko Jan 2, 2025
8ced81e
disable unpause until the scan is completed
seongyun-ko Jan 2, 2025
86ac4a0
check the basis points params are below 1e4
seongyun-ko Jan 2, 2025
1e8cdea
disallow calling 'initializeOnUpgradeWithRedemptionManager' with inva…
seongyun-ko Jan 2, 2025
6fffba6
(1) withdrawRequestNFT cannot call LiquidityPool.addEthAmountLockedFo…
seongyun-ko Jan 2, 2025
89db9d5
prevent finalizing future requests
seongyun-ko Jan 2, 2025
c5a2dd1
add {redeemEEthWithPermit, redeemWeEthWithPermit}, use try-catch for
seongyun-ko Jan 2, 2025
c85e920
remove a redundant check
seongyun-ko Jan 2, 2025
cca361e
Prevent 'initializeOnUpgrade' of LiquidityPool from being called twic…
seongyun-ko Jan 2, 2025
268efe5
use 'isScanOfShareRemainderCompleted'
seongyun-ko Jan 2, 2025
a13919d
add the max value constraint on rate limit
seongyun-ko Jan 2, 2025
58fe3fb
remove equality condition
seongyun-ko Jan 2, 2025
898896a
fix the overflow issue in '_refill'
seongyun-ko Jan 2, 2025
25ac914
Update EtherFiRedemptionManager.sol
seongyun-ko Jan 2, 2025
fd52a52
prevent the total shares from going below 1 gwei after redemption
seongyun-ko Jan 2, 2025
6eefec0
init. Instant Withdrawal via Buffer
seongyun-ko Dec 6, 2024
9963471
implemented instant fee mechanism, handling of the implicit fee
seongyun-ko Dec 9, 2024
9dcb732
fix scripts
seongyun-ko Dec 12, 2024
0e35c6b
add role registry, consider eth amount locked for withdrawal in liqui…
seongyun-ko Dec 17, 2024
77e61d8
use setter for 'shareRemainderSplitToTreasuryInBps', add more fuzz te…
seongyun-ko Dec 19, 2024
1435cc8
handle issues in calculating the dust shares
seongyun-ko Dec 20, 2024
8565d21
improve comments
seongyun-ko Dec 20, 2024
805bf07
add sorted & unique constraints + type change to reduce gas
seongyun-ko Dec 24, 2024
2de521a
update 'handleAccumulatedShareRemainder' to be callable by admin
seongyun-ko Dec 24, 2024
fc4a179
Certora audit: (1) add {aggregateSumEEthShareAmount}, (2) fix {_claim…
seongyun-ko Dec 26, 2024
8acd291
wip: to be amended
seongyun-ko Dec 30, 2024
a7e974b
add simplified {invalidate, validate} request, fix unit tests
seongyun-ko Dec 30, 2024
83bcd4f
rename EtherFiWithdrawBuffer -> EtherFiRedemptionManager
seongyun-ko Dec 30, 2024
34f67b9
fix the logic to check the aggr calls
seongyun-ko Dec 30, 2024
da5af14
Update test/WithdrawRequestNFT.t.sol
jtfirek Dec 30, 2024
577587b
reduce gas spending for 'call', update the upgrade init function, rem…
seongyun-ko Dec 30, 2024
980af7d
apply gas opt for BucketLimiter
seongyun-ko Dec 30, 2024
599d287
improve assetion tsets, apply design pattern, function rename
seongyun-ko Dec 30, 2024
5bd6630
apply CEI pattern to 'handleRemainder'
seongyun-ko Dec 30, 2024
2dd2115
apply CEI pattern to 'redeem'
seongyun-ko Dec 31, 2024
fbcd9f1
use 'totalRemainderEEthShares' instead of locked share
seongyun-ko Dec 31, 2024
3730663
initializeOnUpgrade cant be called twice
seongyun-ko Dec 31, 2024
72172e1
initializeOnUpgrade onlyOnce
seongyun-ko Dec 31, 2024
9dd6db1
use uint256 instead of uint32
seongyun-ko Dec 31, 2024
b61899b
revert
seongyun-ko Dec 31, 2024
80c21be
improve the fuzz test
seongyun-ko Dec 31, 2024
4862685
(1) pause the contract on upgrade, (2) prevent from calling 'aggregat…
seongyun-ko Jan 1, 2025
f36c180
only owner of the funds can call {redeemEEth, redeemWeEth}
seongyun-ko Jan 2, 2025
3356771
disable unpause until the scan is completed
seongyun-ko Jan 2, 2025
ddd1b59
check the basis points params are below 1e4
seongyun-ko Jan 2, 2025
43a5a5e
disallow calling 'initializeOnUpgradeWithRedemptionManager' with inva…
seongyun-ko Jan 2, 2025
aa53280
(1) withdrawRequestNFT cannot call LiquidityPool.addEthAmountLockedFo…
seongyun-ko Jan 2, 2025
8ae4844
prevent finalizing future requests
seongyun-ko Jan 2, 2025
26b5a0b
add {redeemEEthWithPermit, redeemWeEthWithPermit}, use try-catch for
seongyun-ko Jan 2, 2025
a785f25
remove a redundant check
seongyun-ko Jan 2, 2025
8785224
Prevent 'initializeOnUpgrade' of LiquidityPool from being called twic…
seongyun-ko Jan 2, 2025
edc30cb
use 'isScanOfShareRemainderCompleted'
seongyun-ko Jan 2, 2025
b666808
add the max value constraint on rate limit
seongyun-ko Jan 2, 2025
23fd48b
remove equality condition
seongyun-ko Jan 2, 2025
7a909ac
fix the overflow issue in '_refill'
seongyun-ko Jan 2, 2025
0e6662b
Update EtherFiRedemptionManager.sol
seongyun-ko Jan 2, 2025
f2cbc82
prevent the total shares from going below 1 gwei after redemption
seongyun-ko Jan 2, 2025
d193b00
fixes for Instant Withdrawal
shivam-ef Jan 16, 2025
17aabaa
fix: certora audit fixes
shivam-ef Jan 20, 2025
c782ab3
changed gas limit in redemption to 50k from 10k
shivam-ef Jan 20, 2025
b877f7e
added only liquidity pool to burn shares
shivam-ef Jan 20, 2025
3128cf3
remove batch cancel deposit by admin since not required
shivam-ef Jan 21, 2025
fdbf21a
Merge branch 'syko/feature/instant_withdrawal' of https://github.com/…
shivam-ef Jan 21, 2025
1cb9971
Merge branch 'master' of https://github.com/etherfi-protocol/smart-co…
shivam-ef Jan 22, 2025
fd0f75f
Merge branch 'syko/feature/instant_withdrawal' of https://github.com/…
shivam-ef Jan 22, 2025
ce827c2
removed duplicate bytecode_hash config from foundry.toml and added au…
shivam-ef Jan 23, 2025
3230fa7
instant withdrawal upgrade prepared
shivam-ef Jan 24, 2025
07bbcfa
instant withdrawal script
shivam-ef Jan 28, 2025
3b4be39
deployed instant withdrawal upgrade
shivam-ef Jan 28, 2025
c2e6a53
fix test
shivam-ef Jan 28, 2025
95cfaaa
Rename 2025.01.23 - Certora - EtherFi - Withdrawal Fee - Re-audit.pdf…
seongyun-ko Feb 6, 2025
824bcf8
Merge pull request #227 from etherfi-protocol/shivam/fix/instant_with…
shivam-ef Feb 10, 2025
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
5 changes: 5 additions & 0 deletions lib/BucketLimiter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@ library BucketLimiter {
return limit.remaining >= amount;
}

function consumable(Limit memory limit) external view returns (uint64) {
_refill(limit);
return limit.remaining;
}

/*
* Consumes the given amount from the bucket, if there is sufficient capacity, and returns
* whether the bucket had enough remaining capacity to consume the amount.
Expand Down
2 changes: 1 addition & 1 deletion script/deploys/DeployPhaseTwo.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ contract DeployPhaseTwoScript is Script {
}
retrieve_contract_addresses();

withdrawRequestNftImplementation = new WithdrawRequestNFT();
withdrawRequestNftImplementation = new WithdrawRequestNFT(address(0), 0);
withdrawRequestNftProxy = new UUPSProxy(address(withdrawRequestNftImplementation), "");
withdrawRequestNftInstance = WithdrawRequestNFT(payable(withdrawRequestNftProxy));

Expand Down
2 changes: 1 addition & 1 deletion script/upgrades/WithdrawRequestNFTUpgradeScript.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ contract WithdrawRequestNFTUpgrade is Script {
vm.startBroadcast(deployerPrivateKey);

WithdrawRequestNFT oracleInstance = WithdrawRequestNFT(proxyAddress);
WithdrawRequestNFT v2Implementation = new WithdrawRequestNFT();
WithdrawRequestNFT v2Implementation = new WithdrawRequestNFT(address(0), 0);

oracleInstance.upgradeTo(address(v2Implementation));

Expand Down
249 changes: 249 additions & 0 deletions src/EtherFiWithdrawalBuffer.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,249 @@
// SPDX-License-Identifier: MIT
seongyun-ko marked this conversation as resolved.
Show resolved Hide resolved
pragma solidity ^0.8.13;

import "@openzeppelin/contracts/utils/math/SafeCast.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol";
import "@openzeppelin-upgradeable/contracts/token/ERC20/IERC20Upgradeable.sol";
import "@openzeppelin-upgradeable/contracts/proxy/utils/Initializable.sol";
import "@openzeppelin-upgradeable/contracts/proxy/utils/UUPSUpgradeable.sol";
import "@openzeppelin-upgradeable/contracts/security/ReentrancyGuardUpgradeable.sol";
import "@openzeppelin-upgradeable/contracts/access/OwnableUpgradeable.sol";
import "@openzeppelin-upgradeable/contracts/security/PausableUpgradeable.sol";

import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/utils/math/Math.sol";

import "./interfaces/ILiquidityPool.sol";
import "./interfaces/IeETH.sol";
import "./interfaces/IWeETH.sol";

import "lib/BucketLimiter.sol";


/*
The contract allows instant redemption of eETH and weETH tokens to ETH with an exit fee.
- It has the exit fee as a percentage of the total amount redeemed.
- It has a rate limiter to limit the total amount that can be redeemed in a given time period.
*/
contract EtherFiWithdrawalBuffer is Initializable, OwnableUpgradeable, PausableUpgradeable, ReentrancyGuardUpgradeable, UUPSUpgradeable {
using SafeERC20 for IERC20;
using Math for uint256;

uint256 private constant BUCKET_UNIT_SCALE = 1e12;
uint256 private constant BASIS_POINT_SCALE = 1e4;
address public immutable treasury;
IeETH public immutable eEth;
IWeETH public immutable weEth;
ILiquidityPool public immutable liquidityPool;

BucketLimiter.Limit public limit;
uint16 public exitFeeSplitToTreasuryInBps;
uint16 public exitFeeInBps;
uint16 public lowWatermarkInBpsOfTvl; // bps of TVL

receive() external payable {}

/// @custom:oz-upgrades-unsafe-allow constructor
constructor(address _liquidityPool, address _eEth, address _weEth, address _treasury) {
require(address(liquidityPool) == address(0) && address(eEth) == address(0) && address(treasury) == address(0), "EtherFiWithdrawalBuffer: Cannot initialize twice");

treasury = _treasury;
liquidityPool = ILiquidityPool(payable(_liquidityPool));
eEth = IeETH(_eEth);
weEth = IWeETH(_weEth);

_disableInitializers();
}

function initialize(uint16 _exitFeeSplitToTreasuryInBps, uint16 _exitFeeInBps, uint16 _lowWatermarkInBpsOfTvl) external initializer {
__Ownable_init();
__UUPSUpgradeable_init();
__Pausable_init();
__ReentrancyGuard_init();

limit = BucketLimiter.create(0, 0);
exitFeeSplitToTreasuryInBps = _exitFeeSplitToTreasuryInBps;
exitFeeInBps = _exitFeeInBps;
lowWatermarkInBpsOfTvl = _lowWatermarkInBpsOfTvl;
}

/**
* @notice Redeems eETH for ETH.
* @param eEthAmount The amount of eETH to redeem after the exit fee.
* @param receiver The address to receive the redeemed ETH.
* @param owner The address of the owner of the eETH.
* @return The amount of ETH sent to the receiver and the exit fee amount.
*/
function redeemEEth(uint256 eEthAmount, address receiver, address owner) public whenNotPaused nonReentrant returns (uint256, uint256) {
require(canRedeem(eEthAmount), "EtherFiWithdrawalBuffer: Exceeded total redeemable amount");
require(eEthAmount <= eEth.balanceOf(owner), "EtherFiWithdrawalBuffer: Insufficient balance");

uint256 beforeEEthAmount = eEth.balanceOf(address(this));
jtfirek marked this conversation as resolved.
Show resolved Hide resolved
IERC20(address(eEth)).safeTransferFrom(owner, address(this), eEthAmount);
uint256 afterEEthAmount = eEth.balanceOf(address(this));

uint256 transferredEEthAmount = afterEEthAmount - beforeEEthAmount;
return _redeem(transferredEEthAmount, receiver);
}

/**
* @notice Redeems weETH for ETH.
* @param weEthAmount The amount of weETH to redeem after the exit fee.
* @param receiver The address to receive the redeemed ETH.
* @param owner The address of the owner of the weETH.
* @return The amount of ETH sent to the receiver and the exit fee amount.
*/
function redeemWeEth(uint256 weEthAmount, address receiver, address owner) public whenNotPaused nonReentrant returns (uint256, uint256) {
uint256 eEthShares = weEthAmount;
uint256 eEthAmount = liquidityPool.amountForShare(eEthShares);
require(canRedeem(eEthAmount), "EtherFiWithdrawalBuffer: Exceeded total redeemable amount");
require(weEthAmount <= weEth.balanceOf(owner), "EtherFiWithdrawalBuffer: Insufficient balance");

uint256 beforeEEthAmount = eEth.balanceOf(address(this));
IERC20(address(weEth)).safeTransferFrom(owner, address(this), weEthAmount);
weEth.unwrap(weEthAmount);
uint256 afterEEthAmount = eEth.balanceOf(address(this));

uint256 transferredEEthAmount = afterEEthAmount - beforeEEthAmount;
return _redeem(transferredEEthAmount, receiver);
}


/**
* @notice Redeems ETH.
* @param ethAmount The amount of ETH to redeem after the exit fee.
* @param receiver The address to receive the redeemed ETH.
* @return The amount of ETH sent to the receiver and the exit fee amount.
*/
function _redeem(uint256 ethAmount, address receiver) internal returns (uint256, uint256) {
_updateRateLimit(ethAmount);

uint256 ethShares = liquidityPool.sharesForAmount(ethAmount);
uint256 ethShareToReceiver = ethShares.mulDiv(BASIS_POINT_SCALE - exitFeeInBps, BASIS_POINT_SCALE);
uint256 eEthAmountToReceiver = liquidityPool.amountForShare(ethShareToReceiver);

uint256 prevLpBalance = address(liquidityPool).balance;
uint256 prevBalance = address(this).balance;
uint256 burnedShares = (eEthAmountToReceiver > 0) ? liquidityPool.withdraw(address(this), eEthAmountToReceiver) : 0;
uint256 ethReceived = address(this).balance - prevBalance;

uint256 ethShareFee = ethShares - burnedShares;
uint256 eEthAmountFee = liquidityPool.amountForShare(ethShareFee);
uint256 feeShareToTreasury = ethShareFee.mulDiv(exitFeeSplitToTreasuryInBps, BASIS_POINT_SCALE);
uint256 eEthFeeAmountToTreasury = liquidityPool.amountForShare(feeShareToTreasury);
uint256 feeShareToStakers = ethShareFee - feeShareToTreasury;

// To Stakers by burning shares
eEth.burnShares(address(this), liquidityPool.sharesForAmount(feeShareToStakers));

// To Treasury by transferring eETH
IERC20(address(eEth)).safeTransfer(treasury, eEthFeeAmountToTreasury);

// To Receiver by transferring ETH
payable(receiver).transfer(ethReceived);
require(address(liquidityPool).balance == prevLpBalance - ethReceived, "EtherFiWithdrawalBuffer: Transfer failed");

return (ethReceived, eEthAmountFee);
}

/**
* @dev if the contract has less than the low watermark, it will not allow any instant redemption.
*/
function lowWatermarkInETH() public view returns (uint256) {
return liquidityPool.getTotalPooledEther().mulDiv(lowWatermarkInBpsOfTvl, BASIS_POINT_SCALE);
}

/**
* @dev Returns the total amount that can be redeemed.
*/
function totalRedeemableAmount() external view returns (uint256) {
if (address(liquidityPool).balance < lowWatermarkInETH()) {
return 0;
}
uint64 consumableBucketUnits = BucketLimiter.consumable(limit);
uint256 consumableAmount = _convertBucketUnitToAmount(consumableBucketUnits);
return consumableAmount;
}

/**
* @dev Returns whether the given amount can be redeemed.
* @param amount The ETH or eETH amount to check.
*/
function canRedeem(uint256 amount) public view returns (bool) {
if (address(liquidityPool).balance < lowWatermarkInETH()) {
return false;
}
uint64 bucketUnit = _convertSharesToBucketUnit(amount, Math.Rounding.Up);
bool consumable = BucketLimiter.canConsume(limit, bucketUnit);
return consumable;
}

/**
* @dev Sets the maximum size of the bucket that can be consumed in a given time period.
* @param capacity The capacity of the bucket.
*/
function setCapacity(uint256 capacity) external onlyOwner {
// max capacity = max(uint64) * 1e12 ~= 16 * 1e18 * 1e12 = 16 * 1e12 ether, which is practically enough
uint64 bucketUnit = _convertSharesToBucketUnit(capacity, Math.Rounding.Down);
BucketLimiter.setCapacity(limit, bucketUnit);
}

/**
* @dev Sets the rate at which the bucket is refilled per second.
* @param refillRate The rate at which the bucket is refilled per second.
*/
function setRefillRatePerSecond(uint256 refillRate) external onlyOwner {
// max refillRate = max(uint64) * 1e12 ~= 16 * 1e18 * 1e12 = 16 * 1e12 ether per second, which is practically enough
uint64 bucketUnit = _convertSharesToBucketUnit(refillRate, Math.Rounding.Down);
BucketLimiter.setRefillRate(limit, bucketUnit);
}

/**
* @dev Sets the exit fee.
* @param _exitFeeInBps The exit fee.
*/
function setExitFeeBasisPoints(uint16 _exitFeeInBps) external onlyOwner {
require(_exitFeeInBps <= BASIS_POINT_SCALE, "INVALID");
exitFeeInBps = _exitFeeInBps;
}

function setLowWatermarkInBpsOfTvl(uint16 _lowWatermarkInBpsOfTvl) external onlyOwner {
require(_lowWatermarkInBpsOfTvl <= BASIS_POINT_SCALE, "INVALID");
lowWatermarkInBpsOfTvl = _lowWatermarkInBpsOfTvl;
}

function setExitFeeSplitToTreasuryInBps(uint16 _exitFeeSplitToTreasuryInBps) external onlyOwner {
require(_exitFeeSplitToTreasuryInBps <= BASIS_POINT_SCALE, "INVALID");
exitFeeSplitToTreasuryInBps = _exitFeeSplitToTreasuryInBps;
}

function _updateRateLimit(uint256 shares) internal {
uint64 bucketUnit = _convertSharesToBucketUnit(shares, Math.Rounding.Up);
require(BucketLimiter.consume(limit, bucketUnit), "BucketRateLimiter: rate limit exceeded");
}

function _convertSharesToBucketUnit(uint256 shares, Math.Rounding rounding) internal pure returns (uint64) {
return (rounding == Math.Rounding.Up) ? SafeCast.toUint64((shares + BUCKET_UNIT_SCALE - 1) / BUCKET_UNIT_SCALE) : SafeCast.toUint64(shares / BUCKET_UNIT_SCALE);
}

function _convertBucketUnitToAmount(uint64 bucketUnit) internal pure returns (uint256) {
return bucketUnit * BUCKET_UNIT_SCALE;
}

/**
* @dev Preview taking an exit fee on redeem. See {IERC4626-previewRedeem}.
*/
// redeemable amount after exit fee
function previewRedeem(uint256 shares) public view returns (uint256) {
uint256 amountInEth = liquidityPool.amountForShare(shares);
return amountInEth - _fee(amountInEth, exitFeeInBps);
}

function _fee(uint256 assets, uint256 feeBasisPoints) internal pure virtual returns (uint256) {
return assets.mulDiv(feeBasisPoints, BASIS_POINT_SCALE, Math.Rounding.Up);
}

function _authorizeUpgrade(address newImplementation) internal override onlyOwner {}

}
11 changes: 10 additions & 1 deletion src/LiquidityPool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ import "./interfaces/IEtherFiAdmin.sol";
import "./interfaces/IAuctionManager.sol";
import "./interfaces/ILiquifier.sol";

import "./EtherFiWithdrawalBuffer.sol";


contract LiquidityPool is Initializable, OwnableUpgradeable, UUPSUpgradeable, ILiquidityPool {
//--------------------------------------------------------------------------------------
//--------------------------------- STATE-VARIABLES ----------------------------------
Expand Down Expand Up @@ -69,6 +72,8 @@ contract LiquidityPool is Initializable, OwnableUpgradeable, UUPSUpgradeable, IL

bool private isLpBnftHolder;

EtherFiWithdrawalBuffer public etherFiWithdrawalBuffer;

//--------------------------------------------------------------------------------------
//------------------------------------- EVENTS ---------------------------------------
//--------------------------------------------------------------------------------------
Expand Down Expand Up @@ -139,6 +144,10 @@ contract LiquidityPool is Initializable, OwnableUpgradeable, UUPSUpgradeable, IL
liquifier = ILiquifier(_liquifier);
}

function initializeOnUpgradeWithWithdrawalBuffer(address _withdrawalBuffer) external onlyOwner {
etherFiWithdrawalBuffer = EtherFiWithdrawalBuffer(payable(_withdrawalBuffer));
}

// Used by eETH staking flow
function deposit() external payable returns (uint256) {
return deposit(address(0));
Expand Down Expand Up @@ -179,7 +188,7 @@ contract LiquidityPool is Initializable, OwnableUpgradeable, UUPSUpgradeable, IL
/// it returns the amount of shares burned
function withdraw(address _recipient, uint256 _amount) external whenNotPaused returns (uint256) {
uint256 share = sharesForWithdrawalAmount(_amount);
require(msg.sender == address(withdrawRequestNFT) || msg.sender == address(membershipManager), "Incorrect Caller");
require(msg.sender == address(withdrawRequestNFT) || msg.sender == address(membershipManager) || msg.sender == address(etherFiWithdrawalBuffer), "Incorrect Caller");
if (totalValueInLp < _amount || (msg.sender == address(withdrawRequestNFT) && ethAmountLockedForWithdrawal < _amount) || eETH.balanceOf(msg.sender) < _amount) revert InsufficientLiquidity();
if (_amount > type(uint128).max || _amount == 0 || share == 0) revert InvalidAmount();

Expand Down
Loading
Loading