Skip to content

Commit

Permalink
Make-aave-vars-public (#17)
Browse files Browse the repository at this point in the history
* private -> public

* keeper

* compute lib

* remove claim from sellrewards

* deploy

* fix tests

* update flashloan max liquidity index

* deploy cost

* optimizer
  • Loading branch information
teddav authored Apr 7, 2022
1 parent 0d54eee commit dc27c89
Show file tree
Hide file tree
Showing 12 changed files with 146 additions and 92 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,13 @@ contract AaveFlashloanStrategy is BaseStrategyUpgradeable, IERC3156FlashBorrower
// ========================= Aave Protocol Parameters ==========================

IReserveInterestRateStrategy private _interestRateStrategyAddress;
uint256 private _cooldownSeconds;
uint256 private _unstakeWindow;
int256 private _reserveFactor;
int256 private _slope1;
int256 private _slope2;
int256 private _r0;
int256 private _uOptimal;
uint256 public cooldownSeconds;
uint256 public unstakeWindow;
int256 public reserveFactor;
int256 public slope1;
int256 public slope2;
int256 public r0;
int256 public uOptimal;

// =============================== Parameters and Variables ====================

Expand Down Expand Up @@ -467,12 +467,8 @@ contract AaveFlashloanStrategy is BaseStrategyUpgradeable, IERC3156FlashBorrower
/// @param payload Bytes needed for 1Inch API. Tokens swapped should be: stkAave -> `want` or Aave -> `want`
function sellRewards(
uint256 minAmountOut,
bytes memory payload,
bool claim
bytes memory payload
) external onlyRole(KEEPER_ROLE) {
if (claim) {
_claimRewards();
}
//solhint-disable-next-line
(bool success, bytes memory result) = _oneInch.call(payload);
if (!success) _revertBytes(result);
Expand Down Expand Up @@ -526,6 +522,10 @@ contract AaveFlashloanStrategy is BaseStrategyUpgradeable, IERC3156FlashBorrower
}
}

function claimRewards() external onlyRole(KEEPER_ROLE) {
_claimRewards();
}

/// @notice Reduce exposure by withdrawing funds and repaying debt
/// @param amountToFree Amount of `want` to withdraw/repay
/// @return balance Current balance of `want`
Expand Down Expand Up @@ -756,13 +756,13 @@ contract AaveFlashloanStrategy is BaseStrategyUpgradeable, IERC3156FlashBorrower
/// @notice Internal version of the `_setAavePoolVariables`
function _setAavePoolVariables() internal {
(, , , , uint256 reserveFactor_, , , , , ) = _protocolDataProvider.getReserveConfigurationData(address(want));
_cooldownSeconds = IStakedAave(_stkAave).COOLDOWN_SECONDS();
_unstakeWindow = IStakedAave(_stkAave).UNSTAKE_WINDOW();
_reserveFactor = int256(reserveFactor_ * 10**23);
_slope1 = int256(_interestRateStrategyAddress.variableRateSlope1());
_slope2 = int256(_interestRateStrategyAddress.variableRateSlope2());
_r0 = int256(_interestRateStrategyAddress.baseVariableBorrowRate());
_uOptimal = int256(_interestRateStrategyAddress.OPTIMAL_UTILIZATION_RATE());
cooldownSeconds = IStakedAave(_stkAave).COOLDOWN_SECONDS();
unstakeWindow = IStakedAave(_stkAave).UNSTAKE_WINDOW();
reserveFactor = int256(reserveFactor_ * 10**23);
slope1 = int256(_interestRateStrategyAddress.variableRateSlope1());
slope2 = int256(_interestRateStrategyAddress.variableRateSlope2());
r0 = int256(_interestRateStrategyAddress.baseVariableBorrowRate());
uOptimal = int256(_interestRateStrategyAddress.OPTIMAL_UTILIZATION_RATE());
}

// ========================= Internal View Functions ===========================
Expand Down Expand Up @@ -796,7 +796,7 @@ contract AaveFlashloanStrategy is BaseStrategyUpgradeable, IERC3156FlashBorrower
) = _protocolDataProvider.getReserveData(address(want));

parameters = ComputeProfitability.SCalculateBorrow({
reserveFactor: _reserveFactor,
reserveFactor: reserveFactor,
totalStableDebt: int256(totalStableDebt * normalizationFactor),
totalVariableDebt: int256((totalVariableDebt - currentBorrow) * normalizationFactor),
totalDeposits: int256(
Expand All @@ -813,10 +813,10 @@ contract AaveFlashloanStrategy is BaseStrategyUpgradeable, IERC3156FlashBorrower
rewardBorrow: 0,
strategyAssets: int256(balanceExcludingRewards * normalizationFactor),
guessedBorrowAssets: int256(guessedBorrow * normalizationFactor),
slope1: _slope1,
slope2: _slope2,
r0: _r0,
uOptimal: _uOptimal
slope1: slope1,
slope2: slope2,
r0: r0,
uOptimal: uOptimal
});
}

Expand Down Expand Up @@ -921,11 +921,11 @@ contract AaveFlashloanStrategy is BaseStrategyUpgradeable, IERC3156FlashBorrower
/// the strategy should claim
function _checkCooldown() internal view returns (uint256 cooldownStatus) {
uint256 cooldownStartTimestamp = IStakedAave(_stkAave).stakersCooldowns(address(this));
uint256 nextClaimStartTimestamp = cooldownStartTimestamp + _cooldownSeconds;
uint256 nextClaimStartTimestamp = cooldownStartTimestamp + cooldownSeconds;
if (cooldownStartTimestamp == 0) {
return 0;
}
if (block.timestamp > nextClaimStartTimestamp && block.timestamp <= nextClaimStartTimestamp + _unstakeWindow) {
if (block.timestamp > nextClaimStartTimestamp && block.timestamp <= nextClaimStartTimestamp + unstakeWindow) {
return 1;
}
if (block.timestamp < nextClaimStartTimestamp) {
Expand Down
4 changes: 3 additions & 1 deletion contracts/strategies/AaveFlashloanStrategy/AaveLibraries.sol
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,9 @@ library FlashMintLib {
requiredDAI = (rayDiv * getReserveNormalizedIncome + (_RAY / 2)) / _RAY;

if (requiredDAI > _maxLiquidity) {
requiredDAI = _maxLiquidity;
requiredDAI = (_maxLiquidity * _RAY - (_RAY / 2)) / getReserveNormalizedIncome;
requiredDAI = (requiredDAI * liquidityIndex - liquidityIndex / 2) / _RAY;

// NOTE: if we cap amountDAI, we reduce amountToken we are taking too
amount =
(fromDAI(requiredDAI - requiredDAIToCloseLTVGap, token) * collatRatioDAI) /
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ library ComputeProfitability {
/// to maximize folding revenues
/// @dev Performs a newton Raphson approximation to get the zero point of the derivative of the
/// revenue function of the protocol depending on the amount borrowed
function computeProfitability(SCalculateBorrow memory parameters) external pure returns (int256 borrow) {
function computeProfitability(SCalculateBorrow memory parameters) internal pure returns (int256 borrow) {
(int256 y, , ) = _revenuePrimes(0, parameters, true);
(int256 revenueWithBorrow, , ) = _revenuePrimes(_BASE_RAY, parameters, true);

Expand Down
45 changes: 22 additions & 23 deletions deploy/StrategyAaveFlashloan.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { DeployFunction } from 'hardhat-deploy/types';
import { CONTRACTS_ADDRESSES, Interfaces } from '@angleprotocol/sdk';
import { Contract, utils } from 'ethers';
import { BigNumber, Contract, utils } from 'ethers';
import { AaveFlashloanStrategy__factory, PoolManager } from '../typechain';
import { impersonate } from '../test/test-utils';
import { network } from 'hardhat';
Expand All @@ -12,18 +12,13 @@ const func: DeployFunction = async ({ deployments, ethers }) => {
const governor = CONTRACTS_ADDRESSES[1].GovernanceMultiSig as string;
const guardian = CONTRACTS_ADDRESSES[1].Guardian as string;

// TODO: change to real keeper
const keeper = '0xC2ad4f9799Dc7Cbc88958d1165bC43507664f3E0';
// const keeper = '0xcC617C6f9725eACC993ac626C7efC6B96476916E';
// const keeper = '0xC2ad4f9799Dc7Cbc88958d1165bC43507664f3E0';
const keeper = '0xcC617C6f9725eACC993ac626C7efC6B96476916E';

const flashMintLib = await deploy('FlashMintLib', {
contract: 'FlashMintLib',
from: deployer.address,
});
const computeProfitabilityLib = await deploy('ComputeProfitability', {
contract: 'ComputeProfitability',
from: deployer.address,
});

const poolManager = new Contract(
CONTRACTS_ADDRESSES[1].agEUR.collaterals!.USDC.PoolManager as string,
Expand Down Expand Up @@ -53,10 +48,7 @@ const func: DeployFunction = async ({ deployments, ethers }) => {
contract: 'AaveFlashloanStrategy',
from: deployer.address,
args: [],
libraries: {
FlashMintLib: flashMintLib.address,
ComputeProfitability: computeProfitabilityLib.address,
},
libraries: { FlashMintLib: flashMintLib.address },
});

const initializeData = AaveFlashloanStrategy__factory.createInterface().encodeFunctionData('initialize', [
Expand All @@ -76,20 +68,27 @@ const func: DeployFunction = async ({ deployments, ethers }) => {

console.log('Implementation deployed at address: ', strategyImplementation.address);
console.log('Strategy (proxy) successfully deployed at address: ', proxy.address);
console.log(
'Deploy cost',
(strategyImplementation.receipt?.gasUsed as BigNumber)?.add(proxy.receipt?.gasUsed as BigNumber)?.toString(),
);

const strategy = new Contract(proxy.address, ['function harvest() external'], deployer);
const oldStrategy = '0x5fE0E497Ac676d8bA78598FC8016EBC1E6cE14a3';
const _old = new Contract(oldStrategy, ['function harvest() external'], deployer);
// const strategy = new Contract(proxy.address, ['function harvest() external'], deployer);
// const oldStrategy = new Contract(
// '0x5fE0E497Ac676d8bA78598FC8016EBC1E6cE14a3',
// ['function harvest() external'],
// deployer,
// );

// CHANGE DEBT RATIOS
await impersonate('0xdC4e6DFe07EFCa50a197DF15D9200883eF4Eb1c8', async _governor => {
await network.provider.send('hardhat_setBalance', [_governor.address, '0x8ac7230489e80000']);
await poolManager.connect(_governor).updateStrategyDebtRatio(oldStrategy, utils.parseUnits('0', 9));
await poolManager.connect(_governor).addStrategy(strategy.address, utils.parseUnits('0.95', 9));
});
// // CHANGE DEBT RATIOS
// await impersonate('0xdC4e6DFe07EFCa50a197DF15D9200883eF4Eb1c8', async _governor => {
// await network.provider.send('hardhat_setBalance', [_governor.address, '0x8ac7230489e80000']);
// await poolManager.connect(_governor).updateStrategyDebtRatio(oldStrategy.address, utils.parseUnits('0', 9));
// await poolManager.connect(_governor).addStrategy(strategy.address, utils.parseUnits('0.95', 9));
// });

await _old.harvest();
await strategy.harvest();
// await oldStrategy.harvest();
// await strategy.harvest();
};

func.tags = ['aave_flashloan_strategy'];
Expand Down
2 changes: 1 addition & 1 deletion hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ const config: HardhatUserConfig = {
settings: {
optimizer: {
enabled: true,
runs: 1,
runs: 3800,
},
// debug: { revertStrings: 'strip' },
},
Expand Down
78 changes: 78 additions & 0 deletions scripts/keeper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/* eslint-disable camelcase */
import { ethers, network } from 'hardhat';
import { utils, constants, BigNumber } from 'ethers';
import { ILendingPool__factory, ILendingPool, ERC20, ERC20__factory } from '../typechain';

export const logBN = (amount: BigNumber, { base = 6, pad = 20, sign = false } = {}) => {
const num = parseFloat(utils.formatUnits(amount, base));
const formattedNum = new Intl.NumberFormat('fr-FR', {
style: 'decimal',
maximumFractionDigits: 4,
minimumFractionDigits: 4,
signDisplay: sign ? 'always' : 'never',
}).format(num);
return formattedNum.padStart(pad, ' ');
};

async function main() {
const USDC = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48';

const wantToken = (await ethers.getContractAt(ERC20__factory.abi, USDC)) as ERC20;
const aToken = (await ethers.getContractAt(
ERC20__factory.abi,
'0xBcca60bB61934080951369a648Fb03DF4F96263C',
)) as ERC20;

const lendingPool = (await ethers.getContractAt(
ILendingPool__factory.abi,
'0x7d2768dE32b0b80b7a3454c06BdAc94A69DDc7A9',
)) as ILendingPool;

await network.provider.request({
method: 'hardhat_impersonateAccount',
params: ['0x6262998Ced04146fA42253a5C0AF90CA02dfd2A3'],
});
const richUSDCUser = await ethers.getSigner('0x6262998Ced04146fA42253a5C0AF90CA02dfd2A3');
await wantToken.connect(richUSDCUser).approve(lendingPool.address, constants.MaxUint256);
await aToken.connect(richUSDCUser).approve(lendingPool.address, constants.MaxUint256);

// === HELPERS ===
const randomDeposit = async () => {
const min = 20_000_000;
const max = 100_000_000;
const amount = utils.parseUnits(Math.floor(Math.random() * (max - min + 1) + min).toString(), 6);
console.log(`user depositing... ${logBN(amount)}`);
await lendingPool.connect(richUSDCUser).deposit(USDC, amount, richUSDCUser.address, 0);
};
const randomWithdraw = async () => {
const min = 5_000_000;
const max = 30_000_000;
let amount = utils.parseUnits(Math.floor(Math.random() * (max - min + 1) + min).toString(), 6);
const maxAmount = await aToken.balanceOf(richUSDCUser.address);
if (amount.gt(maxAmount)) {
amount = maxAmount;
}
console.log(`user withdrawing... ${logBN(amount)} (max: ${logBN(maxAmount)})`);
await lendingPool.connect(richUSDCUser).withdraw(USDC, amount, richUSDCUser.address);
};

await randomDeposit();
await wait();

for (let i = 0; i < 8; i++) {
if (Math.random() < 0.7) await randomDeposit();
else await randomWithdraw();
await wait();
}
console.log('current user deposits: ', logBN(await aToken.balanceOf(richUSDCUser.address)));
}

const wait = (n = 10000) => {
return new Promise(resolve => {
setTimeout(() => {
resolve('ok');
}, n);
});
};

main();
14 changes: 2 additions & 12 deletions test/ComputeProfitability/computeProfitability.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import { BigNumber, Contract } from 'ethers';
import { formatUnits, parseUnits } from 'ethers/lib/utils';
import { ethers } from 'hardhat';
import { ComputeProfitability, ComputeProfitability__factory } from '../../typechain';
import { parseUnits } from 'ethers/lib/utils';
import { expectApproxDelta } from '../../utils/bignumber';
import { deploy } from '../test-utils';

Expand All @@ -28,15 +26,7 @@ export type SCalculateBorrow = {

describe('AaveFlashLoanStrategy - ComputeProfitability', () => {
before(async () => {
const [deployer] = await ethers.getSigners();

const computeProfitabilityLib = (await deploy('ComputeProfitability')) as ComputeProfitability;

computeProfitabilityContract = await deploy('ComputeProfitabilityTest', [], {
libraries: {
ComputeProfitability: computeProfitabilityLib.address,
},
});
computeProfitabilityContract = await deploy('ComputeProfitabilityTest', []);
});

describe('Testing Optim', () => {
Expand Down
17 changes: 7 additions & 10 deletions test/strategies/aaveFlashloanStrategy1.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import {
ERC20,
ERC20__factory,
IAaveIncentivesController__factory,
ComputeProfitability,
IStakedAave,
IStakedAave__factory,
AaveFlashloanStrategy__factory,
Expand Down Expand Up @@ -44,7 +43,6 @@ describe('AaveFlashloan Strat', () => {
let incentivesController: IAaveIncentivesController;
let lendingPool: ILendingPool;
let flashMintLib: FlashMintLib;
let computeProfitabilityLib: ComputeProfitability;

let strategy: AaveFlashloanStrategy;

Expand Down Expand Up @@ -94,13 +92,9 @@ describe('AaveFlashloan Strat', () => {
)) as ILendingPool;

flashMintLib = (await deploy('FlashMintLib')) as FlashMintLib;
computeProfitabilityLib = (await deploy('ComputeProfitability')) as ComputeProfitability;

const strategyImplementation = (await deploy('AaveFlashloanStrategy', [], {
libraries: {
FlashMintLib: flashMintLib.address,
ComputeProfitability: computeProfitabilityLib.address,
},
libraries: { FlashMintLib: flashMintLib.address },
})) as AaveFlashloanStrategy;

const proxy = await deploy('TransparentUpgradeableProxy', [
Expand Down Expand Up @@ -402,7 +396,8 @@ describe('AaveFlashloan Strat', () => {
expect(await stkAave.stakersCooldowns(strategy.address)).to.equal(0);
expect(await wantToken.balanceOf(strategy.address)).to.equal(0);

expect(strategy.connect(guardian).sellRewards(0, '0x', true)).to.be.revertedWith(
await strategy.connect(keeper).claimRewards();
expect(strategy.connect(guardian).sellRewards(0, '0x')).to.be.revertedWith(
`AccessControl: account ${guardian.address.toLowerCase()} is missing role ${await strategy.KEEPER_ROLE()}`,
);

Expand All @@ -427,7 +422,8 @@ describe('AaveFlashloan Strat', () => {
// ).data.tx.data;
// await strategy.connect(keeper).sellRewards(0, payloadRevert, true);

await expect(strategy.connect(keeper).sellRewards(0, '0x', true)).to.be.reverted;
await strategy.connect(keeper).claimRewards();
await expect(strategy.connect(keeper).sellRewards(0, '0x')).to.be.reverted;

const chainId = 1;
const oneInchParams = qs.stringify({
Expand All @@ -445,7 +441,8 @@ describe('AaveFlashloan Strat', () => {

const usdcBefore = await wantToken.balanceOf(strategy.address);

await strategy.connect(keeper).sellRewards(0, payload, true);
await strategy.connect(keeper).claimRewards();
await strategy.connect(keeper).sellRewards(0, payload);

const usdcAfter = parseFloat(utils.formatUnits(await wantToken.balanceOf(strategy.address), 6));
const stkAaveAfter = parseFloat(utils.formatUnits(await stkAave.balanceOf(strategy.address)));
Expand Down
1 change: 0 additions & 1 deletion test/strategies/aaveFlashloanStrategy2.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ describe('AaveFlashloan strategy', () => {
await (await oldStrategy.harvest()).wait();

// we check that values are in the correct state
expect(await ethers.provider.getBlockNumber()).to.equal(14456170);
expect((await poolManager.getTotalAsset()).mul(3).div(4)).to.be.closeTo(BigNumber.from('0x5365efafcf9b'), 1000);

let _data = await protocolDataProvider.getReserveData(USDC);
Expand Down
Loading

0 comments on commit dc27c89

Please sign in to comment.