Skip to content

Commit 70f926f

Browse files
authored
ALM external audit fixes (#127)
Gas Optimizations: Declare state variables as immutable. Add check in component hooks to see if component is a debt or equity position. Added creating new Default position for borrow token in case debt is fully paid down qnd some borrow token remains.
1 parent af0b3e2 commit 70f926f

File tree

6 files changed

+234
-81
lines changed

6 files changed

+234
-81
lines changed

contracts/mocks/external/OneInchExchangeMock.sol

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,14 @@ contract OneInchExchangeMock {
5050
setTokenAddress = _setTokenAddress;
5151
}
5252

53+
function updateSendAmount(uint256 _newSendAmount) external {
54+
mockSendAmount = _newSendAmount;
55+
}
56+
57+
function updateReceiveAmount(uint256 _newReceiveAmount) external {
58+
mockReceiveAmount = _newReceiveAmount;
59+
}
60+
5361
// Conform to 1Inch Swap interface
5462
function swap(
5563
address _fromToken,

contracts/protocol/modules/AaveLeverageModule.sol

Lines changed: 102 additions & 66 deletions
Large diffs are not rendered by default.

test/integration/aaveUniswapLeverageDebtIssuance.spec.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,6 @@ describe.skip("AaveUniswapLeverageDebtIssuance", () => {
151151
aaveLeverageModule = await deployer.modules.deployAaveLeverageModule(
152152
setup.controller.address,
153153
aaveV2Setup.lendingPoolAddressesProvider.address,
154-
aaveV2Setup.protocolDataProvider.address,
155154
"contracts/protocol/integration/lib/AaveV2.sol:AaveV2",
156155
aaveV2Library.address,
157156
);

test/protocol/modules/aaveLeverageModule.spec.ts

Lines changed: 121 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,6 @@ describe("AaveLeverageModule", () => {
122122
aaveLeverageModule = await deployer.modules.deployAaveLeverageModule(
123123
setup.controller.address,
124124
aaveSetup.lendingPoolAddressesProvider.address,
125-
aaveSetup.protocolDataProvider.address,
126125
"contracts/protocol/integration/lib/AaveV2.sol:AaveV2",
127126
aaveV2Library.address,
128127
);
@@ -221,19 +220,16 @@ describe("AaveLeverageModule", () => {
221220
describe("#constructor", async () => {
222221
let subjectController: Address;
223222
let subjectLendingPoolAddressesProvider: Address;
224-
let subjectProtocolDataProvider: Address;
225223

226224
beforeEach(async () => {
227225
subjectController = setup.controller.address;
228226
subjectLendingPoolAddressesProvider = aaveSetup.lendingPoolAddressesProvider.address;
229-
subjectProtocolDataProvider = aaveSetup.protocolDataProvider.address;
230227
});
231228

232229
async function subject(): Promise<AaveLeverageModule> {
233230
return deployer.modules.deployAaveLeverageModule(
234231
subjectController,
235232
subjectLendingPoolAddressesProvider,
236-
subjectProtocolDataProvider,
237233
"contracts/protocol/integration/lib/AaveV2.sol:AaveV2",
238234
aaveV2Library.address
239235
);
@@ -249,11 +245,9 @@ describe("AaveLeverageModule", () => {
249245
it("should set the correct Aave contracts", async () => {
250246
const aaveLeverageModule = await subject();
251247

252-
const lendingPool = await aaveLeverageModule.lendingPool();
253248
const lendingPoolAddressesProvider = await aaveLeverageModule.lendingPoolAddressesProvider();
254249
const protocolDataProvider = await aaveLeverageModule.protocolDataProvider();
255250

256-
expect(lendingPool).to.eq(aaveSetup.lendingPool.address);
257251
expect(lendingPoolAddressesProvider).to.eq(aaveSetup.lendingPoolAddressesProvider.address);
258252
expect(protocolDataProvider).to.eq(aaveSetup.protocolDataProvider.address);
259253
});
@@ -1319,6 +1313,89 @@ describe("AaveLeverageModule", () => {
13191313
});
13201314
});
13211315

1316+
describe("when used to delever to zero", async () => {
1317+
1318+
beforeEach(async () => {
1319+
subjectMinRepayQuantity = ether(1001);
1320+
await oneInchExchangeMockFromWeth.updateReceiveAmount(subjectMinRepayQuantity);
1321+
1322+
subjectTradeData = oneInchExchangeMockFromWeth.interface.encodeFunctionData("swap", [
1323+
setup.weth.address, // Send token
1324+
setup.dai.address, // Receive token
1325+
subjectRedeemQuantity, // Send quantity
1326+
subjectMinRepayQuantity, // Min receive quantity
1327+
ZERO,
1328+
ADDRESS_ZERO,
1329+
[ADDRESS_ZERO],
1330+
EMPTY_BYTES,
1331+
[ZERO],
1332+
[ZERO],
1333+
]);
1334+
});
1335+
1336+
it("should transfer the correct components to the exchange", async () => {
1337+
const oldSourceTokenBalance = await setup.weth.balanceOf(oneInchExchangeMockFromWeth.address);
1338+
1339+
await subject();
1340+
const totalSourceQuantity = subjectRedeemQuantity;
1341+
const expectedSourceTokenBalance = oldSourceTokenBalance.add(totalSourceQuantity);
1342+
const newSourceTokenBalance = await setup.weth.balanceOf(oneInchExchangeMockFromWeth.address);
1343+
expect(newSourceTokenBalance).to.eq(expectedSourceTokenBalance);
1344+
});
1345+
1346+
it("should update the collateral position on the SetToken correctly", async () => {
1347+
const initialPositions = await setToken.getPositions();
1348+
1349+
await subject();
1350+
1351+
const currentPositions = await setToken.getPositions();
1352+
const newFirstPosition = (await setToken.getPositions())[0];
1353+
1354+
const newUnits = subjectRedeemQuantity;
1355+
const expectedFirstPositionUnit = initialPositions[0].unit.sub(newUnits);
1356+
1357+
expect(initialPositions.length).to.eq(2);
1358+
expect(currentPositions.length).to.eq(2);
1359+
expect(newFirstPosition.component).to.eq(aWETH.address);
1360+
expect(newFirstPosition.positionState).to.eq(0); // Default
1361+
expect(newFirstPosition.unit).to.eq(expectedFirstPositionUnit);
1362+
expect(newFirstPosition.module).to.eq(ADDRESS_ZERO);
1363+
});
1364+
1365+
it("should update the borrow position on the SetToken correctly", async () => {
1366+
const initialPositions = await setToken.getPositions();
1367+
1368+
await subject();
1369+
1370+
const currentPositions = await setToken.getPositions();
1371+
const newSecondPosition = (await setToken.getPositions())[1];
1372+
1373+
const expectedSecondPositionUnit = await setup.dai.balanceOf(setToken.address);
1374+
1375+
expect(initialPositions.length).to.eq(2);
1376+
expect(currentPositions.length).to.eq(2);
1377+
expect(newSecondPosition.component).to.eq(setup.dai.address);
1378+
expect(newSecondPosition.positionState).to.eq(0); // Default since we traded for more Dai than outstannding debt
1379+
expect(newSecondPosition.unit).to.eq(expectedSecondPositionUnit);
1380+
expect(newSecondPosition.module).to.eq(ADDRESS_ZERO);
1381+
});
1382+
1383+
it("should emit the correct LeverageDecreased event", async () => {
1384+
const totalCollateralQuantity = subjectRedeemQuantity;
1385+
const totalRepayQuantity = subjectMinRepayQuantity;
1386+
1387+
await expect(subject()).to.emit(aaveLeverageModule, "LeverageDecreased").withArgs(
1388+
setToken.address,
1389+
subjectCollateralAsset,
1390+
subjectRepayAsset,
1391+
oneInchExchangeAdapterFromWeth.address,
1392+
totalCollateralQuantity,
1393+
totalRepayQuantity,
1394+
ZERO
1395+
);
1396+
});
1397+
});
1398+
13221399
describe("when the exchange is not valid", async () => {
13231400
beforeEach(async () => {
13241401
subjectTradeAdapterName = "UNISWAP";
@@ -3052,7 +3129,7 @@ describe("AaveLeverageModule", () => {
30523129
subjectSetToken = setToken.address;
30533130
subjectSetQuantity = issueQuantity;
30543131
subjectComponent = setup.dai.address;
3055-
subjectIsEquity = true; // Unused by module
3132+
subjectIsEquity = false;
30563133
subjectCaller = mockModule;
30573134
});
30583135

@@ -3076,7 +3153,7 @@ describe("AaveLeverageModule", () => {
30763153
expect(currentDaiBalance).to.eq(preciseMul(borrowQuantity, subjectSetQuantity));
30773154
});
30783155

3079-
describe("when component has positive unit", async () => {
3156+
describe("when isEquity is false and component has positive unit (should not happen)", async () => {
30803157
beforeEach(async () => {
30813158
subjectComponent = aWETH.address;
30823159
});
@@ -3086,6 +3163,23 @@ describe("AaveLeverageModule", () => {
30863163
});
30873164
});
30883165

3166+
describe("when isEquity is true", async () => {
3167+
beforeEach(async () => {
3168+
subjectIsEquity = true;
3169+
});
3170+
3171+
it("should NOT increase borrowed quantity on the SetToken", async () => {
3172+
const previousDaiBalance = await setup.dai.balanceOf(setToken.address);
3173+
3174+
await subject();
3175+
3176+
const currentDaiBalance = await setup.dai.balanceOf(setToken.address);
3177+
3178+
expect(previousDaiBalance).to.eq(ZERO);
3179+
expect(currentDaiBalance).to.eq(ZERO);
3180+
});
3181+
});
3182+
30893183
describe("when caller is not module", async () => {
30903184
beforeEach(async () => {
30913185
subjectCaller = owner;
@@ -3203,7 +3297,7 @@ describe("AaveLeverageModule", () => {
32033297
subjectSetToken = setToken.address;
32043298
subjectSetQuantity = issueQuantity;
32053299
subjectComponent = setup.dai.address;
3206-
subjectIsEquity = true; // Unused by module
3300+
subjectIsEquity = false;
32073301
subjectCaller = mockModule;
32083302
});
32093303

@@ -3227,7 +3321,7 @@ describe("AaveLeverageModule", () => {
32273321
expect(currentDaiBalance).to.eq(ZERO);
32283322
});
32293323

3230-
describe("when component has positive unit", async () => {
3324+
describe("when _isEquity is false and component has positive unit", async () => {
32313325
beforeEach(async () => {
32323326
subjectComponent = aWETH.address;
32333327
});
@@ -3237,6 +3331,23 @@ describe("AaveLeverageModule", () => {
32373331
});
32383332
});
32393333

3334+
describe("when isEquity is true", async () => {
3335+
beforeEach(async () => {
3336+
subjectIsEquity = true;
3337+
});
3338+
3339+
it("should NOT decrease borrowed quantity on the SetToken", async () => {
3340+
const previousDaiBalance = await setup.dai.balanceOf(setToken.address);
3341+
3342+
await subject();
3343+
3344+
const currentDaiBalance = await setup.dai.balanceOf(setToken.address);
3345+
3346+
expect(previousDaiBalance).to.eq(repayQuantity);
3347+
expect(currentDaiBalance).to.eq(repayQuantity);
3348+
});
3349+
});
3350+
32403351
describe("when caller is not module", async () => {
32413352
beforeEach(async () => {
32423353
subjectCaller = owner;

utils/deploys/deployModules.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,6 @@ export default class DeployModules {
168168
public async deployAaveLeverageModule(
169169
controller: Address,
170170
lendingPoolAddressesProvider: Address,
171-
protocolDataProvider: Address,
172171
libraryName: string,
173172
libraryAddress: Address
174173
): Promise<AaveLeverageModule> {
@@ -182,8 +181,7 @@ export default class DeployModules {
182181
this._deployerSigner
183182
).deploy(
184183
controller,
185-
lendingPoolAddressesProvider,
186-
protocolDataProvider
184+
lendingPoolAddressesProvider
187185
);
188186
}
189187

utils/fixtures/aaveV2Fixture.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import DeployHelper from "../deploys";
2-
import { Signer } from "ethers";
2+
import { ethers , Signer } from "ethers";
33
import { JsonRpcProvider, Web3Provider } from "@ethersproject/providers";
44
import { Address } from "../types";
55
import { BigNumber, BigNumberish } from "@ethersproject/bignumber";
@@ -107,6 +107,7 @@ export class AaveV2Fixture {
107107
await this.lendingPoolAddressesProvider.setLendingRateOracle(this.lendingRateOracle.address);
108108
await this.lendingPoolAddressesProvider.setPoolAdmin(await this._ownerSigner.getAddress());
109109
await this.lendingPoolAddressesProvider.setLendingPoolCollateralManager(this.lendingPoolCollateralManager.address);
110+
await this.lendingPoolAddressesProvider.setAddress(ethers.utils.formatBytes32String("0x1"), this.protocolDataProvider.address);
110111

111112
// LendingPoolAddressProvider creates a new proxy contract and sets the passed in address as the implementation.
112113
// We then fetch the proxy's address and attach it to the contract object, which allows us to use the contract object

0 commit comments

Comments
 (0)