From 6cd57ebaf4c5cc4f49619b549c3655cf19ad52c2 Mon Sep 17 00:00:00 2001 From: domenicodev Date: Wed, 28 Feb 2024 12:38:59 +0100 Subject: [PATCH] feat: Implemented price --- evm/src/etherfi/EtherfiAdapter.sol | 261 ++++++++++++++++++++--------- 1 file changed, 183 insertions(+), 78 deletions(-) diff --git a/evm/src/etherfi/EtherfiAdapter.sol b/evm/src/etherfi/EtherfiAdapter.sol index d2ac197..4a15437 100644 --- a/evm/src/etherfi/EtherfiAdapter.sol +++ b/evm/src/etherfi/EtherfiAdapter.sol @@ -3,10 +3,12 @@ pragma experimental ABIEncoderV2; pragma solidity ^0.8.13; import {IERC20, ISwapAdapter} from "src/interfaces/ISwapAdapter.sol"; -import {SafeERC20} from "openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol"; +import {SafeERC20} from + "openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol"; /// @title Etherfi Adapter -/// @dev This contract supports the following swaps: ETH->eETH, wETH<->eETH, ETH->weETH +/// @dev This contract supports the following swaps: ETH->eETH, wETH<->eETH, +/// ETH->weETH contract EtherfiAdapter is ISwapAdapter { using SafeERC20 for IERC20; @@ -22,13 +24,16 @@ contract EtherfiAdapter is ISwapAdapter { /// @dev Check if tokens in input are supported by this adapter modifier checkInputTokens(address sellToken, address buyToken) { - if(sellToken == buyToken) { + if (sellToken == buyToken) { revert Unavailable("This pool only supports eETH, weEth and ETH"); } - if(sellToken != address(weEth) && sellToken != address(eEth) && sellToken != address(0)) { + if ( + sellToken != address(weEth) && sellToken != address(eEth) + && sellToken != address(0) + ) { revert Unavailable("This pool only supports eETH, weEth and ETH"); } - if(buyToken != address(weEth) && buyToken != address(eEth)) { + if (buyToken != address(weEth) && buyToken != address(eEth)) { revert Unavailable("This pool only supports eETH, weEth and ETH"); } _; @@ -37,23 +42,66 @@ contract EtherfiAdapter is ISwapAdapter { /// @dev enable receive as this contract supports ETH receive() external payable {} + /// @inheritdoc ISwapAdapter function price( - bytes32 _poolId, + bytes32, IERC20 _sellToken, IERC20 _buyToken, uint256[] memory _specifiedAmounts - ) external view override returns (Fraction[] memory _prices) { - revert NotImplemented("TemplateSwapAdapter.price"); + ) + external + view + override + checkInputTokens(address(_sellToken), address(_buyToken)) + returns (Fraction[] memory _prices) + { + _prices = new Fraction[](_specifiedAmounts.length); + address sellTokenAddress = address(_sellToken); + address buyTokenAddress = address(_buyToken); + + for (uint256 i = 0; i < _specifiedAmounts.length; i++) { + _prices[i] = getPriceAt(sellTokenAddress, buyTokenAddress, _specifiedAmounts[i]); + } } function swap( - bytes32 poolId, + bytes32, IERC20 sellToken, IERC20 buyToken, OrderSide side, uint256 specifiedAmount - ) external returns (Trade memory trade) { - revert NotImplemented("TemplateSwapAdapter.swap"); + ) + external + override + checkInputTokens(address(sellToken), address(buyToken)) + returns (Trade memory trade) + { + // if (specifiedAmount == 0) { + // return trade; + // } + + // address sellTokenAddress = address(sellToken); + // address buyTokenAddress = address(buyToken); + // uint256 gasBefore = gasleft(); + // if (sellTokenAddress == address(0)) { + // if (buyTokenAddress == address(eEth)) { + // trade.calculatedAmount = swapEthForEeth(specifiedAmount, + // side); + // } else { + // trade.calculatedAmount = swapEthForWeEth(specifiedAmount, + // side); + // } + // } else { + // if (sellTokenAddress == address(eEth)) { + // trade.calculatedAmount = swapEthForWeEth(specifiedAmount, + // side); + // } else { + // trade.calculatedAmount = swapWeEthForEeth(specifiedAmount, + // side); + // } + // } + // trade.gasUsed = gasBefore - gasleft(); + // // trade.price = getPriceAt(); } function getLimits(bytes32, IERC20 sellToken, IERC20 buyToken) @@ -66,32 +114,17 @@ contract EtherfiAdapter is ISwapAdapter { address sellTokenAddress = address(sellToken); address buyTokenAddress = address(buyToken); limits = new uint256[](2); - - if(sellTokenAddress == address(0)) { - if(buyTokenAddress == address(eEth)) { + if (sellTokenAddress == address(0)) { + if (buyTokenAddress == address(eEth)) {} else { // ETH-weEth } - else { // ETH-weEth - + } else if (sellTokenAddress == address(weEth)) { + if (buyTokenAddress == address(0)) {} else { // weEth-ETH + } + } else if (sellTokenAddress == address(eEth)) { + if (buyTokenAddress == address(0)) {} else { // eEth-weEth } } - else if(sellTokenAddress == address(weEth)) { - if(buyTokenAddress == address(0)) { - - } - else { // weEth-ETH - - } - } - else if(sellTokenAddress == address(eEth)) { - if(buyTokenAddress == address(0)) { - - } - else { // eEth-weEth - - } - } - } function getCapabilities(bytes32 poolId, IERC20 sellToken, IERC20 buyToken) @@ -125,112 +158,184 @@ contract EtherfiAdapter is ISwapAdapter { /// @notice Swap ETH for eETH /// @param amount amountIn or amountOut depending on side - function swapEthForEeth(uint256 amount, OrderSide side) internal returns (uint256) { - if(side == OrderSide.Buy) { + function swapEthForEeth(uint256 amount, OrderSide side) + internal + returns (uint256) + { + if (side == OrderSide.Buy) { uint256 amountIn = getAmountIn(address(0), address(eEth), amount); uint256 receivedAmount = liquidityPool.deposit{value: amountIn}(); - IERC20(address(eEth)).safeTransfer(address(msg.sender), receivedAmount); + IERC20(address(eEth)).safeTransfer( + address(msg.sender), receivedAmount + ); return amountIn; - } - else { + } else { uint256 receivedAmount = liquidityPool.deposit{value: amount}(); - IERC20(address(eEth)).safeTransfer(address(msg.sender), receivedAmount); + IERC20(address(eEth)).safeTransfer( + address(msg.sender), receivedAmount + ); return receivedAmount; } } /// @notice Swap ETH for weEth /// @param amount amountIn or amountOut depending on side - function swapEthForWeEth(uint256 amount, OrderSide side) internal returns (uint256) { - if(side == OrderSide.Buy) { + function swapEthForWeEth(uint256 amount, OrderSide side) + internal + returns (uint256) + { + 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 receivedAmountEeth = + liquidityPool.deposit{value: amountIn}(); uint256 receivedAmount = weEth.wrap(receivedAmountEeth); - IERC20(address(weEth)).safeTransfer(address(msg.sender), receivedAmount); + IERC20(address(weEth)).safeTransfer( + address(msg.sender), receivedAmount + ); return amountIn; - } - else { + } 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); + 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); + /// @notice Swap eETH for weETH + /// @param amount amountIn or amountOut depending on side + function swapEethForWeEth(uint256 amount, OrderSide side) + internal + returns (uint256) + { + if (side == OrderSide.Buy) {} else {} + } + + /// @notice Swap weETH for eEth + /// @param amount amountIn or amountOut depending on side + function swapWeEthForEeth(uint256 amount, OrderSide side) + internal + returns (uint256) + { + if (side == OrderSide.Buy) {} else {} + } + + /// @notice Get swap price + /// @param sellToken token to sell + /// @param buyToken token to buy + function getPriceAt(address sellToken, address buyToken, uint256 amount) + internal + view + returns (Fraction memory) + { + if (sellToken == address(0)) { + if (buyToken == address(eEth)) { + return Fraction(liquidityPool.sharesForAmount(amount), amount); + } else { + uint256 eEthOut = liquidityPool.sharesForAmount(amount); + return Fraction(liquidityPool.sharesForAmount(eEthOut), amount); } - 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); + } else if (sellToken == address(eEth)) { + return Fraction(liquidityPool.sharesForAmount(amount), amount); + } else { + return Fraction(liquidityPool.amountForShare(amount), amount); } } + /// @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 IWithdrawRequestNFT { + function requestWithdraw( + uint96 amountOfEEth, + uint96 shareOfEEth, + address recipient, + uint256 fee + ) 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 getClaimableAmount(uint256 tokenId) + external + view + returns (uint256); function claimWithdraw(uint256 tokenId) external; - } interface ILiquidityPool { - function numPendingDeposits() external view returns (uint32); function totalValueOutOfLp() external view returns (uint128); function totalValueInLp() external view returns (uint128); - function getTotalEtherClaimOf(address _user) external view returns (uint256); + function getTotalEtherClaimOf(address _user) + external + view + returns (uint256); function getTotalPooledEther() external view returns (uint256); function sharesForAmount(uint256 _amount) external view returns (uint256); - function sharesForWithdrawalAmount(uint256 _amount) external view returns (uint256); + function sharesForWithdrawalAmount(uint256 _amount) + external + view + returns (uint256); function amountForShare(uint256 _share) external view returns (uint256); function deposit() 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 requestWithdraw(address recipient, uint256 amount) external returns (uint256); + function requestWithdraw(address recipient, uint256 amount) + external + returns (uint256); function withdrawRequestNFT() external view returns (IWithdrawRequestNFT); - } interface IeEth { - function liquidityPool() external view returns (ILiquidityPool); function totalShares() external view returns (uint256); function shares(address _user) external view returns (uint256); - } interface IWeEth { - function eETH() external view returns (IeEth); - function getWeETHByeETH(uint256 _eETHAmount) external view returns (uint256); + function getWeETHByeETH(uint256 _eETHAmount) + external + view + returns (uint256); - function getEETHByWeETH(uint256 _weETHAmount) external view returns (uint256); + function getEETHByWeETH(uint256 _weETHAmount) + external + view + returns (uint256); function wrap(uint256 _eETHAmount) external returns (uint256); function unwrap(uint256 _weETHAmount) external returns (uint256); - }