Aave-v3 to Notional refinance

This commit is contained in:
Richa-iitr 2022-06-11 19:57:38 +05:30
parent fbca8bdfe3
commit 7b002f9704
7 changed files with 330 additions and 55 deletions

View File

@ -5,6 +5,8 @@ import { TokenInterface } from "./interface.sol";
contract Events {
event LogRefinance(
uint256 indexed source,
uint256 indexed target,
uint256 collateralFee,
uint256 debtFee,
address[] tokens,

View File

@ -4,7 +4,7 @@ pragma experimental ABIEncoderV2;
// import { Helpers } from "./helpers.sol";
import { Basic } from "../../common/basic.sol";
import { Token, NotionalInterface, BalanceAction, BalanceActionWithTrades, DepositActionType, AaveV2LendingPoolProviderInterface, AaveV2DataProviderInterface, AaveV2Interface } from "./interface.sol";
import { Token, NotionalInterface, BalanceAction, BalanceActionWithTrades, DepositActionType, AaveV2LendingPoolProviderInterface, AaveV2DataProviderInterface, AaveV2Interface, AaveV3PoolProviderInterface, AaveV3Interface, AaveV3DataProviderInterface } from "./interface.sol";
import { TokenInterface } from "../../common/interfaces.sol";
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
@ -12,6 +12,13 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
contract Helpers is Basic {
using SafeERC20 for IERC20;
enum Protocol {
AaveV2,
AaveV3,
Compound,
Notional
}
uint256 internal constant LEND_TRADE = 0;
uint256 internal constant BORROW_TRADE = 1;
uint256 internal constant INTERNAL_TOKEN_PRECISION = 1e8;
@ -21,7 +28,7 @@ contract Helpers is Basic {
address payable constant feeCollector =
0xb1DC62EC38E6E3857a887210C38418E4A17Da5B2;
AaveV2DataProviderInterface internal constant aaveData =
AaveV2DataProviderInterface internal constant aaveV2Data =
AaveV2DataProviderInterface(0x057835Ad21a177dbdd3090bB1CAE03EaCF78Fc6d);
NotionalInterface internal constant notional =
@ -34,6 +41,17 @@ contract Helpers is Basic {
AaveV2LendingPoolProviderInterface(
0xB53C1a33016B2DC2fF3653530bfF1848a515c8c5
);
/**
* @dev Aave V3 Pool Provider
*/
AaveV3PoolProviderInterface internal constant getAaveV3Provider =
AaveV3PoolProviderInterface(0xA55125A90d75a95EC00130E8E8C197dB5641Eb19); //rinkeby address
/**
* @dev Aave V3 Pool Data Provider
*/
AaveV3DataProviderInterface internal constant aaveV3Data =
AaveV3DataProviderInterface(0x256bBbeDbA70a1240a1EB64210abB1b063267408); //rinkeby address
/**
* @dev get Referral Code
@ -41,6 +59,9 @@ contract Helpers is Basic {
uint16 internal constant getReferralCode = 3228;
struct NotionalBorrowData {
// refinance to Notional from source
Protocol source;
// length of tokens
uint256 length;
// debt fee
uint256 fee;
@ -73,6 +94,17 @@ contract Helpers is Basic {
);
}
// withdraw balance of Aave v3
function getWithdrawBalanceV3(
AaveV3DataProviderInterface aaveData,
address token
) internal view returns (uint256 bal) {
(bal, , , , , , , , ) = aaveData.getUserReserveData(
token,
address(this)
);
}
function getAssetOrUnderlyingToken(uint16 currencyId, bool underlying)
internal
view
@ -109,12 +141,29 @@ contract Helpers is Basic {
returns (uint256 bal)
{
if (rateMode == 1) {
(, bal, , , , , , , ) = aaveData.getUserReserveData(
(, bal, , , , , , , ) = aaveV2Data.getUserReserveData(
token,
address(this)
);
} else {
(, , bal, , , , , , ) = aaveData.getUserReserveData(
(, , bal, , , , , , ) = aaveV2Data.getUserReserveData(
token,
address(this)
);
}
}
function getAaveV3PaybackAmt(uint256 rateMode, address token)
internal
returns (uint256 bal)
{
if (rateMode == 1) {
(, bal, , , , , , , ) = aaveV3Data.getUserReserveData(
token,
address(this)
);
} else {
(, , bal, , , , , , ) = aaveV3Data.getUserReserveData(
token,
address(this)
);

View File

@ -7,7 +7,7 @@ import { Helpers } from "../helpers.sol";
import { AaveV2DataProviderInterface, AaveV2LendingPoolProviderInterface, AaveV2Interface } from "../interface.sol";
import { TokenInterface } from "../../../common/interfaces.sol";
contract AaveHelpers is Helpers {
contract AaveV2Helpers is Helpers {
// payback token to Aave V2, amts sent already checked for MAX
function _aaveV2PaybackOne(
AaveV2Interface aave,

View File

@ -0,0 +1,72 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.6;
pragma experimental ABIEncoderV2;
import { Helpers } from "../helpers.sol";
import { AaveV3DataProviderInterface, AaveV3PoolProviderInterface, AaveV3Interface } from "../interface.sol";
import { TokenInterface } from "../../../common/interfaces.sol";
contract AaveV3Helpers is Helpers {
// payback token to Aave V2, amts sent already checked for MAX
function _aaveV3PaybackOne(
AaveV3Interface aave,
TokenInterface token,
uint256 amt,
uint256 rateMode
) internal {
if (amt > 0) {
bool isEth = address(token) == wethAddr;
if (isEth) convertEthToWeth(isEth, token, amt);
approve(token, address(aave), amt);
aave.repay(address(token), amt, rateMode, address(this));
}
}
function _aaveV3Payback(
uint256 length,
AaveV3Interface aave,
TokenInterface[] memory tokens,
uint256[] memory amts,
uint256[] memory rateModes
) internal {
for (uint256 i = 0; i < length; i++) {
_aaveV3PaybackOne(aave, tokens[i], amts[i], rateModes[i]);
}
}
// withdraw aToken from aaveV2
function _aaveV3WithdrawOne(
AaveV3Interface aave,
AaveV3DataProviderInterface aaveData,
TokenInterface token,
uint256 amt
) internal returns (uint256 _amt) {
if (amt > 0) {
bool isEth = address(token) == wethAddr;
aave.withdraw(address(token), amt, address(this));
_amt = amt == uint256(-1)
? getWithdrawBalanceV3(aaveData, address(token))
: amt;
convertWethToEth(isEth, token, _amt);
}
}
function _aaveV3Withdraw(
AaveV3Interface aave,
AaveV3DataProviderInterface aaveData,
uint256 length,
TokenInterface[] memory tokens,
uint256[] memory amts
) internal returns (uint256[] memory) {
uint256[] memory finalAmts = new uint256[](length);
for (uint256 i = 0; i < length; i++) {
finalAmts[i] = _aaveV3WithdrawOne(
aave,
aaveData,
tokens[i],
amts[i]
);
}
}
}

View File

@ -52,7 +52,16 @@ contract NotionalHelpers is Helpers {
//calculating payback amounts for Aave v2
if (_amt == uint256(-1)) {
_amt = getAaveV2PaybackAmt(data.rateModes[i], data.tokens[i]);
if (data.source == Protocol.AaveV2)
_amt = getAaveV2PaybackAmt(
data.rateModes[i],
data.tokens[i]
);
else if(data.source == Protocol.AaveV3)
_amt = getAaveV3PaybackAmt(
data.rateModes[i],
data.tokens[i]
);
}
finalAmts[i] = _amt;

View File

@ -169,4 +169,81 @@ interface AaveV2Interface {
interface AaveV2LendingPoolProviderInterface {
function getLendingPool() external view returns (address);
}
// Aave V3 interfaces
interface AaveV3Interface {
function supply(
address asset,
uint256 amount,
address onBehalfOf,
uint16 referralCode
) external;
function withdraw(
address asset,
uint256 amount,
address to
) external returns (uint256);
function borrow(
address asset,
uint256 amount,
uint256 interestRateMode,
uint16 referralCode,
address onBehalfOf
) external;
function repay(
address asset,
uint256 amount,
uint256 interestRateMode,
address onBehalfOf
) external returns (uint256);
function repayWithATokens(
address asset,
uint256 amount,
uint256 interestRateMode
) external returns (uint256);
function setUserUseReserveAsCollateral(address asset, bool useAsCollateral)
external;
function setUserEMode(uint8 categoryId) external;
}
interface AaveV3PoolProviderInterface {
function getPool() external view returns (address);
}
interface AaveV3DataProviderInterface {
function getReserveTokensAddresses(address _asset)
external
view
returns (
address aTokenAddress,
address stableDebtTokenAddress,
address variableDebtTokenAddress
);
function getUserReserveData(address _asset, address _user)
external
view
returns (
uint256 currentATokenBalance,
uint256 currentStableDebt,
uint256 currentVariableDebt,
uint256 principalStableDebt,
uint256 scaledVariableDebt,
uint256 stableBorrowRate,
uint256 liquidityRate,
uint40 stableRateLastUpdated,
bool usageAsCollateralEnabled
);
function getReserveEModeCategory(address asset)
external
view
returns (uint256);
}

View File

@ -3,16 +3,19 @@ pragma solidity ^0.7.6;
pragma experimental ABIEncoderV2;
/**
* @title Refinance Notional, Aave v2.
* @dev Refinancing.
* @title Refinance.
* @dev Refinancing among Notional, Aave v2, Aave v3.
*/
import { AaveV2Interface, AaveV2DataProviderInterface, AaveV2LendingPoolProviderInterface } from "./interface.sol";
import { AaveV2Interface, AaveV2DataProviderInterface, AaveV2LendingPoolProviderInterface, AaveV3Interface, AaveV3DataProviderInterface, AaveV3PoolProviderInterface } from "./interface.sol";
import { TokenInterface } from "../../common/interfaces.sol";
import { AaveHelpers } from "./helpers/aaveV2.sol";
import { AaveV2Helpers } from "./helpers/aaveV2.sol";
import { AaveV3Helpers } from "./helpers/aaveV3.sol";
import { NotionalHelpers } from "./helpers/notional.sol";
contract RefinanceResolver is AaveHelpers, NotionalHelpers {
contract RefinanceResolver is AaveV2Helpers, AaveV3Helpers, NotionalHelpers {
struct RefinanceData {
Protocol source;
Protocol target;
uint256 collateralFee;
uint256 debtFee;
uint256[] currencyIDs;
@ -27,8 +30,10 @@ contract RefinanceResolver is AaveHelpers, NotionalHelpers {
}
struct RefinanceInternalData {
AaveV2Interface aave;
AaveV2DataProviderInterface aaveData;
AaveV2Interface aaveV2;
AaveV2DataProviderInterface aaveV2Data;
AaveV3Interface aaveV3;
AaveV3DataProviderInterface aaveV3Data;
uint256[] depositAmts;
uint256[] paybackAmts;
address[] tokens;
@ -53,11 +58,15 @@ contract RefinanceResolver is AaveHelpers, NotionalHelpers {
require(data.mintNTokens.length == length, "length-mismatch");
RefinanceInternalData memory refinanceInternalData;
refinanceInternalData.aave = AaveV2Interface(
refinanceInternalData.aaveV2 = AaveV2Interface(
AaveV2LendingPoolProviderInterface(getAaveV2Provider)
.getLendingPool()
);
refinanceInternalData.aaveData = aaveData;
refinanceInternalData.aaveV2Data = aaveV2Data;
refinanceInternalData.aaveV3 = AaveV3Interface(
AaveV3PoolProviderInterface(getAaveV3Provider).getPool()
);
refinanceInternalData.aaveV3Data = aaveV3Data;
refinanceInternalData.depositAmts;
refinanceInternalData.paybackAmts;
@ -69,51 +78,108 @@ contract RefinanceResolver is AaveHelpers, NotionalHelpers {
);
// Aave v2 to Notional
NotionalBorrowData memory _notionalBorrowData;
if (
data.source == Protocol.AaveV2 && data.target == Protocol.Notional
) {
NotionalBorrowData memory _notionalBorrowData;
_notionalBorrowData.length = length;
_notionalBorrowData.fee = data.debtFee;
_notionalBorrowData.tokens = refinanceInternalData.tokens;
_notionalBorrowData.redeemToUnderlying = data.redeemBorrowToUnderlying;
_notionalBorrowData.amts = data.borrowAmts;
_notionalBorrowData.rateModes = data.paybackRateModes;
_notionalBorrowData.fCashAmount = data.borrowfCashAmts;
_notionalBorrowData.maxBorrowRate = data.maxBorrowingRates;
_notionalBorrowData.currencyIDs = data.currencyIDs;
_notionalBorrowData.marketIndex = data.borrowMarketIndices;
_notionalBorrowData.length = length;
_notionalBorrowData.source = data.source;
_notionalBorrowData.fee = data.debtFee;
_notionalBorrowData.tokens = refinanceInternalData.tokens;
_notionalBorrowData.redeemToUnderlying = data
.redeemBorrowToUnderlying;
_notionalBorrowData.amts = data.borrowAmts;
_notionalBorrowData.rateModes = data.paybackRateModes;
_notionalBorrowData.fCashAmount = data.borrowfCashAmts;
_notionalBorrowData.maxBorrowRate = data.maxBorrowingRates;
_notionalBorrowData.currencyIDs = data.currencyIDs;
_notionalBorrowData.marketIndex = data.borrowMarketIndices;
//borrow on Notional
refinanceInternalData.paybackAmts = _notionalBorrow(
_notionalBorrowData
);
//payback debt on Aave-v2
_aaveV2Payback(
length,
refinanceInternalData.aave,
refinanceInternalData.tokenInterfaces,
refinanceInternalData.paybackAmts,
data.paybackRateModes
);
//withdraw aTokens from Aave-v2
refinanceInternalData.depositAmts = _aaveV2Withdraw(
refinanceInternalData.aave,
refinanceInternalData.aaveData,
length,
refinanceInternalData.tokenInterfaces,
data.withdrawAmts
);
//deposit on Notional
_notionalDeposit(
length,
data.collateralFee,
data.currencyIDs,
refinanceInternalData.depositAmts,
refinanceInternalData.tokens,
data.mintNTokens
);
//borrow on Notional
refinanceInternalData.paybackAmts = _notionalBorrow(
_notionalBorrowData
);
//payback debt on Aave-v2
_aaveV2Payback(
length,
refinanceInternalData.aaveV2,
refinanceInternalData.tokenInterfaces,
refinanceInternalData.paybackAmts,
data.paybackRateModes
);
//withdraw aTokens from Aave-v2
refinanceInternalData.depositAmts = _aaveV2Withdraw(
refinanceInternalData.aaveV2,
refinanceInternalData.aaveV2Data,
length,
refinanceInternalData.tokenInterfaces,
data.withdrawAmts
);
//deposit on Notional
_notionalDeposit(
length,
data.collateralFee,
data.currencyIDs,
refinanceInternalData.depositAmts,
refinanceInternalData.tokens,
data.mintNTokens
);
}
// Aave v3 to Notional
else if (
data.source == Protocol.AaveV3 && data.target == Protocol.Notional
) {
NotionalBorrowData memory _notionalBorrowData;
_notionalBorrowData.length = length;
_notionalBorrowData.source = data.source;
_notionalBorrowData.fee = data.debtFee;
_notionalBorrowData.tokens = refinanceInternalData.tokens;
_notionalBorrowData.redeemToUnderlying = data
.redeemBorrowToUnderlying;
_notionalBorrowData.amts = data.borrowAmts;
_notionalBorrowData.rateModes = data.paybackRateModes;
_notionalBorrowData.fCashAmount = data.borrowfCashAmts;
_notionalBorrowData.maxBorrowRate = data.maxBorrowingRates;
_notionalBorrowData.currencyIDs = data.currencyIDs;
_notionalBorrowData.marketIndex = data.borrowMarketIndices;
//borrow on Notional
refinanceInternalData.paybackAmts = _notionalBorrow(
_notionalBorrowData
);
//payback debt on Aave-v3
_aaveV3Payback(
length,
refinanceInternalData.aaveV3,
refinanceInternalData.tokenInterfaces,
refinanceInternalData.paybackAmts,
data.paybackRateModes
);
//withdraw aTokens from Aave-v3
refinanceInternalData.depositAmts = _aaveV3Withdraw(
refinanceInternalData.aaveV3,
refinanceInternalData.aaveV3Data,
length,
refinanceInternalData.tokenInterfaces,
data.withdrawAmts
);
//deposit on Notional
_notionalDeposit(
length,
data.collateralFee,
data.currencyIDs,
refinanceInternalData.depositAmts,
refinanceInternalData.tokens,
data.mintNTokens
);
}
_eventName = "LogRefinance(uint,uint,address[],uint[],uint[],uint[],uint[])";
_eventParam = abi.encode(
uint256(data.source),
uint256(data.target),
data.collateralFee,
data.debtFee,
refinanceInternalData.tokens,