feat: Implemented internal swap functions and getAmountIn

This commit is contained in:
domenicodev
2024-02-28 12:07:57 +01:00
parent 61d4c4eb9f
commit 0f3fe80b00

View File

@@ -3,24 +3,21 @@ pragma experimental ABIEncoderV2;
pragma solidity ^0.8.13; pragma solidity ^0.8.13;
import {IERC20, ISwapAdapter} from "src/interfaces/ISwapAdapter.sol"; import {IERC20, ISwapAdapter} from "src/interfaces/ISwapAdapter.sol";
import {SafeERC20} from "openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol";
/// @title Etherfi Adapter /// @title Etherfi Adapter
/// @dev This contract supports the following swaps: eETH<->ETH, wETH<->eETH, wETH<->ETH /// @dev This contract supports the following swaps: ETH->eETH, wETH<->eETH, ETH->weETH
contract EtherfiAdapter is ISwapAdapter { contract EtherfiAdapter is ISwapAdapter {
using SafeERC20 for IERC20;
uint16 mintFee; // fee = 0.001 ETH * 'mintFee' IWeEth weEth;
uint16 burnFee; // fee = 0.001 ETH * 'burnFee'
IWeEth wEeth;
IeEth eEth; IeEth eEth;
ILiquidityPool liquidityPool; ILiquidityPool public liquidityPool;
IMembershipManager membershipManager;
constructor(address _wEeth) { constructor(address _weEth) {
wEeth = IWeEth(_wEeth); weEth = IWeEth(_weEth);
eEth = wEeth.eETH(); eEth = weEth.eETH();
liquidityPool = eEth.liquidityPool(); liquidityPool = eEth.liquidityPool();
membershipManager = liquidityPool.membershipManager();
} }
/// @dev Check if tokens in input are supported by this adapter /// @dev Check if tokens in input are supported by this adapter
@@ -28,10 +25,10 @@ contract EtherfiAdapter is ISwapAdapter {
if(sellToken == buyToken) { if(sellToken == buyToken) {
revert Unavailable("This pool only supports eETH, weEth and ETH"); revert Unavailable("This pool only supports eETH, weEth and ETH");
} }
if(sellToken != address(wEeth) && sellToken != address(eEth) && sellToken && sellToken != address(0)) { if(sellToken != address(weEth) && sellToken != address(eEth) && sellToken != address(0)) {
revert Unavailable("This pool only supports eETH, weEth and ETH"); revert Unavailable("This pool only supports eETH, weEth and ETH");
} }
if(buyToken != address(wEeth) && buyToken != address(eEth) && buyToken != address(0)) { if(buyToken != address(weEth) && buyToken != address(eEth)) {
revert Unavailable("This pool only supports eETH, weEth and ETH"); revert Unavailable("This pool only supports eETH, weEth and ETH");
} }
_; _;
@@ -74,15 +71,15 @@ contract EtherfiAdapter is ISwapAdapter {
if(buyTokenAddress == address(eEth)) { if(buyTokenAddress == address(eEth)) {
} }
else { // ETH-weETH else { // ETH-weEth
} }
} }
else if(sellTokenAddress == address(wEeth)) { else if(sellTokenAddress == address(weEth)) {
if(buyTokenAddress == address(0)) { if(buyTokenAddress == address(0)) {
} }
else { // wEeth-ETH else { // weEth-ETH
} }
} }
@@ -90,7 +87,7 @@ contract EtherfiAdapter is ISwapAdapter {
if(buyTokenAddress == address(0)) { if(buyTokenAddress == address(0)) {
} }
else { // eEth-wEeth else { // eEth-weEth
} }
} }
@@ -114,7 +111,7 @@ contract EtherfiAdapter is ISwapAdapter {
tokens = new IERC20[](3); tokens = new IERC20[](3);
tokens[0] = IERC20(address(0)); tokens[0] = IERC20(address(0));
tokens[1] = IERC20(address(eEth)); tokens[1] = IERC20(address(eEth));
tokens[2] = IERC20(address(wEeth)); tokens[2] = IERC20(address(weEth));
} }
/// @inheritdoc ISwapAdapter /// @inheritdoc ISwapAdapter
@@ -122,27 +119,75 @@ contract EtherfiAdapter is ISwapAdapter {
external external
returns (bytes32[] memory ids) returns (bytes32[] memory ids)
{ {
ids[] = new bytes32[](1); ids = new bytes32[](1);
ids[0] = bytes20(address(liquidityPool)); ids[0] = bytes20(address(liquidityPool));
} }
/// @notice Swap ETH for eETH using MembershipManager /// @notice Swap ETH for eETH
/// @param payedAmount result of getETHRequiredToMintEeth(), the amount of ETH to pay(incl. fee) /// @param amount amountIn or amountOut depending on side
/// @param receivedAmount eETH received function swapEthForEeth(uint256 amount, OrderSide side) internal returns (uint256) {
function swapEthForEeth(uint256 payedAmount, uint256 receivedAmount) internal { if(side == OrderSide.Buy) {
return membershipManager.wrapEth(_amount, 0); uint256 amountIn = getAmountIn(address(0), address(eEth), amount);
uint256 receivedAmount = liquidityPool.deposit{value: amountIn}();
IERC20(address(eEth)).safeTransfer(address(msg.sender), receivedAmount);
return amountIn;
}
else {
uint256 receivedAmount = liquidityPool.deposit{value: amount}();
IERC20(address(eEth)).safeTransfer(address(msg.sender), receivedAmount);
return receivedAmount;
}
} }
/// @notice Get ETH required to mint `_amount` eETH /// @notice Swap ETH for weEth
function getETHRequiredToMintEeth(uint256 _amount) internal returns (uint256) { /// @param amount amountIn or amountOut depending on side
uint256 feeAmount = uint256(mintFee) * 0.001 ether; function swapEthForWeEth(uint256 amount, OrderSide side) internal returns (uint256) {
return _amount + feeAmount; if(side == OrderSide.Buy) {
uint256 amountIn = getAmountIn(address(0), address(weEth), amount);
IERC20(address(eEth)).approve(address(weEth), amountIn);
uint256 receivedAmountEeth = liquidityPool.deposit{value: amountIn}();
uint256 receivedAmount = weEth.wrap(receivedAmountEeth);
IERC20(address(weEth)).safeTransfer(address(msg.sender), receivedAmount);
return amountIn;
}
else {
IERC20(address(eEth)).approve(address(weEth), amount);
uint256 receivedAmountEeth = liquidityPool.deposit{value: amount}();
uint256 receivedAmount = weEth.wrap(receivedAmountEeth);
IERC20(address(weEth)).safeTransfer(address(msg.sender), receivedAmount);
return receivedAmount;
}
} }
/// @notice Get amountIn for swap functions with OrderSide buy
function getAmountIn(address sellToken, address buyToken, uint256 amountOut) internal view returns (uint256) {
if(sellToken == address(0)) {
if(buyToken == address(eEth)) {
return liquidityPool.amountForShare(amountOut);
}
else {
uint256 ethRequiredForEeth = liquidityPool.amountForShare(amountOut);
return liquidityPool.amountForShare(ethRequiredForEeth);
}
}
else if(sellToken == address(eEth)) { // eEth-weEth
return weEth.getEETHByWeETH(amountOut);
}
else { // weEth-eEth
return weEth.getWeETHByeETH(amountOut);
}
}
} }
interface IMembershipManager { interface IWithdrawRequestNFT {
function wrapEth(uint256 _amount, uint256 _amountForPoints) external payable returns (uint256); function requestWithdraw(uint96 amountOfEEth, uint96 shareOfEEth, address recipient, uint256 fee)
external payable returns (uint256);
function getClaimableAmount(uint256 tokenId) external view returns (uint256);
function claimWithdraw(uint256 tokenId) external;
} }
@@ -161,7 +206,8 @@ interface ILiquidityPool {
function deposit(address _referral) external payable returns (uint256); function deposit(address _referral) external payable returns (uint256);
function deposit(address _user, address _referral) external payable returns (uint256); function deposit(address _user, address _referral) external payable returns (uint256);
function membershipManager() external view returns (IMembershipManager); function requestWithdraw(address recipient, uint256 amount) external returns (uint256);
function withdrawRequestNFT() external view returns (IWithdrawRequestNFT);
} }