2020-06-30 12:09:28 +00:00
|
|
|
import BigNumber from 'bignumber.js';
|
2020-06-12 20:12:53 +00:00
|
|
|
|
|
|
|
import {
|
2020-08-21 10:38:08 +00:00
|
|
|
calcExpectedReserveDataAfterBorrow,
|
2020-06-12 20:12:53 +00:00
|
|
|
calcExpectedReserveDataAfterDeposit,
|
2020-08-21 10:38:08 +00:00
|
|
|
calcExpectedReserveDataAfterRepay,
|
|
|
|
calcExpectedReserveDataAfterStableRateRebalance,
|
|
|
|
calcExpectedReserveDataAfterSwapRateMode,
|
2020-08-19 10:56:39 +00:00
|
|
|
calcExpectedReserveDataAfterWithdraw,
|
2020-06-12 20:12:53 +00:00
|
|
|
calcExpectedUserDataAfterBorrow,
|
2020-08-21 10:38:08 +00:00
|
|
|
calcExpectedUserDataAfterDeposit,
|
2020-06-12 20:12:53 +00:00
|
|
|
calcExpectedUserDataAfterRepay,
|
|
|
|
calcExpectedUserDataAfterSetUseAsCollateral,
|
|
|
|
calcExpectedUserDataAfterStableRateRebalance,
|
2020-08-21 10:38:08 +00:00
|
|
|
calcExpectedUserDataAfterSwapRateMode,
|
|
|
|
calcExpectedUserDataAfterWithdraw,
|
2020-06-30 12:09:28 +00:00
|
|
|
} from './utils/calculations';
|
|
|
|
import {getReserveAddressFromSymbol, getReserveData, getUserData} from './utils/helpers';
|
2020-06-12 20:12:53 +00:00
|
|
|
|
2020-10-15 17:19:02 +00:00
|
|
|
import {convertToCurrencyDecimals} from '../../helpers/contracts-helpers';
|
2020-11-03 18:47:57 +00:00
|
|
|
import {
|
|
|
|
getAToken,
|
|
|
|
getMintableErc20,
|
|
|
|
getStableDebtToken,
|
|
|
|
getVariableDebtToken,
|
|
|
|
} from '../../helpers/contracts-getters';
|
2020-08-21 10:38:08 +00:00
|
|
|
import {MAX_UINT_AMOUNT, ONE_YEAR} from '../../helpers/constants';
|
|
|
|
import {SignerWithAddress, TestEnv} from './make-suite';
|
2020-11-05 12:44:20 +00:00
|
|
|
import {DRE, increaseTime, timeLatest, waitForTx} from '../../helpers/misc-utils';
|
2020-06-30 12:09:28 +00:00
|
|
|
|
|
|
|
import chai from 'chai';
|
|
|
|
import {ReserveData, UserReserveData} from './utils/interfaces';
|
2020-08-19 12:23:41 +00:00
|
|
|
import {ContractReceipt} from 'ethers';
|
2020-06-30 12:09:28 +00:00
|
|
|
import {AToken} from '../../types/AToken';
|
2020-08-21 10:38:08 +00:00
|
|
|
import {RateMode, tEthereumAddress} from '../../helpers/types';
|
2020-06-12 20:12:53 +00:00
|
|
|
|
|
|
|
const {expect} = chai;
|
|
|
|
|
|
|
|
const almostEqualOrEqual = function (
|
|
|
|
this: any,
|
|
|
|
expected: ReserveData | UserReserveData,
|
|
|
|
actual: ReserveData | UserReserveData
|
|
|
|
) {
|
|
|
|
const keys = Object.keys(actual);
|
|
|
|
|
|
|
|
keys.forEach((key) => {
|
|
|
|
if (
|
2020-06-30 12:09:28 +00:00
|
|
|
key === 'lastUpdateTimestamp' ||
|
|
|
|
key === 'marketStableRate' ||
|
|
|
|
key === 'symbol' ||
|
|
|
|
key === 'aTokenAddress' ||
|
2020-09-21 13:27:53 +00:00
|
|
|
key === 'decimals' ||
|
|
|
|
key === 'totalStableDebtLastUpdated'
|
2020-06-12 20:12:53 +00:00
|
|
|
) {
|
|
|
|
// skipping consistency check on accessory data
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-06-30 12:09:28 +00:00
|
|
|
this.assert(actual[key] != undefined, `Property ${key} is undefined in the actual data`);
|
|
|
|
expect(expected[key] != undefined, `Property ${key} is undefined in the expected data`);
|
2020-06-12 20:12:53 +00:00
|
|
|
|
2020-09-09 17:43:41 +00:00
|
|
|
if (expected[key] == null || actual[key] == null) {
|
2020-09-09 08:44:34 +00:00
|
|
|
console.log('Found a undefined value for Key ', key, ' value ', expected[key], actual[key]);
|
|
|
|
}
|
|
|
|
|
2020-06-12 20:12:53 +00:00
|
|
|
if (actual[key] instanceof BigNumber) {
|
2020-06-30 12:09:28 +00:00
|
|
|
const actualValue = (<BigNumber>actual[key]).decimalPlaces(0, BigNumber.ROUND_DOWN);
|
|
|
|
const expectedValue = (<BigNumber>expected[key]).decimalPlaces(0, BigNumber.ROUND_DOWN);
|
2020-09-14 17:59:00 +00:00
|
|
|
|
2020-06-12 20:12:53 +00:00
|
|
|
this.assert(
|
|
|
|
actualValue.eq(expectedValue) ||
|
|
|
|
actualValue.plus(1).eq(expectedValue) ||
|
|
|
|
actualValue.eq(expectedValue.plus(1)) ||
|
|
|
|
actualValue.plus(2).eq(expectedValue) ||
|
|
|
|
actualValue.eq(expectedValue.plus(2)) ||
|
|
|
|
actualValue.plus(3).eq(expectedValue) ||
|
|
|
|
actualValue.eq(expectedValue.plus(3)),
|
|
|
|
`expected #{act} to be almost equal or equal #{exp} for property ${key}`,
|
|
|
|
`expected #{act} to be almost equal or equal #{exp} for property ${key}`,
|
|
|
|
expectedValue.toFixed(0),
|
|
|
|
actualValue.toFixed(0)
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
this.assert(
|
|
|
|
actual[key] !== null &&
|
|
|
|
expected[key] !== null &&
|
|
|
|
actual[key].toString() === expected[key].toString(),
|
|
|
|
`expected #{act} to be equal #{exp} for property ${key}`,
|
|
|
|
`expected #{act} to be equal #{exp} for property ${key}`,
|
|
|
|
expected[key],
|
|
|
|
actual[key]
|
|
|
|
);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
chai.use(function (chai: any, utils: any) {
|
2020-06-30 12:09:28 +00:00
|
|
|
chai.Assertion.overwriteMethod('almostEqualOrEqual', function (original: any) {
|
2020-06-12 20:12:53 +00:00
|
|
|
return function (this: any, expected: ReserveData | UserReserveData) {
|
|
|
|
const actual = (expected as ReserveData)
|
|
|
|
? <ReserveData>this._obj
|
|
|
|
: <UserReserveData>this._obj;
|
|
|
|
|
|
|
|
almostEqualOrEqual.apply(this, [expected, actual]);
|
|
|
|
};
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
interface ActionsConfig {
|
|
|
|
skipIntegrityCheck: boolean;
|
|
|
|
}
|
|
|
|
|
|
|
|
export const configuration: ActionsConfig = <ActionsConfig>{};
|
|
|
|
|
2020-06-30 12:09:28 +00:00
|
|
|
export const mint = async (reserveSymbol: string, amount: string, user: SignerWithAddress) => {
|
2020-06-12 20:12:53 +00:00
|
|
|
const reserve = await getReserveAddressFromSymbol(reserveSymbol);
|
|
|
|
|
|
|
|
const token = await getMintableErc20(reserve);
|
|
|
|
|
|
|
|
await waitForTx(
|
2020-06-30 12:09:28 +00:00
|
|
|
await token.connect(user.signer).mint(await convertToCurrencyDecimals(reserve, amount))
|
2020-06-12 20:12:53 +00:00
|
|
|
);
|
|
|
|
};
|
|
|
|
|
2020-06-30 12:09:28 +00:00
|
|
|
export const approve = async (reserveSymbol: string, user: SignerWithAddress, testEnv: TestEnv) => {
|
2020-06-20 23:40:03 +00:00
|
|
|
const {pool} = testEnv;
|
2020-06-12 20:12:53 +00:00
|
|
|
const reserve = await getReserveAddressFromSymbol(reserveSymbol);
|
|
|
|
|
|
|
|
const token = await getMintableErc20(reserve);
|
|
|
|
|
2020-06-30 12:09:28 +00:00
|
|
|
await token.connect(user.signer).approve(pool.address, '100000000000000000000000000000');
|
2020-06-12 20:12:53 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
export const deposit = async (
|
|
|
|
reserveSymbol: string,
|
|
|
|
amount: string,
|
2020-09-09 10:47:27 +00:00
|
|
|
sender: SignerWithAddress,
|
|
|
|
onBehalfOf: tEthereumAddress,
|
2020-06-12 20:12:53 +00:00
|
|
|
sendValue: string,
|
|
|
|
expectedResult: string,
|
|
|
|
testEnv: TestEnv,
|
|
|
|
revertMessage?: string
|
|
|
|
) => {
|
|
|
|
const {pool} = testEnv;
|
|
|
|
|
|
|
|
const reserve = await getReserveAddressFromSymbol(reserveSymbol);
|
|
|
|
|
|
|
|
const amountToDeposit = await convertToCurrencyDecimals(reserve, amount);
|
|
|
|
|
|
|
|
const txOptions: any = {};
|
|
|
|
|
2020-06-30 12:09:28 +00:00
|
|
|
const {reserveData: reserveDataBefore, userData: userDataBefore} = await getContractsData(
|
|
|
|
reserve,
|
2020-09-09 10:47:27 +00:00
|
|
|
onBehalfOf,
|
|
|
|
testEnv,
|
|
|
|
sender.address
|
2020-06-30 12:09:28 +00:00
|
|
|
);
|
2020-06-12 20:12:53 +00:00
|
|
|
|
2020-08-13 11:06:23 +00:00
|
|
|
if (sendValue) {
|
2020-08-21 10:38:08 +00:00
|
|
|
txOptions.value = await convertToCurrencyDecimals(reserve, sendValue);
|
2020-06-12 20:12:53 +00:00
|
|
|
}
|
2020-06-30 12:09:28 +00:00
|
|
|
if (expectedResult === 'success') {
|
2020-06-12 20:12:53 +00:00
|
|
|
const txResult = await waitForTx(
|
2020-09-09 10:47:27 +00:00
|
|
|
await pool
|
|
|
|
.connect(sender.signer)
|
|
|
|
.deposit(reserve, amountToDeposit, onBehalfOf, '0', txOptions)
|
2020-06-12 20:12:53 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
const {
|
|
|
|
reserveData: reserveDataAfter,
|
|
|
|
userData: userDataAfter,
|
|
|
|
timestamp,
|
2020-09-09 10:47:27 +00:00
|
|
|
} = await getContractsData(reserve, onBehalfOf, testEnv, sender.address);
|
2020-06-12 20:12:53 +00:00
|
|
|
|
|
|
|
const {txCost, txTimestamp} = await getTxCostAndTimestamp(txResult);
|
|
|
|
|
|
|
|
const expectedReserveData = calcExpectedReserveDataAfterDeposit(
|
|
|
|
amountToDeposit.toString(),
|
|
|
|
reserveDataBefore,
|
|
|
|
txTimestamp
|
|
|
|
);
|
|
|
|
|
|
|
|
const expectedUserReserveData = calcExpectedUserDataAfterDeposit(
|
|
|
|
amountToDeposit.toString(),
|
|
|
|
reserveDataBefore,
|
|
|
|
expectedReserveData,
|
|
|
|
userDataBefore,
|
|
|
|
txTimestamp,
|
|
|
|
timestamp,
|
|
|
|
txCost
|
|
|
|
);
|
|
|
|
|
|
|
|
expectEqual(reserveDataAfter, expectedReserveData);
|
|
|
|
expectEqual(userDataAfter, expectedUserReserveData);
|
|
|
|
|
|
|
|
// truffleAssert.eventEmitted(txResult, "Deposit", (ev: any) => {
|
|
|
|
// const {_reserve, _user, _amount} = ev;
|
|
|
|
// return (
|
|
|
|
// _reserve === reserve &&
|
|
|
|
// _user === user &&
|
|
|
|
// new BigNumber(_amount).isEqualTo(new BigNumber(amountToDeposit))
|
|
|
|
// );
|
|
|
|
// });
|
2020-06-30 12:09:28 +00:00
|
|
|
} else if (expectedResult === 'revert') {
|
2020-06-12 20:12:53 +00:00
|
|
|
await expect(
|
2020-09-09 10:47:27 +00:00
|
|
|
pool.connect(sender.signer).deposit(reserve, amountToDeposit, onBehalfOf, '0', txOptions),
|
2020-06-12 20:12:53 +00:00
|
|
|
revertMessage
|
|
|
|
).to.be.reverted;
|
|
|
|
}
|
|
|
|
};
|
2020-06-08 12:03:40 +00:00
|
|
|
|
2020-08-19 10:56:39 +00:00
|
|
|
export const withdraw = async (
|
2020-06-13 09:12:49 +00:00
|
|
|
reserveSymbol: string,
|
|
|
|
amount: string,
|
|
|
|
user: SignerWithAddress,
|
|
|
|
expectedResult: string,
|
|
|
|
testEnv: TestEnv,
|
|
|
|
revertMessage?: string
|
|
|
|
) => {
|
2020-08-19 10:56:39 +00:00
|
|
|
const {pool} = testEnv;
|
|
|
|
|
2020-06-13 09:12:49 +00:00
|
|
|
const {
|
|
|
|
aTokenInstance,
|
|
|
|
reserve,
|
|
|
|
userData: userDataBefore,
|
|
|
|
reserveData: reserveDataBefore,
|
|
|
|
} = await getDataBeforeAction(reserveSymbol, user.address, testEnv);
|
|
|
|
|
2020-08-19 10:56:39 +00:00
|
|
|
let amountToWithdraw = '0';
|
2020-06-30 12:09:28 +00:00
|
|
|
|
|
|
|
if (amount !== '-1') {
|
2020-08-19 10:56:39 +00:00
|
|
|
amountToWithdraw = (await convertToCurrencyDecimals(reserve, amount)).toString();
|
2020-06-13 09:12:49 +00:00
|
|
|
} else {
|
2020-08-19 10:56:39 +00:00
|
|
|
amountToWithdraw = MAX_UINT_AMOUNT;
|
2020-06-13 09:12:49 +00:00
|
|
|
}
|
|
|
|
|
2020-06-30 12:09:28 +00:00
|
|
|
if (expectedResult === 'success') {
|
2020-06-13 09:12:49 +00:00
|
|
|
const txResult = await waitForTx(
|
2020-10-30 11:38:41 +00:00
|
|
|
await pool.connect(user.signer).withdraw(reserve, amountToWithdraw, user.address)
|
2020-06-13 09:12:49 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
const {
|
|
|
|
reserveData: reserveDataAfter,
|
|
|
|
userData: userDataAfter,
|
|
|
|
timestamp,
|
|
|
|
} = await getContractsData(reserve, user.address, testEnv);
|
|
|
|
|
|
|
|
const {txCost, txTimestamp} = await getTxCostAndTimestamp(txResult);
|
|
|
|
|
2020-08-19 10:56:39 +00:00
|
|
|
const expectedReserveData = calcExpectedReserveDataAfterWithdraw(
|
|
|
|
amountToWithdraw,
|
2020-06-13 09:12:49 +00:00
|
|
|
reserveDataBefore,
|
|
|
|
userDataBefore,
|
|
|
|
txTimestamp
|
|
|
|
);
|
|
|
|
|
2020-08-19 10:56:39 +00:00
|
|
|
const expectedUserData = calcExpectedUserDataAfterWithdraw(
|
|
|
|
amountToWithdraw,
|
2020-06-13 09:12:49 +00:00
|
|
|
reserveDataBefore,
|
|
|
|
expectedReserveData,
|
|
|
|
userDataBefore,
|
|
|
|
txTimestamp,
|
|
|
|
timestamp,
|
|
|
|
txCost
|
|
|
|
);
|
|
|
|
|
|
|
|
expectEqual(reserveDataAfter, expectedReserveData);
|
|
|
|
expectEqual(userDataAfter, expectedUserData);
|
|
|
|
|
|
|
|
// truffleAssert.eventEmitted(txResult, "Redeem", (ev: any) => {
|
|
|
|
// const {_from, _value} = ev;
|
|
|
|
// return (
|
|
|
|
// _from === user && new BigNumber(_value).isEqualTo(actualAmountRedeemed)
|
|
|
|
// );
|
|
|
|
// });
|
2020-06-30 12:09:28 +00:00
|
|
|
} else if (expectedResult === 'revert') {
|
2020-10-30 11:38:41 +00:00
|
|
|
await expect(
|
|
|
|
pool.connect(user.signer).withdraw(reserve, amountToWithdraw, user.address),
|
|
|
|
revertMessage
|
|
|
|
).to.be.reverted;
|
2020-06-13 09:12:49 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-09-09 12:33:05 +00:00
|
|
|
export const delegateBorrowAllowance = async (
|
2020-11-03 18:47:57 +00:00
|
|
|
reserve: string,
|
|
|
|
amount: string,
|
|
|
|
interestRateMode: string,
|
2020-09-09 12:33:05 +00:00
|
|
|
user: SignerWithAddress,
|
|
|
|
receiver: tEthereumAddress,
|
2020-09-14 12:41:44 +00:00
|
|
|
expectedResult: string,
|
|
|
|
testEnv: TestEnv,
|
|
|
|
revertMessage?: string
|
2020-09-09 12:33:05 +00:00
|
|
|
) => {
|
|
|
|
const {pool} = testEnv;
|
|
|
|
|
2020-11-03 18:47:57 +00:00
|
|
|
const reserveAddress: tEthereumAddress = await getReserveAddressFromSymbol(reserve);
|
|
|
|
|
|
|
|
const amountToDelegate: string = await (
|
|
|
|
await convertToCurrencyDecimals(reserveAddress, amount)
|
|
|
|
).toString();
|
2020-09-09 12:33:05 +00:00
|
|
|
|
2020-11-03 18:47:57 +00:00
|
|
|
const reserveData = await pool.getReserveData(reserveAddress);
|
|
|
|
|
|
|
|
const debtToken =
|
2020-11-04 10:12:26 +00:00
|
|
|
interestRateMode === '1'
|
2020-11-03 18:47:57 +00:00
|
|
|
? await getStableDebtToken(reserveData.stableDebtTokenAddress)
|
|
|
|
: await getVariableDebtToken(reserveData.variableDebtTokenAddress);
|
|
|
|
|
|
|
|
const delegateAllowancePromise = debtToken
|
2020-09-09 12:33:05 +00:00
|
|
|
.connect(user.signer)
|
2020-11-03 18:47:57 +00:00
|
|
|
.approveDelegation(receiver, amountToDelegate);
|
|
|
|
|
2020-11-04 10:12:26 +00:00
|
|
|
if (expectedResult === 'revert' && revertMessage) {
|
|
|
|
await expect(delegateAllowancePromise, revertMessage).to.be.revertedWith(revertMessage);
|
2020-09-14 12:41:44 +00:00
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
await delegateAllowancePromise;
|
2020-11-03 18:47:57 +00:00
|
|
|
const allowance = await debtToken.borrowAllowance(user.address, receiver);
|
|
|
|
expect(allowance.toString()).to.be.equal(
|
|
|
|
amountToDelegate,
|
2020-11-04 10:12:26 +00:00
|
|
|
'borrowAllowance is set incorrectly'
|
2020-11-03 18:47:57 +00:00
|
|
|
);
|
2020-09-14 12:41:44 +00:00
|
|
|
}
|
2020-09-09 12:33:05 +00:00
|
|
|
};
|
|
|
|
|
2020-06-13 09:12:49 +00:00
|
|
|
export const borrow = async (
|
|
|
|
reserveSymbol: string,
|
|
|
|
amount: string,
|
|
|
|
interestRateMode: string,
|
|
|
|
user: SignerWithAddress,
|
2020-09-09 12:33:05 +00:00
|
|
|
onBehalfOf: tEthereumAddress,
|
2020-06-13 09:12:49 +00:00
|
|
|
timeTravel: string,
|
|
|
|
expectedResult: string,
|
|
|
|
testEnv: TestEnv,
|
|
|
|
revertMessage?: string
|
|
|
|
) => {
|
|
|
|
const {pool} = testEnv;
|
|
|
|
|
|
|
|
const reserve = await getReserveAddressFromSymbol(reserveSymbol);
|
|
|
|
|
2020-06-30 12:09:28 +00:00
|
|
|
const {reserveData: reserveDataBefore, userData: userDataBefore} = await getContractsData(
|
|
|
|
reserve,
|
2020-09-09 12:33:05 +00:00
|
|
|
onBehalfOf,
|
|
|
|
testEnv,
|
|
|
|
user.address
|
2020-06-30 12:09:28 +00:00
|
|
|
);
|
2020-06-13 09:12:49 +00:00
|
|
|
|
|
|
|
const amountToBorrow = await convertToCurrencyDecimals(reserve, amount);
|
|
|
|
|
2020-06-30 12:09:28 +00:00
|
|
|
if (expectedResult === 'success') {
|
2020-06-13 09:12:49 +00:00
|
|
|
const txResult = await waitForTx(
|
2020-09-09 12:33:05 +00:00
|
|
|
await pool
|
|
|
|
.connect(user.signer)
|
|
|
|
.borrow(reserve, amountToBorrow, interestRateMode, '0', onBehalfOf)
|
2020-06-13 09:12:49 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
const {txCost, txTimestamp} = await getTxCostAndTimestamp(txResult);
|
|
|
|
|
|
|
|
if (timeTravel) {
|
2020-06-30 12:09:28 +00:00
|
|
|
const secondsToTravel = new BigNumber(timeTravel).multipliedBy(ONE_YEAR).div(365).toNumber();
|
2020-06-13 09:12:49 +00:00
|
|
|
|
|
|
|
await increaseTime(secondsToTravel);
|
|
|
|
}
|
|
|
|
|
|
|
|
const {
|
|
|
|
reserveData: reserveDataAfter,
|
|
|
|
userData: userDataAfter,
|
|
|
|
timestamp,
|
2020-09-09 12:33:05 +00:00
|
|
|
} = await getContractsData(reserve, onBehalfOf, testEnv, user.address);
|
2020-06-13 09:12:49 +00:00
|
|
|
|
|
|
|
const expectedReserveData = calcExpectedReserveDataAfterBorrow(
|
|
|
|
amountToBorrow.toString(),
|
|
|
|
interestRateMode,
|
|
|
|
reserveDataBefore,
|
|
|
|
userDataBefore,
|
|
|
|
txTimestamp,
|
|
|
|
timestamp
|
|
|
|
);
|
|
|
|
|
|
|
|
const expectedUserData = calcExpectedUserDataAfterBorrow(
|
|
|
|
amountToBorrow.toString(),
|
|
|
|
interestRateMode,
|
|
|
|
reserveDataBefore,
|
|
|
|
expectedReserveData,
|
|
|
|
userDataBefore,
|
|
|
|
txTimestamp,
|
2020-09-21 13:35:22 +00:00
|
|
|
timestamp
|
2020-06-13 09:12:49 +00:00
|
|
|
);
|
2020-07-07 10:07:31 +00:00
|
|
|
|
2020-06-13 09:12:49 +00:00
|
|
|
expectEqual(reserveDataAfter, expectedReserveData);
|
|
|
|
expectEqual(userDataAfter, expectedUserData);
|
|
|
|
|
|
|
|
// truffleAssert.eventEmitted(txResult, "Borrow", (ev: any) => {
|
|
|
|
// const {
|
|
|
|
// _reserve,
|
|
|
|
// _user,
|
|
|
|
// _amount,
|
|
|
|
// _borrowRateMode,
|
|
|
|
// _borrowRate,
|
|
|
|
// _originationFee,
|
|
|
|
// } = ev;
|
|
|
|
// return (
|
|
|
|
// _reserve.toLowerCase() === reserve.toLowerCase() &&
|
|
|
|
// _user.toLowerCase() === user.toLowerCase() &&
|
|
|
|
// new BigNumber(_amount).eq(amountToBorrow) &&
|
|
|
|
// new BigNumber(_borrowRateMode).eq(expectedUserData.borrowRateMode) &&
|
|
|
|
// new BigNumber(_borrowRate).eq(expectedUserData.borrowRate) &&
|
|
|
|
// new BigNumber(_originationFee).eq(
|
|
|
|
// expectedUserData.originationFee.minus(userDataBefore.originationFee)
|
|
|
|
// )
|
|
|
|
// );
|
|
|
|
// });
|
2020-06-30 12:09:28 +00:00
|
|
|
} else if (expectedResult === 'revert') {
|
2020-06-13 09:12:49 +00:00
|
|
|
await expect(
|
2020-09-09 12:33:05 +00:00
|
|
|
pool.connect(user.signer).borrow(reserve, amountToBorrow, interestRateMode, '0', onBehalfOf),
|
2020-06-13 09:12:49 +00:00
|
|
|
revertMessage
|
|
|
|
).to.be.reverted;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
export const repay = async (
|
|
|
|
reserveSymbol: string,
|
|
|
|
amount: string,
|
2020-06-30 12:09:28 +00:00
|
|
|
rateMode: string,
|
2020-06-13 09:12:49 +00:00
|
|
|
user: SignerWithAddress,
|
|
|
|
onBehalfOf: SignerWithAddress,
|
|
|
|
sendValue: string,
|
|
|
|
expectedResult: string,
|
|
|
|
testEnv: TestEnv,
|
|
|
|
revertMessage?: string
|
|
|
|
) => {
|
|
|
|
const {pool} = testEnv;
|
|
|
|
const reserve = await getReserveAddressFromSymbol(reserveSymbol);
|
|
|
|
|
2020-06-30 12:09:28 +00:00
|
|
|
const {reserveData: reserveDataBefore, userData: userDataBefore} = await getContractsData(
|
|
|
|
reserve,
|
|
|
|
onBehalfOf.address,
|
|
|
|
testEnv
|
|
|
|
);
|
2020-06-13 09:12:49 +00:00
|
|
|
|
2020-06-30 12:09:28 +00:00
|
|
|
let amountToRepay = '0';
|
2020-06-13 09:12:49 +00:00
|
|
|
|
2020-06-30 12:09:28 +00:00
|
|
|
if (amount !== '-1') {
|
|
|
|
amountToRepay = (await convertToCurrencyDecimals(reserve, amount)).toString();
|
2020-06-13 09:12:49 +00:00
|
|
|
} else {
|
2020-08-19 12:23:41 +00:00
|
|
|
amountToRepay = MAX_UINT_AMOUNT;
|
2020-06-13 09:12:49 +00:00
|
|
|
}
|
2020-06-30 12:09:28 +00:00
|
|
|
amountToRepay = '0x' + new BigNumber(amountToRepay).toString(16);
|
2020-06-13 09:12:49 +00:00
|
|
|
|
|
|
|
const txOptions: any = {};
|
|
|
|
|
2020-08-13 11:06:23 +00:00
|
|
|
if (sendValue) {
|
|
|
|
const valueToSend = await convertToCurrencyDecimals(reserve, sendValue);
|
|
|
|
txOptions.value = '0x' + new BigNumber(valueToSend.toString()).toString(16);
|
2020-06-13 09:12:49 +00:00
|
|
|
}
|
|
|
|
|
2020-06-30 12:09:28 +00:00
|
|
|
if (expectedResult === 'success') {
|
2020-06-13 09:12:49 +00:00
|
|
|
const txResult = await waitForTx(
|
|
|
|
await pool
|
|
|
|
.connect(user.signer)
|
2020-06-30 12:09:28 +00:00
|
|
|
.repay(reserve, amountToRepay, rateMode, onBehalfOf.address, txOptions)
|
2020-06-13 09:12:49 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
const {txCost, txTimestamp} = await getTxCostAndTimestamp(txResult);
|
|
|
|
|
|
|
|
const {
|
|
|
|
reserveData: reserveDataAfter,
|
|
|
|
userData: userDataAfter,
|
|
|
|
timestamp,
|
|
|
|
} = await getContractsData(reserve, onBehalfOf.address, testEnv);
|
|
|
|
|
|
|
|
const expectedReserveData = calcExpectedReserveDataAfterRepay(
|
|
|
|
amountToRepay,
|
2020-07-03 21:20:02 +00:00
|
|
|
<RateMode>rateMode,
|
2020-06-13 09:12:49 +00:00
|
|
|
reserveDataBefore,
|
|
|
|
userDataBefore,
|
|
|
|
txTimestamp,
|
|
|
|
timestamp
|
|
|
|
);
|
|
|
|
|
|
|
|
const expectedUserData = calcExpectedUserDataAfterRepay(
|
|
|
|
amountToRepay,
|
2020-07-03 21:20:02 +00:00
|
|
|
<RateMode>rateMode,
|
2020-06-13 09:12:49 +00:00
|
|
|
reserveDataBefore,
|
|
|
|
expectedReserveData,
|
|
|
|
userDataBefore,
|
|
|
|
user.address,
|
|
|
|
onBehalfOf.address,
|
|
|
|
txTimestamp,
|
2020-09-21 13:35:22 +00:00
|
|
|
timestamp
|
2020-06-13 09:12:49 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
expectEqual(reserveDataAfter, expectedReserveData);
|
|
|
|
expectEqual(userDataAfter, expectedUserData);
|
|
|
|
|
|
|
|
// truffleAssert.eventEmitted(txResult, "Repay", (ev: any) => {
|
|
|
|
// const {_reserve, _user, _repayer} = ev;
|
|
|
|
|
|
|
|
// return (
|
|
|
|
// _reserve.toLowerCase() === reserve.toLowerCase() &&
|
|
|
|
// _user.toLowerCase() === onBehalfOf.toLowerCase() &&
|
|
|
|
// _repayer.toLowerCase() === user.toLowerCase()
|
|
|
|
// );
|
|
|
|
// });
|
2020-06-30 12:09:28 +00:00
|
|
|
} else if (expectedResult === 'revert') {
|
2020-06-13 09:12:49 +00:00
|
|
|
await expect(
|
2020-07-03 21:20:02 +00:00
|
|
|
pool
|
|
|
|
.connect(user.signer)
|
|
|
|
.repay(reserve, amountToRepay, rateMode, onBehalfOf.address, txOptions),
|
2020-06-13 09:12:49 +00:00
|
|
|
revertMessage
|
|
|
|
).to.be.reverted;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
export const setUseAsCollateral = async (
|
|
|
|
reserveSymbol: string,
|
|
|
|
user: SignerWithAddress,
|
|
|
|
useAsCollateral: string,
|
|
|
|
expectedResult: string,
|
|
|
|
testEnv: TestEnv,
|
|
|
|
revertMessage?: string
|
|
|
|
) => {
|
|
|
|
const {pool} = testEnv;
|
|
|
|
|
|
|
|
const reserve = await getReserveAddressFromSymbol(reserveSymbol);
|
|
|
|
|
2020-06-30 12:09:28 +00:00
|
|
|
const {reserveData: reserveDataBefore, userData: userDataBefore} = await getContractsData(
|
|
|
|
reserve,
|
|
|
|
user.address,
|
|
|
|
testEnv
|
|
|
|
);
|
2020-06-13 09:12:49 +00:00
|
|
|
|
2020-06-30 12:09:28 +00:00
|
|
|
const useAsCollateralBool = useAsCollateral.toLowerCase() === 'true';
|
2020-06-13 09:12:49 +00:00
|
|
|
|
2020-06-30 12:09:28 +00:00
|
|
|
if (expectedResult === 'success') {
|
2020-06-13 09:12:49 +00:00
|
|
|
const txResult = await waitForTx(
|
2020-06-30 12:09:28 +00:00
|
|
|
await pool.connect(user.signer).setUserUseReserveAsCollateral(reserve, useAsCollateralBool)
|
2020-06-13 09:12:49 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
const {txCost} = await getTxCostAndTimestamp(txResult);
|
|
|
|
|
2020-06-30 12:09:28 +00:00
|
|
|
const {userData: userDataAfter} = await getContractsData(reserve, user.address, testEnv);
|
2020-06-13 09:12:49 +00:00
|
|
|
|
|
|
|
const expectedUserData = calcExpectedUserDataAfterSetUseAsCollateral(
|
2020-06-30 12:09:28 +00:00
|
|
|
useAsCollateral.toLocaleLowerCase() === 'true',
|
2020-06-13 09:12:49 +00:00
|
|
|
reserveDataBefore,
|
|
|
|
userDataBefore,
|
|
|
|
txCost
|
|
|
|
);
|
|
|
|
|
|
|
|
expectEqual(userDataAfter, expectedUserData);
|
|
|
|
// if (useAsCollateralBool) {
|
|
|
|
// truffleAssert.eventEmitted(txResult, 'ReserveUsedAsCollateralEnabled', (ev: any) => {
|
|
|
|
// const {_reserve, _user} = ev;
|
|
|
|
// return _reserve === reserve && _user === user;
|
|
|
|
// });
|
|
|
|
// } else {
|
|
|
|
// truffleAssert.eventEmitted(txResult, 'ReserveUsedAsCollateralDisabled', (ev: any) => {
|
|
|
|
// const {_reserve, _user} = ev;
|
|
|
|
// return _reserve === reserve && _user === user;
|
|
|
|
// });
|
|
|
|
// }
|
2020-06-30 12:09:28 +00:00
|
|
|
} else if (expectedResult === 'revert') {
|
2020-06-13 09:12:49 +00:00
|
|
|
await expect(
|
2020-06-30 12:09:28 +00:00
|
|
|
pool.connect(user.signer).setUserUseReserveAsCollateral(reserve, useAsCollateralBool),
|
2020-06-13 09:12:49 +00:00
|
|
|
revertMessage
|
|
|
|
).to.be.reverted;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
export const swapBorrowRateMode = async (
|
|
|
|
reserveSymbol: string,
|
|
|
|
user: SignerWithAddress,
|
2020-07-07 10:07:31 +00:00
|
|
|
rateMode: string,
|
2020-06-13 09:12:49 +00:00
|
|
|
expectedResult: string,
|
|
|
|
testEnv: TestEnv,
|
|
|
|
revertMessage?: string
|
|
|
|
) => {
|
|
|
|
const {pool} = testEnv;
|
|
|
|
|
|
|
|
const reserve = await getReserveAddressFromSymbol(reserveSymbol);
|
|
|
|
|
2020-06-30 12:09:28 +00:00
|
|
|
const {reserveData: reserveDataBefore, userData: userDataBefore} = await getContractsData(
|
|
|
|
reserve,
|
|
|
|
user.address,
|
|
|
|
testEnv
|
|
|
|
);
|
2020-06-13 09:12:49 +00:00
|
|
|
|
2020-06-30 12:09:28 +00:00
|
|
|
if (expectedResult === 'success') {
|
2020-07-13 08:54:08 +00:00
|
|
|
const txResult = await waitForTx(
|
|
|
|
await pool.connect(user.signer).swapBorrowRateMode(reserve, rateMode)
|
|
|
|
);
|
2020-06-13 09:12:49 +00:00
|
|
|
|
|
|
|
const {txCost, txTimestamp} = await getTxCostAndTimestamp(txResult);
|
|
|
|
|
2020-06-30 12:09:28 +00:00
|
|
|
const {reserveData: reserveDataAfter, userData: userDataAfter} = await getContractsData(
|
|
|
|
reserve,
|
|
|
|
user.address,
|
|
|
|
testEnv
|
|
|
|
);
|
2020-06-13 09:12:49 +00:00
|
|
|
|
|
|
|
const expectedReserveData = calcExpectedReserveDataAfterSwapRateMode(
|
|
|
|
reserveDataBefore,
|
|
|
|
userDataBefore,
|
2020-07-07 10:07:31 +00:00
|
|
|
rateMode,
|
2020-06-13 09:12:49 +00:00
|
|
|
txTimestamp
|
|
|
|
);
|
|
|
|
|
|
|
|
const expectedUserData = calcExpectedUserDataAfterSwapRateMode(
|
|
|
|
reserveDataBefore,
|
|
|
|
expectedReserveData,
|
|
|
|
userDataBefore,
|
2020-07-07 10:07:31 +00:00
|
|
|
rateMode,
|
2020-06-13 09:12:49 +00:00
|
|
|
txCost,
|
|
|
|
txTimestamp
|
|
|
|
);
|
|
|
|
|
|
|
|
expectEqual(reserveDataAfter, expectedReserveData);
|
|
|
|
expectEqual(userDataAfter, expectedUserData);
|
|
|
|
|
|
|
|
// truffleAssert.eventEmitted(txResult, "Swap", (ev: any) => {
|
|
|
|
// const {_user, _reserve, _newRateMode, _newRate} = ev;
|
|
|
|
// return (
|
|
|
|
// _user === user &&
|
|
|
|
// _reserve == reserve &&
|
|
|
|
// new BigNumber(_newRateMode).eq(expectedUserData.borrowRateMode) &&
|
|
|
|
// new BigNumber(_newRate).eq(expectedUserData.borrowRate)
|
|
|
|
// );
|
|
|
|
// });
|
2020-06-30 12:09:28 +00:00
|
|
|
} else if (expectedResult === 'revert') {
|
2020-07-13 08:54:08 +00:00
|
|
|
await expect(pool.connect(user.signer).swapBorrowRateMode(reserve, rateMode), revertMessage).to
|
|
|
|
.be.reverted;
|
2020-06-13 09:12:49 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
export const rebalanceStableBorrowRate = async (
|
|
|
|
reserveSymbol: string,
|
|
|
|
user: SignerWithAddress,
|
|
|
|
target: SignerWithAddress,
|
|
|
|
expectedResult: string,
|
|
|
|
testEnv: TestEnv,
|
|
|
|
revertMessage?: string
|
|
|
|
) => {
|
|
|
|
const {pool} = testEnv;
|
|
|
|
|
|
|
|
const reserve = await getReserveAddressFromSymbol(reserveSymbol);
|
|
|
|
|
2020-06-30 12:09:28 +00:00
|
|
|
const {reserveData: reserveDataBefore, userData: userDataBefore} = await getContractsData(
|
|
|
|
reserve,
|
|
|
|
target.address,
|
|
|
|
testEnv
|
|
|
|
);
|
2020-06-13 09:12:49 +00:00
|
|
|
|
2020-06-30 12:09:28 +00:00
|
|
|
if (expectedResult === 'success') {
|
2020-06-13 09:12:49 +00:00
|
|
|
const txResult = await waitForTx(
|
2020-06-30 12:09:28 +00:00
|
|
|
await pool.connect(user.signer).rebalanceStableBorrowRate(reserve, target.address)
|
2020-06-13 09:12:49 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
const {txCost, txTimestamp} = await getTxCostAndTimestamp(txResult);
|
|
|
|
|
2020-06-30 12:09:28 +00:00
|
|
|
const {reserveData: reserveDataAfter, userData: userDataAfter} = await getContractsData(
|
|
|
|
reserve,
|
|
|
|
target.address,
|
|
|
|
testEnv
|
|
|
|
);
|
2020-06-13 09:12:49 +00:00
|
|
|
|
|
|
|
const expectedReserveData = calcExpectedReserveDataAfterStableRateRebalance(
|
|
|
|
reserveDataBefore,
|
|
|
|
userDataBefore,
|
|
|
|
txTimestamp
|
|
|
|
);
|
|
|
|
|
|
|
|
const expectedUserData = calcExpectedUserDataAfterStableRateRebalance(
|
|
|
|
reserveDataBefore,
|
|
|
|
expectedReserveData,
|
|
|
|
userDataBefore,
|
|
|
|
txCost,
|
|
|
|
txTimestamp
|
|
|
|
);
|
|
|
|
|
|
|
|
expectEqual(reserveDataAfter, expectedReserveData);
|
|
|
|
expectEqual(userDataAfter, expectedUserData);
|
|
|
|
|
|
|
|
// truffleAssert.eventEmitted(txResult, 'RebalanceStableBorrowRate', (ev: any) => {
|
|
|
|
// const {_user, _reserve, _newStableRate} = ev;
|
|
|
|
// return (
|
|
|
|
// _user.toLowerCase() === target.toLowerCase() &&
|
|
|
|
// _reserve.toLowerCase() === reserve.toLowerCase() &&
|
|
|
|
// new BigNumber(_newStableRate).eq(expectedUserData.borrowRate)
|
|
|
|
// );
|
|
|
|
// });
|
2020-06-30 12:09:28 +00:00
|
|
|
} else if (expectedResult === 'revert') {
|
2020-06-13 09:12:49 +00:00
|
|
|
await expect(
|
2020-06-30 12:09:28 +00:00
|
|
|
pool.connect(user.signer).rebalanceStableBorrowRate(reserve, target.address),
|
2020-06-13 09:12:49 +00:00
|
|
|
revertMessage
|
|
|
|
).to.be.reverted;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-06-12 20:12:53 +00:00
|
|
|
const expectEqual = (
|
|
|
|
actual: UserReserveData | ReserveData,
|
|
|
|
expected: UserReserveData | ReserveData
|
|
|
|
) => {
|
|
|
|
if (!configuration.skipIntegrityCheck) {
|
|
|
|
// @ts-ignore
|
|
|
|
expect(actual).to.be.almostEqualOrEqual(expected);
|
|
|
|
}
|
|
|
|
};
|
2020-06-08 12:03:40 +00:00
|
|
|
|
2020-06-13 09:12:49 +00:00
|
|
|
interface ActionData {
|
|
|
|
reserve: string;
|
|
|
|
reserveData: ReserveData;
|
|
|
|
userData: UserReserveData;
|
|
|
|
aTokenInstance: AToken;
|
|
|
|
}
|
|
|
|
|
|
|
|
const getDataBeforeAction = async (
|
|
|
|
reserveSymbol: string,
|
|
|
|
user: tEthereumAddress,
|
|
|
|
testEnv: TestEnv
|
|
|
|
): Promise<ActionData> => {
|
|
|
|
const reserve = await getReserveAddressFromSymbol(reserveSymbol);
|
|
|
|
|
2020-06-30 12:09:28 +00:00
|
|
|
const {reserveData, userData} = await getContractsData(reserve, user, testEnv);
|
2020-06-13 09:12:49 +00:00
|
|
|
const aTokenInstance = await getAToken(reserveData.aTokenAddress);
|
|
|
|
return {
|
|
|
|
reserve,
|
|
|
|
reserveData,
|
|
|
|
userData,
|
|
|
|
aTokenInstance,
|
|
|
|
};
|
|
|
|
};
|
2020-06-08 12:03:40 +00:00
|
|
|
|
2020-09-08 10:08:16 +00:00
|
|
|
export const getTxCostAndTimestamp = async (tx: ContractReceipt) => {
|
2020-06-12 20:12:53 +00:00
|
|
|
if (!tx.blockNumber || !tx.transactionHash || !tx.cumulativeGasUsed) {
|
2020-06-30 12:09:28 +00:00
|
|
|
throw new Error('No tx blocknumber');
|
2020-06-12 20:12:53 +00:00
|
|
|
}
|
2020-11-05 12:44:20 +00:00
|
|
|
const txTimestamp = new BigNumber((await DRE.ethers.provider.getBlock(tx.blockNumber)).timestamp);
|
2020-06-12 20:12:53 +00:00
|
|
|
|
2020-11-05 12:44:20 +00:00
|
|
|
const txInfo = await DRE.ethers.provider.getTransaction(tx.transactionHash);
|
2020-06-12 20:12:53 +00:00
|
|
|
const txCost = new BigNumber(tx.cumulativeGasUsed.toString()).multipliedBy(
|
|
|
|
txInfo.gasPrice.toString()
|
|
|
|
);
|
|
|
|
|
|
|
|
return {txCost, txTimestamp};
|
|
|
|
};
|
|
|
|
|
2020-09-10 19:40:26 +00:00
|
|
|
export const getContractsData = async (
|
2020-09-09 10:47:27 +00:00
|
|
|
reserve: string,
|
|
|
|
user: string,
|
|
|
|
testEnv: TestEnv,
|
|
|
|
sender?: string
|
|
|
|
) => {
|
2020-10-12 18:07:17 +00:00
|
|
|
const {pool, helpersContract} = testEnv;
|
2020-09-18 15:56:33 +00:00
|
|
|
|
|
|
|
const [userData, reserveData, timestamp] = await Promise.all([
|
2020-10-12 18:07:17 +00:00
|
|
|
getUserData(pool, helpersContract, reserve, user, sender || user),
|
|
|
|
getReserveData(helpersContract, reserve),
|
2020-09-18 15:56:33 +00:00
|
|
|
timeLatest(),
|
|
|
|
]);
|
2020-06-12 20:12:53 +00:00
|
|
|
|
|
|
|
return {
|
|
|
|
reserveData,
|
|
|
|
userData,
|
|
|
|
timestamp: new BigNumber(timestamp),
|
|
|
|
};
|
|
|
|
};
|