Skip to content

Commit f2907ac

Browse files
authored
feat(extension): Add support for alternative Flashloan providers to migration extension (#167)
* Add morpho flashloan implementation * Balancer flashloan option * Adjust subsidy amounts * Rename old migrate method to migrateAave * Rename to MigrationExtension * Reorder imports * Add morpho and balancer address as constructor args
1 parent f1d2baf commit f2907ac

File tree

7 files changed

+312
-32
lines changed

7 files changed

+312
-32
lines changed

contracts/adapters/AaveMigrationExtension.sol renamed to contracts/adapters/MigrationExtension.sol

Lines changed: 117 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ import { SafeCast } from "@openzeppelin/contracts/utils/SafeCast.sol";
2525
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
2626
import { SafeMath } from "@openzeppelin/contracts/math/SafeMath.sol";
2727

28+
import { IBalancerVault } from "../interfaces/IBalancerVault.sol";
29+
import { IMorpho } from "../interfaces/IMorpho.sol";
2830
import { FlashLoanSimpleReceiverBase } from "../lib/FlashLoanSimpleReceiverBase.sol";
2931
import { IPoolAddressesProvider } from "../interfaces/IPoolAddressesProvider.sol";
3032

@@ -39,7 +41,7 @@ import { ITradeModule } from "../interfaces/ITradeModule.sol";
3941
import { PreciseUnitMath } from "../lib/PreciseUnitMath.sol";
4042

4143
/**
42-
* @title AaveMigrationExtension
44+
* @title MigrationExtension
4345
* @author Index Coop
4446
* @notice This extension facilitates the migration of a SetToken's position from an unwrapped collateral
4547
* asset to another SetToken that consists solely of Aave's wrapped collateral asset. The migration is
@@ -49,7 +51,7 @@ import { PreciseUnitMath } from "../lib/PreciseUnitMath.sol";
4951
* redeeming any excess wrapped SetToken. This process is specifically designed to efficiently migrate
5052
* the SetToken's collateral using only the TradeModule on the SetToken.
5153
*/
52-
contract AaveMigrationExtension is BaseExtension, FlashLoanSimpleReceiverBase, IERC721Receiver {
54+
contract MigrationExtension is BaseExtension, FlashLoanSimpleReceiverBase, IERC721Receiver {
5355
using PreciseUnitMath for uint256;
5456
using SafeCast for int256;
5557
using SafeERC20 for IERC20;
@@ -81,13 +83,15 @@ contract AaveMigrationExtension is BaseExtension, FlashLoanSimpleReceiverBase, I
8183
ITradeModule public immutable tradeModule;
8284
IDebtIssuanceModule public immutable issuanceModule;
8385
INonfungiblePositionManager public immutable nonfungiblePositionManager;
86+
IMorpho public immutable morpho;
87+
IBalancerVault public immutable balancer;
8488

8589
uint256[] public tokenIds; // UniV3 LP Token IDs
8690

8791
/* ============ Constructor ============ */
8892

8993
/**
90-
* @notice Initializes the AaveMigrationExtension with immutable migration variables.
94+
* @notice Initializes the MigrationExtension with immutable migration variables.
9195
* @param _manager BaseManager contract for managing the SetToken's operations and permissions.
9296
* @param _underlyingToken Address of the underlying token to be migrated.
9397
* @param _aaveToken Address of Aave's wrapped collateral asset.
@@ -105,7 +109,9 @@ contract AaveMigrationExtension is BaseExtension, FlashLoanSimpleReceiverBase, I
105109
ITradeModule _tradeModule,
106110
IDebtIssuanceModule _issuanceModule,
107111
INonfungiblePositionManager _nonfungiblePositionManager,
108-
IPoolAddressesProvider _addressProvider
112+
IPoolAddressesProvider _addressProvider,
113+
IMorpho _morpho,
114+
IBalancerVault _balancer
109115
)
110116
public
111117
BaseExtension(_manager)
@@ -119,6 +125,8 @@ contract AaveMigrationExtension is BaseExtension, FlashLoanSimpleReceiverBase, I
119125
tradeModule = _tradeModule;
120126
issuanceModule = _issuanceModule;
121127
nonfungiblePositionManager = _nonfungiblePositionManager;
128+
morpho = _morpho;
129+
balancer = _balancer;
122130
}
123131

124132
/* ========== External Functions ========== */
@@ -258,12 +266,13 @@ contract AaveMigrationExtension is BaseExtension, FlashLoanSimpleReceiverBase, I
258266
/**
259267
* @notice OPERATOR ONLY: Migrates a SetToken's position from an unwrapped collateral asset to another SetToken
260268
* that consists solely of Aave's wrapped collateral asset
269+
* using Aave Flashloan
261270
* @param _decodedParams The decoded migration parameters.
262271
* @param _underlyingLoanAmount The amount of unwrapped collateral asset to be borrowed via flash loan.
263272
* @param _maxSubsidy The maximum amount of unwrapped collateral asset to be transferred to the Extension as a subsidy.
264273
* @return underlyingOutputAmount The amount of unwrapped collateral asset returned to the operator.
265274
*/
266-
function migrate(
275+
function migrateAave(
267276
DecodedParams memory _decodedParams,
268277
uint256 _underlyingLoanAmount,
269278
uint256 _maxSubsidy
@@ -293,6 +302,109 @@ contract AaveMigrationExtension is BaseExtension, FlashLoanSimpleReceiverBase, I
293302
underlyingOutputAmount = _returnExcessUnderlying();
294303
}
295304

305+
/**
306+
* @notice OPERATOR ONLY: Migrates a SetToken's position from an unwrapped collateral asset to another SetToken
307+
* that consists solely of Aave's wrapped collateral asset
308+
* using Balancer Flashloan
309+
* @param _decodedParams The decoded migration parameters.
310+
* @param _underlyingLoanAmount The amount of unwrapped collateral asset to be borrowed via flash loan.
311+
* @param _maxSubsidy The maximum amount of unwrapped collateral asset to be transferred to the Extension as a subsidy.
312+
* @return underlyingOutputAmount The amount of unwrapped collateral asset returned to the operator.
313+
*/
314+
function migrateBalancer(
315+
DecodedParams memory _decodedParams,
316+
uint256 _underlyingLoanAmount,
317+
uint256 _maxSubsidy
318+
)
319+
external
320+
onlyOperator
321+
returns (uint256 underlyingOutputAmount)
322+
{
323+
// Subsidize the migration
324+
if (_maxSubsidy > 0) {
325+
underlyingToken.transferFrom(msg.sender, address(this), _maxSubsidy);
326+
}
327+
328+
// Encode migration parameters for flash loan callback
329+
bytes memory params = abi.encode(_decodedParams);
330+
address[] memory tokens = new address[](1);
331+
tokens[0] = address(underlyingToken);
332+
uint256[] memory amounts = new uint256[](1);
333+
amounts[0] = _underlyingLoanAmount;
334+
335+
// Request flash loan for the underlying token
336+
balancer.flashLoan(address(this), tokens, amounts, params);
337+
338+
// Return remaining underlying token to the operator
339+
underlyingOutputAmount = _returnExcessUnderlying();
340+
}
341+
342+
/**
343+
* @dev Callback function for Balancer flashloan
344+
*/
345+
function receiveFlashLoan(
346+
IERC20[] memory tokens,
347+
uint256[] memory amounts,
348+
uint256[] memory feeAmounts,
349+
bytes memory params
350+
) external {
351+
require(msg.sender == address(balancer));
352+
// Decode parameters and migrate
353+
DecodedParams memory decodedParams = abi.decode(params, (DecodedParams));
354+
_migrate(decodedParams);
355+
356+
underlyingToken.transfer(address(balancer), amounts[0] + feeAmounts[0]);
357+
}
358+
359+
360+
/**
361+
* @notice OPERATOR ONLY: Migrates a SetToken's position from an unwrapped collateral asset to another SetToken
362+
* that consists solely of Aave's wrapped collateral asset
363+
* using Morpho Flashloan
364+
* @param _decodedParams The decoded migration parameters.
365+
* @param _underlyingLoanAmount The amount of unwrapped collateral asset to be borrowed via flash loan.
366+
* @param _maxSubsidy The maximum amount of unwrapped collateral asset to be transferred to the Extension as a subsidy.
367+
* @return underlyingOutputAmount The amount of unwrapped collateral asset returned to the operator.
368+
*/
369+
function migrateMorpho(
370+
DecodedParams memory _decodedParams,
371+
uint256 _underlyingLoanAmount,
372+
uint256 _maxSubsidy
373+
)
374+
external
375+
onlyOperator
376+
returns (uint256 underlyingOutputAmount)
377+
{
378+
// Subsidize the migration
379+
if (_maxSubsidy > 0) {
380+
underlyingToken.transferFrom(msg.sender, address(this), _maxSubsidy);
381+
}
382+
383+
// Encode migration parameters for flash loan callback
384+
bytes memory params = abi.encode(_decodedParams);
385+
386+
// Request flash loan for the underlying token
387+
morpho.flashLoan(address(underlyingToken), _underlyingLoanAmount, params);
388+
389+
// Return remaining underlying token to the operator
390+
underlyingOutputAmount = _returnExcessUnderlying();
391+
}
392+
393+
/**
394+
* @dev Callback function for Morpho Flashloan
395+
*/
396+
function onMorphoFlashLoan(uint256 assets, bytes calldata params) external
397+
{
398+
require(msg.sender == address(morpho), "MigrationExtension: invalid flashloan sender");
399+
400+
// Decode parameters and migrate
401+
DecodedParams memory decodedParams = abi.decode(params, (DecodedParams));
402+
_migrate(decodedParams);
403+
404+
underlyingToken.approve(address(morpho), assets);
405+
}
406+
407+
296408
/**
297409
* @dev Callback function for Aave V3 flash loan, executed post-loan. It decodes the provided parameters, conducts the migration, and repays the flash loan.
298410
* @param amount The amount borrowed.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
pragma solidity 0.6.10;
2+
interface IBalancerVault {
3+
function flashLoan(address recipient, address[] memory tokens, uint256[] memory amounts, bytes memory userData) external;
4+
}

contracts/interfaces/IMorpho.sol

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
// SPDX-License-bytes32entifier: UNLICENSED
2+
pragma solidity 0.6.10;
3+
pragma experimental ABIEncoderV2;
4+
5+
interface IMorpho {
6+
7+
struct Authorization {
8+
address authorizer;
9+
address authorized;
10+
bool isAuthorized;
11+
uint256 nonce;
12+
uint256 deadline;
13+
}
14+
15+
struct MarketParams {
16+
address loanToken;
17+
address collateralToken;
18+
address oracle;
19+
address irm;
20+
uint256 lltv;
21+
}
22+
23+
struct Signature {
24+
uint8 v;
25+
bytes32 r;
26+
bytes32 s;
27+
}
28+
29+
event AccrueInterest(bytes32 indexed id, uint256 prevBorrowRate, uint256 interest, uint256 feeShares);
30+
event Borrow(
31+
bytes32 indexed id,
32+
address caller,
33+
address indexed onBehalf,
34+
address indexed receiver,
35+
uint256 assets,
36+
uint256 shares
37+
);
38+
event CreateMarket(bytes32 indexed id, MarketParams marketParams);
39+
event EnableIrm(address indexed irm);
40+
event EnableLltv(uint256 lltv);
41+
event FlashLoan(address indexed caller, address indexed token, uint256 assets);
42+
event IncrementNonce(address indexed caller, address indexed authorizer, uint256 usedNonce);
43+
event Liquidate(
44+
bytes32 indexed id,
45+
address indexed caller,
46+
address indexed borrower,
47+
uint256 repaidAssets,
48+
uint256 repaidShares,
49+
uint256 seizedAssets,
50+
uint256 badDebtAssets,
51+
uint256 badDebtShares
52+
);
53+
event Repay(bytes32 indexed id, address indexed caller, address indexed onBehalf, uint256 assets, uint256 shares);
54+
event SetAuthorization(
55+
address indexed caller, address indexed authorizer, address indexed authorized, bool newIsAuthorized
56+
);
57+
event SetFee(bytes32 indexed id, uint256 newFee);
58+
event SetFeeRecipient(address indexed newFeeRecipient);
59+
event SetOwner(address indexed newOwner);
60+
event Supply(bytes32 indexed id, address indexed caller, address indexed onBehalf, uint256 assets, uint256 shares);
61+
event SupplyCollateral(bytes32 indexed id, address indexed caller, address indexed onBehalf, uint256 assets);
62+
event Withdraw(
63+
bytes32 indexed id,
64+
address caller,
65+
address indexed onBehalf,
66+
address indexed receiver,
67+
uint256 assets,
68+
uint256 shares
69+
);
70+
event WithdrawCollateral(
71+
bytes32 indexed id, address caller, address indexed onBehalf, address indexed receiver, uint256 assets
72+
);
73+
74+
75+
function DOMAIN_SEPARATOR() external view returns (bytes32);
76+
function accrueInterest(MarketParams memory marketParams) external;
77+
function borrow(
78+
MarketParams memory marketParams,
79+
uint256 assets,
80+
uint256 shares,
81+
address onBehalf,
82+
address receiver
83+
) external returns (uint256, uint256);
84+
function createMarket(MarketParams memory marketParams) external;
85+
function enableIrm(address irm) external;
86+
function enableLltv(uint256 lltv) external;
87+
function extSloads(bytes32[] memory slots) external view returns (bytes32[] memory res);
88+
function feeRecipient() external view returns (address);
89+
function flashLoan(address token, uint256 assets, bytes memory data) external;
90+
function idToMarketParams(bytes32)
91+
external
92+
view
93+
returns (address loanToken, address collateralToken, address oracle, address irm, uint256 lltv);
94+
function isAuthorized(address, address) external view returns (bool);
95+
function isIrmEnabled(address) external view returns (bool);
96+
function isLltvEnabled(uint256) external view returns (bool);
97+
function liquidate(
98+
MarketParams memory marketParams,
99+
address borrower,
100+
uint256 seizedAssets,
101+
uint256 repaidShares,
102+
bytes memory data
103+
) external returns (uint256, uint256);
104+
function market(bytes32)
105+
external
106+
view
107+
returns (
108+
uint128 totalSupplyAssets,
109+
uint128 totalSupplyShares,
110+
uint128 totalBorrowAssets,
111+
uint128 totalBorrowShares,
112+
uint128 lastUpdate,
113+
uint128 fee
114+
);
115+
function nonce(address) external view returns (uint256);
116+
function owner() external view returns (address);
117+
function position(bytes32, address)
118+
external
119+
view
120+
returns (uint256 supplyShares, uint128 borrowShares, uint128 collateral);
121+
function repay(
122+
MarketParams memory marketParams,
123+
uint256 assets,
124+
uint256 shares,
125+
address onBehalf,
126+
bytes memory data
127+
) external returns (uint256, uint256);
128+
function setAuthorization(address authorized, bool newIsAuthorized) external;
129+
function setAuthorizationWithSig(Authorization memory authorization, Signature memory signature) external;
130+
function setFee(MarketParams memory marketParams, uint256 newFee) external;
131+
function setFeeRecipient(address newFeeRecipient) external;
132+
function setOwner(address newOwner) external;
133+
function supply(
134+
MarketParams memory marketParams,
135+
uint256 assets,
136+
uint256 shares,
137+
address onBehalf,
138+
bytes memory data
139+
) external returns (uint256, uint256);
140+
function supplyCollateral(MarketParams memory marketParams, uint256 assets, address onBehalf, bytes memory data)
141+
external;
142+
function withdraw(
143+
MarketParams memory marketParams,
144+
uint256 assets,
145+
uint256 shares,
146+
address onBehalf,
147+
address receiver
148+
) external returns (uint256, uint256);
149+
function withdrawCollateral(MarketParams memory marketParams, uint256 assets, address onBehalf, address receiver)
150+
external;
151+
}

0 commit comments

Comments
 (0)