From fbca8bdfe30e885b7b1a598d0c51588fe430ceab Mon Sep 17 00:00:00 2001 From: Richa-iitr Date: Fri, 10 Jun 2022 21:45:47 +0530 Subject: [PATCH] notional-aaveV2 refinance --- .../connectors/refinance-notional/events.sol | 16 ++ .../connectors/refinance-notional/helpers.sol | 194 ++++++++++++++++++ .../refinance-notional/helpers/aaveV2.sol | 73 +++++++ .../refinance-notional/helpers/notional.sol | 136 ++++++++++++ .../refinance-notional/interface.sol | 172 ++++++++++++++++ .../connectors/refinance-notional/main.sol | 143 +++++++++++++ 6 files changed, 734 insertions(+) create mode 100644 contracts/mainnet/connectors/refinance-notional/events.sol create mode 100644 contracts/mainnet/connectors/refinance-notional/helpers.sol create mode 100644 contracts/mainnet/connectors/refinance-notional/helpers/aaveV2.sol create mode 100644 contracts/mainnet/connectors/refinance-notional/helpers/notional.sol create mode 100644 contracts/mainnet/connectors/refinance-notional/interface.sol create mode 100644 contracts/mainnet/connectors/refinance-notional/main.sol diff --git a/contracts/mainnet/connectors/refinance-notional/events.sol b/contracts/mainnet/connectors/refinance-notional/events.sol new file mode 100644 index 00000000..0c6a1aab --- /dev/null +++ b/contracts/mainnet/connectors/refinance-notional/events.sol @@ -0,0 +1,16 @@ +//SPDX-License-Identifier: MIT +pragma solidity ^0.7.6; + +import { TokenInterface } from "./interface.sol"; + +contract Events { + event LogRefinance( + uint256 collateralFee, + uint256 debtFee, + address[] tokens, + uint256[] borrowAmts, + uint256[] depositAmts, + uint256[] borrowMarketIndices, + uint256[] maxBorrowingRates + ); +} diff --git a/contracts/mainnet/connectors/refinance-notional/helpers.sol b/contracts/mainnet/connectors/refinance-notional/helpers.sol new file mode 100644 index 00000000..eb86e238 --- /dev/null +++ b/contracts/mainnet/connectors/refinance-notional/helpers.sol @@ -0,0 +1,194 @@ +//SPDX-License-Identifier: MIT +pragma solidity ^0.7.6; +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 { TokenInterface } from "../../common/interfaces.sol"; +import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +contract Helpers is Basic { + using SafeERC20 for IERC20; + + uint256 internal constant LEND_TRADE = 0; + uint256 internal constant BORROW_TRADE = 1; + uint256 internal constant INTERNAL_TOKEN_PRECISION = 1e8; + uint256 internal constant ETH_CURRENCY_ID = 1; + uint256 internal constant MAX_DEPOSIT = type(uint256).max; + + address payable constant feeCollector = + 0xb1DC62EC38E6E3857a887210C38418E4A17Da5B2; + + AaveV2DataProviderInterface internal constant aaveData = + AaveV2DataProviderInterface(0x057835Ad21a177dbdd3090bB1CAE03EaCF78Fc6d); + + NotionalInterface internal constant notional = + NotionalInterface(0x1344A36A1B56144C3Bc62E7757377D288fDE0369); + + /** + * @dev get Aave Lending Pool Provider + */ + AaveV2LendingPoolProviderInterface internal constant getAaveV2Provider = + AaveV2LendingPoolProviderInterface( + 0xB53C1a33016B2DC2fF3653530bfF1848a515c8c5 + ); + + /** + * @dev get Referral Code + */ + uint16 internal constant getReferralCode = 3228; + + struct NotionalBorrowData { + uint256 length; + // debt fee + uint256 fee; + // borrow tokens + address[] tokens; + // true, then redeems the borrowed balance from cTokens to underlying token before transferring to account + bool[] redeemToUnderlying; + // borrow amts im underlying token denomination + uint256[] amts; + // aave V2 borrow rate modes + uint256[] rateModes; + // fCashAmount accounting for the borrowAmt with debtfee, calculated through SDK + uint256[] fCashAmount; + // borrow rate max, 0 means any is acceptable + uint256[] maxBorrowRate; + // notion defined currency IDs of borrowTokens + uint256[] currencyIDs; + // borrow markets based on the maturity where user wants to borrow + uint256[] marketIndex; + } + + // withdraw balance of Aave v2 + function getWithdrawBalanceV2( + AaveV2DataProviderInterface aaveData, + address token + ) internal view returns (uint256 bal) { + (bal, , , , , , , , ) = aaveData.getUserReserveData( + token, + address(this) + ); + } + + function getAssetOrUnderlyingToken(uint16 currencyId, bool underlying) + internal + view + returns (address) + { + // prettier-ignore + (Token memory assetToken, Token memory underlyingToken) = notional.getCurrency(currencyId); + return + underlying ? underlyingToken.tokenAddress : assetToken.tokenAddress; + } + + function toUint88(uint256 value) internal pure returns (uint88) { + require(value <= type(uint88).max, "uint88 value overflow"); + return uint88(value); + } + + function toUint32(uint256 value) internal pure returns (uint32) { + require(value <= type(uint32).max, "uint32 value overflow"); + return uint32(value); + } + + function toUint16(uint256 value) internal pure returns (uint16) { + require(value <= type(uint16).max, "uint16 value overflow"); + return uint16(value); + } + + function toUint8(uint256 value) internal pure returns (uint8) { + require(value <= type(uint8).max, "uint8 value overflow"); + return uint8(value); + } + + function getAaveV2PaybackAmt(uint256 rateMode, address token) + internal + returns (uint256 bal) + { + if (rateMode == 1) { + (, bal, , , , , , , ) = aaveData.getUserReserveData( + token, + address(this) + ); + } else { + (, , bal, , , , , , ) = aaveData.getUserReserveData( + token, + address(this) + ); + } + } + + function calculateFee( + uint256 amount, + uint256 fee, + bool toAdd + ) internal pure returns (uint256 feeAmount, uint256 _amount) { + feeAmount = wmul(amount, fee); + _amount = toAdd ? add(amount, feeAmount) : sub(amount, feeAmount); + } + + function transferFees(address token, uint256 feeAmt) internal { + if (feeAmt > 0) { + if (token == ethAddr) { + feeCollector.transfer(feeAmt); + } else { + IERC20(token).safeTransfer(feeCollector, feeAmt); + } + } + } + + function calculateAndTransferFees( + address token, + uint256 amt, + uint256 fee, + bool toAdd + ) internal { + token = (token == wethAddr) ? ethAddr : token; + (uint256 feeAmt, uint256 _amt) = calculateFee(amt, fee, toAdd); + transferFees(token, feeAmt); + } + + function encodeBorrowTrade( + uint256 marketIndex, + uint256 fCashAmount, + uint256 maxBorrowRate + ) internal pure returns (bytes32) { + return + (bytes32(BORROW_TRADE) << 248) | + (bytes32(marketIndex) << 240) | + (bytes32(fCashAmount) << 152) | + (bytes32(maxBorrowRate) << 120); + } + + function getTokens(uint256 length, uint256[] memory currencyIDs) + internal + view + returns (address[] memory) + { + address[] memory tokens = new address[](length); + for (uint256 i = 0; i < length; i++) { + uint16 _currencyId = toUint16(currencyIDs[i]); + if (_currencyId == ETH_CURRENCY_ID) { + tokens[i] = wethAddr; + } else { + tokens[i] = getAssetOrUnderlyingToken(_currencyId, true); + } + } + return tokens; + } + + function getTokenInterfaces(uint256 length, address[] memory _tokens) + internal + pure + returns (TokenInterface[] memory) + { + TokenInterface[] memory tokens = new TokenInterface[](length); + for (uint256 i = 0; i < length; i++) { + tokens[i] = TokenInterface(_tokens[i]); + } + return tokens; + } +} diff --git a/contracts/mainnet/connectors/refinance-notional/helpers/aaveV2.sol b/contracts/mainnet/connectors/refinance-notional/helpers/aaveV2.sol new file mode 100644 index 00000000..7e74d5f0 --- /dev/null +++ b/contracts/mainnet/connectors/refinance-notional/helpers/aaveV2.sol @@ -0,0 +1,73 @@ +//SPDX-License-Identifier: MIT +pragma solidity ^0.7.6; +pragma experimental ABIEncoderV2; + +import { Helpers } from "../helpers.sol"; + +import { AaveV2DataProviderInterface, AaveV2LendingPoolProviderInterface, AaveV2Interface } from "../interface.sol"; +import { TokenInterface } from "../../../common/interfaces.sol"; + +contract AaveHelpers is Helpers { + // payback token to Aave V2, amts sent already checked for MAX + function _aaveV2PaybackOne( + AaveV2Interface aave, + TokenInterface token, + uint256 amt, + uint256 rateMode + ) internal { + if (amt > 0) { + bool isEth = address(token) == wethAddr; + convertEthToWeth(isEth, token, amt); + approve(token, address(aave), amt); + aave.repay(address(token), amt, rateMode, address(this)); + } + } + + function _aaveV2Payback( + uint256 length, + AaveV2Interface aave, + TokenInterface[] memory tokens, + uint256[] memory amts, + uint256[] memory rateModes + ) internal { + for (uint256 i = 0; i < length; i++) { + _aaveV2PaybackOne(aave, tokens[i], amts[i], rateModes[i]); + } + } + + // withdraw aToken from aaveV2 + function _aaveV2WithdrawOne( + AaveV2Interface aave, + AaveV2DataProviderInterface 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) + ? getWithdrawBalanceV2(aaveData, address(token)) + : amt; + convertWethToEth(isEth, token, _amt); + } + } + + function _aaveV2Withdraw( + AaveV2Interface aave, + AaveV2DataProviderInterface 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] = _aaveV2WithdrawOne( + aave, + aaveData, + tokens[i], + amts[i] + ); + } + return finalAmts; + } +} diff --git a/contracts/mainnet/connectors/refinance-notional/helpers/notional.sol b/contracts/mainnet/connectors/refinance-notional/helpers/notional.sol new file mode 100644 index 00000000..d4ac0233 --- /dev/null +++ b/contracts/mainnet/connectors/refinance-notional/helpers/notional.sol @@ -0,0 +1,136 @@ +//SPDX-License-Identifier: MIT +pragma solidity ^0.7.6; +pragma experimental ABIEncoderV2; + +import { Helpers } from "../helpers.sol"; +import { Token, NotionalInterface, BalanceAction, BalanceActionWithTrades, DepositActionType, AaveV2DataProviderInterface } from "../interface.sol"; + +contract NotionalHelpers is Helpers { + function _notionalBorrowOne( + uint256 fee, + bool redeemToUnderlying, + uint256 fCashAmount, + uint256 maxBorrowRate, + uint16 currencyID, + uint256 marketIndex + ) internal { + //collateral should be depositied beforehand in other currency + BalanceActionWithTrades[] + memory actions = new BalanceActionWithTrades[](1); + bytes32[] memory trades = new bytes32[](1); + trades[0] = encodeBorrowTrade(marketIndex, fCashAmount, maxBorrowRate); + + actions[0].actionType = DepositActionType.None; + actions[0].currencyId = currencyID; + actions[0].withdrawEntireCashBalance = true; + actions[0].depositActionAmount = 0; + actions[0].redeemToUnderlying = redeemToUnderlying; + actions[0].trades = trades; + + notional.batchBalanceAndTradeAction(address(this), actions); + } + + /// @return finalAmts payback amount on Aave + function _notionalBorrow(NotionalBorrowData memory data) + internal + returns (uint256[] memory) + { + uint256[] memory finalAmts = new uint256[](data.length); + for (uint256 i = 0; i < data.length; i++) { + uint16 _currencyID = toUint16(data.currencyIDs[i]); + uint256 _amt = data.amts[i]; + + //borrow token on Notional + _notionalBorrowOne( + data.fee, + data.redeemToUnderlying[i], + data.fCashAmount[i], + data.maxBorrowRate[i], + _currencyID, + data.marketIndex[i] + ); + + //calculating payback amounts for Aave v2 + if (_amt == uint256(-1)) { + _amt = getAaveV2PaybackAmt(data.rateModes[i], data.tokens[i]); + } + finalAmts[i] = _amt; + + //calculate and transferFees + calculateAndTransferFees(data.tokens[i], _amt, data.fee, true); + } + } + + // deposit as collateral i.e. reduces the risk of liquidation or mint ntokens i.e. provides liquidity, this method doesn't lends to the market at fixed rate + function _notionalDepositOne( + uint256 fee, + uint256 amt, + address token, + bool mintNToken, + uint16 currencyID + ) internal { + if (amt > 0) { + (uint256 feeAmt, uint256 depositAmount) = calculateFee( + amt, + fee, + false + ); + + token = (token == wethAddr) ? ethAddr : token; + transferFees(token, feeAmt); + + if (mintNToken) { + //deposit cash and mint nTokens + BalanceAction[] memory action = new BalanceAction[](1); + action[0].actionType = DepositActionType + .DepositUnderlyingAndMintNToken; + action[0].currencyId = toUint16(currencyID); + action[0].depositActionAmount = depositAmount; + + if (currencyID == ETH_CURRENCY_ID) { + notional.batchBalanceAction{ value: depositAmount }( + address(this), + action + ); + } else { + notional.batchBalanceAction(address(this), action); + } + } else { + //deposit as collateral + if (currencyID == ETH_CURRENCY_ID) { + notional.depositUnderlyingToken{ value: depositAmount }( + address(this), + currencyID, + depositAmount + ); + } else { + notional.depositAssetToken( + address(this), + currencyID, + depositAmount + ); + } + } + } + } + + // deposits on notional + function _notionalDeposit( + uint256 length, + uint256 fee, + uint256[] memory currencyIDs, + uint256[] memory amts, + address[] memory tokens, + bool[] memory mintNTokens + ) internal { + for (uint256 i = 0; i < length; i++) { + _notionalDepositOne( + fee, + amts[i], + tokens[i], + mintNTokens[i], + toUint16(currencyIDs[i]) + ); + } + } +} diff --git a/contracts/mainnet/connectors/refinance-notional/interface.sol b/contracts/mainnet/connectors/refinance-notional/interface.sol new file mode 100644 index 00000000..65b5e83f --- /dev/null +++ b/contracts/mainnet/connectors/refinance-notional/interface.sol @@ -0,0 +1,172 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.7.6; +pragma abicoder v2; + +import { TokenInterface } from "../../common/interfaces.sol"; + +/// @notice Different types of internal tokens +/// - UnderlyingToken: underlying asset for a cToken (except for Ether) +/// - cToken: Compound interest bearing token +/// - cETH: Special handling for cETH tokens +/// - Ether: the one and only +/// - NonMintable: tokens that do not have an underlying (therefore not cTokens) +enum TokenType { + UnderlyingToken, + cToken, + cETH, + Ether, + NonMintable +} + +/// @notice Specifies different deposit actions that can occur during BalanceAction or BalanceActionWithTrades +enum DepositActionType { + // No deposit action + None, + // Deposit asset cash, depositActionAmount is specified in asset cash external precision + DepositAsset, + // Deposit underlying tokens that are mintable to asset cash, depositActionAmount is specified in underlying token + // external precision + DepositUnderlying, + // Deposits specified asset cash external precision amount into an nToken and mints the corresponding amount of + // nTokens into the account + DepositAssetAndMintNToken, + // Deposits specified underlying in external precision, mints asset cash, and uses that asset cash to mint nTokens + DepositUnderlyingAndMintNToken, + // Redeems an nToken balance to asset cash. depositActionAmount is specified in nToken precision. Considered a deposit action + // because it deposits asset cash into an account. If there are fCash residuals that cannot be sold off, will revert. + RedeemNToken, + // Converts specified amount of asset cash balance already in Notional to nTokens. depositActionAmount is specified in + // Notional internal 8 decimal precision. + ConvertCashToNToken +} + +/// @notice Defines a balance action with a set of trades to do as well +struct BalanceActionWithTrades { + DepositActionType actionType; + uint16 currencyId; + uint256 depositActionAmount; + uint256 withdrawAmountInternalPrecision; + bool withdrawEntireCashBalance; + bool redeemToUnderlying; + // Array of tightly packed 32 byte objects that represent trades. See TradeActionType documentation + bytes32[] trades; +} + +/// @notice Defines a balance action for batchAction +struct BalanceAction { + // Deposit action to take (if any) + DepositActionType actionType; + uint16 currencyId; + // Deposit action amount must correspond to the depositActionType, see documentation above. + uint256 depositActionAmount; + // Withdraw an amount of asset cash specified in Notional internal 8 decimal precision + uint256 withdrawAmountInternalPrecision; + // If set to true, will withdraw entire cash balance. Useful if there may be an unknown amount of asset cash + // residual left from trading. + bool withdrawEntireCashBalance; + // If set to true, will redeem asset cash to the underlying token on withdraw. + bool redeemToUnderlying; +} + +struct Token { + // Address of the token + address tokenAddress; + // True if the token has a transfer fee which is used internally to determine + // the proper balance change + bool hasTransferFee; + // Decimal precision of the token as a power of 10 + int256 decimals; + // Type of token, enumerated above + TokenType tokenType; + // Used internally for tokens that have a collateral cap, zero if there is no cap + uint256 maxCollateralBalance; +} + +interface NotionalInterface { + function getCurrency(uint16 currencyId) + external + view + returns (Token memory assetToken, Token memory underlyingToken); + + function getAccountBalance(uint16 currencyId, address account) + external + view + returns ( + int256 cashBalance, + int256 nTokenBalance, + uint256 lastClaimTime + ); + + function depositUnderlyingToken( + address account, + uint16 currencyId, + uint256 amountExternalPrecision + ) external payable returns (uint256); + + function depositAssetToken( + address account, + uint16 currencyId, + uint256 amountExternalPrecision + ) external returns (uint256); + + function withdraw( + uint16 currencyId, + uint88 amountInternalPrecision, + bool redeemToUnderlying + ) external returns (uint256); + + function nTokenClaimIncentives() external returns (uint256); + + function nTokenRedeem( + address redeemer, + uint16 currencyId, + uint96 tokensToRedeem_, + bool sellTokenAssets, + bool acceptResidualAssets + ) external returns (int256); + + function batchBalanceAction( + address account, + BalanceAction[] calldata actions + ) external payable; + + function batchBalanceAndTradeAction( + address account, + BalanceActionWithTrades[] calldata actions + ) external payable; +} + +///@dev Aave Interfaces +// Aave Protocol Data Provider +interface AaveV2DataProviderInterface { + 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 + ); +} + +// Aave v2 Helpers +interface AaveV2Interface { + function deposit(address _asset, uint256 _amount, address _onBehalfOf, uint16 _referralCode) external; + function withdraw(address _asset, uint256 _amount, address _to) external; + function borrow( + address _asset, + uint256 _amount, + uint256 _interestRateMode, + uint16 _referralCode, + address _onBehalfOf + ) external; + function repay(address _asset, uint256 _amount, uint256 _rateMode, address _onBehalfOf) external; + function setUserUseReserveAsCollateral(address _asset, bool _useAsCollateral) external; +} + +interface AaveV2LendingPoolProviderInterface { + function getLendingPool() external view returns (address); +} \ No newline at end of file diff --git a/contracts/mainnet/connectors/refinance-notional/main.sol b/contracts/mainnet/connectors/refinance-notional/main.sol new file mode 100644 index 00000000..d267fb59 --- /dev/null +++ b/contracts/mainnet/connectors/refinance-notional/main.sol @@ -0,0 +1,143 @@ +//SPDX-License-Identifier: MIT +pragma solidity ^0.7.6; +pragma experimental ABIEncoderV2; + +/** + * @title Refinance Notional, Aave v2. + * @dev Refinancing. + */ +import { AaveV2Interface, AaveV2DataProviderInterface, AaveV2LendingPoolProviderInterface } from "./interface.sol"; +import { TokenInterface } from "../../common/interfaces.sol"; +import { AaveHelpers } from "./helpers/aaveV2.sol"; +import { NotionalHelpers } from "./helpers/notional.sol"; + +contract RefinanceResolver is AaveHelpers, NotionalHelpers { + struct RefinanceData { + uint256 collateralFee; + uint256 debtFee; + uint256[] currencyIDs; + uint256[] borrowMarketIndices; + uint256[] borrowfCashAmts; + uint256[] borrowAmts; + uint256[] withdrawAmts; + uint256[] paybackRateModes; + uint256[] maxBorrowingRates; + bool[] redeemBorrowToUnderlying; + bool[] mintNTokens; + } + + struct RefinanceInternalData { + AaveV2Interface aave; + AaveV2DataProviderInterface aaveData; + uint256[] depositAmts; + uint256[] paybackAmts; + address[] tokens; + TokenInterface[] tokenInterfaces; + } + + function _refinance(RefinanceData calldata data) + internal + returns (string memory _eventName, bytes memory _eventParam) + { + uint256 length = data.currencyIDs.length; + require(data.borrowMarketIndices.length == length, "length-mismatch"); + require(data.borrowfCashAmts.length == length, "length-mismatch"); + require(data.borrowAmts.length == length, "length-mismatch"); + require(data.withdrawAmts.length == length, "length-mismatch"); + require(data.paybackRateModes.length == length, "length-mismatch"); + require(data.maxBorrowingRates.length == length, "length-mismatch"); + require( + data.redeemBorrowToUnderlying.length == length, + "length-mismatch" + ); + require(data.mintNTokens.length == length, "length-mismatch"); + + RefinanceInternalData memory refinanceInternalData; + refinanceInternalData.aave = AaveV2Interface( + AaveV2LendingPoolProviderInterface(getAaveV2Provider) + .getLendingPool() + ); + refinanceInternalData.aaveData = aaveData; + + refinanceInternalData.depositAmts; + refinanceInternalData.paybackAmts; + + refinanceInternalData.tokens = getTokens(length, data.currencyIDs); + refinanceInternalData.tokenInterfaces = getTokenInterfaces( + length, + refinanceInternalData.tokens + ); + + // Aave v2 to 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; + + //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 + ); + + _eventName = "LogRefinance(uint,uint,address[],uint[],uint[],uint[],uint[])"; + _eventParam = abi.encode( + data.collateralFee, + data.debtFee, + refinanceInternalData.tokens, + refinanceInternalData.paybackAmts, + refinanceInternalData.depositAmts, + data.borrowMarketIndices, + data.maxBorrowingRates + ); + } + + /** + * @dev Refinance + * @notice Refinancing between Notional and Aave V2 + * @param data refinance data. + */ + function refinance(RefinanceData calldata data) + external + payable + returns (string memory _eventName, bytes memory _eventParam) + { + (_eventName, _eventParam) = _refinance(data); + } +} + +contract ConnectV2Refinance is RefinanceResolver { + string public name = "Refinance-v1.2"; +}