Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add additional Foundry test coverage #322

Merged
merged 60 commits into from
May 10, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
fd73e2d
chore: add Foundry initial test environment mocks
kartojal Feb 14, 2023
7aa567d
chore: remove mint at test
kartojal Feb 14, 2023
63e8085
chore: add tests and borrow fuzz to GhoVariableDebtToken
kartojal Feb 20, 2023
05df7e1
chore: add initial test engine for gho borrow
kartojal Feb 21, 2023
d43701c
chore: add percent calc function
kartojal Feb 22, 2023
55aa0ca
fix: Remove discount lock period mechanism (#293)
miguelmtzinf Feb 20, 2023
ecdbc72
fix: Optimize gho debt balanceof (#297)
miguelmtzinf Feb 20, 2023
b6ad733
fix: Simplify GhoToken.addFacilitator function (#295)
miguelmtzinf Feb 20, 2023
1dc6f09
feat: Add helper contract to manage risk params of GHO reserve (#291)
foodaka Feb 20, 2023
e878746
fix: Remove updateLockDiscountPeriod calls from GhoManager (#298)
miguelmtzinf Feb 20, 2023
1cdea12
chore: initial repay engine
kartojal Feb 27, 2023
a789362
chore: add makefile with coverage html report and ignore mocks, add r…
kartojal Mar 1, 2023
28ffe9a
chore: add 100% coverage for GhoVariableDebtToken contract
kartojal Mar 1, 2023
68d9989
chore: add GhoAToken.sol tests
kartojal Mar 1, 2023
6bc762b
fix: Stop prettier formatting dependencies and cache
Zer0dot Apr 3, 2023
f1e960b
feat: Initial flashminter setup
Zer0dot Apr 12, 2023
4ceddc3
misc: Slight optimisation
Zer0dot Apr 13, 2023
cd82952
test: Add Gho FlashMinter unit tests
Zer0dot Apr 14, 2023
402271b
test: Add flash minter unit tests
Zer0dot Apr 18, 2023
dd0314f
fix: Resolve VSCode import callback issue with forge-std/ds-test
Apr 18, 2023
501c89c
test: Add GhoAToken tests for transfer and self-rescue reverts
Apr 18, 2023
8e25323
fix: exclude foundry-test for hardhat coverage tests
Apr 18, 2023
6c2dbc2
test: Add initial GhoToken unit tests
Apr 20, 2023
3e94649
fix: remove stkAave mocks, replace with BGD repo and update impacted …
Apr 25, 2023
89d1195
Merge branch 'main' into chore/foundry-test-suite
Apr 25, 2023
c17e3ba
fix: resolved error in testUpdateDiscountTokenToZero test
Apr 25, 2023
0457b93
fix: increase node testrunner heap alloc to avoid OOM
Apr 25, 2023
66f3f14
fix: setup stkAave behind proxy
Apr 26, 2023
d319705
test: add GhoOracle unit tests
Apr 26, 2023
888ebb5
test: add GhoDiscountRateStrategy unit/fuzz tests
Apr 26, 2023
caff728
test: add GhoInterestRateStrategy fuzz test
Apr 26, 2023
6f134f0
test: add GhoManager unit tests, mocked PoolConfigurator
Apr 27, 2023
ff332a4
fix: remove unnecessary stopPranks that fail in latest forge
Apr 27, 2023
9551aa7
test: added nonce/domain sep unit tests for GhoAToken
Apr 27, 2023
dc8b27a
test: add GhoStableDebtToken unit tests
Apr 27, 2023
00e2550
feat: add combined coverage from hardhat/foundry
Apr 28, 2023
db4ffae
fix: refactor initial foundry tests
May 1, 2023
4845e84
fix: move MockFlashBorrower to common location
May 1, 2023
68ce5ec
feat: add EmptyDiscountRateStrategy fuzz test
May 1, 2023
53b46c4
feat: add UiGhoDataProvider unit tests
May 1, 2023
f268ccd
feat: complete GhoToken unit tests
May 1, 2023
c3faa88
feat: complete GhoVariableDebtToken unit tests
May 1, 2023
95d3625
feat: add last unit test for GhoVariableDebtToken
May 2, 2023
25cefe8
fix: update ordering in constant/event test files
May 2, 2023
524fb1b
Merge pull request #323 from aave/feat/320-unified-coverage-gen
May 4, 2023
e4c6aa5
Merge pull request #324 from aave/fix/321-refactor-foundry-tests
May 4, 2023
5fcdf00
fix: remove unnecessary prank on proxy init
May 4, 2023
d34d73a
fix: naming of fuzz tests to be more descriptive
May 5, 2023
ae957d0
Merge branch 'main' into feat/319-additional-foundry-test-coverage
miguelmtzinf May 10, 2023
e447d7d
fix: re-remove old tests that got re-merged
May 10, 2023
76f1b30
fix: Remove hardhat unitTests folder
miguelmtzinf May 10, 2023
432886b
fix: Fix constants value of tests
miguelmtzinf May 10, 2023
81f3e4e
test: Add couple of test cases
miguelmtzinf May 10, 2023
e410417
test: Rename test titles
miguelmtzinf May 10, 2023
e8612b7
fix: Rename EmptyDiscountRateStrategy to ZeroDiscountRateStrategy
miguelmtzinf May 10, 2023
2eb10cf
fix: Remove unneeded import
miguelmtzinf May 10, 2023
5c8a258
feat: add genhtml back to combined coverage
May 10, 2023
298153f
fix: add error messages on test reverts
May 10, 2023
b814e60
fix: Fix package scripts
miguelmtzinf May 10, 2023
230a761
fix: Fix deploy script of GhoStableDebtToken
miguelmtzinf May 10, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
chore: add tests and borrow fuzz to GhoVariableDebtToken
  • Loading branch information
kartojal committed Feb 20, 2023
commit 63e80859531bc973f0b08c03afa9a736139611bc
24 changes: 21 additions & 3 deletions src/contracts/foundry-test/TestEnv.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,23 +20,35 @@ import {IAaveIncentivesController} from '@aave/core-v3/contracts/interfaces/IAav

contract TestEnv is Test {
address[3] users = [
0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266,
0x70997970C51812dc3A010C7d01b50e0d17dc79C8,
0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC
0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC,
0x90F79bf6EB2c4f870365E785982E1f101E93b906
];
address faucet = 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266;
GhoToken GHO_TOKEN;
ERC20 AAVE_TOKEN;
IStkAave STK_TOKEN;
MockedPool POOL;
MockedAclManager ACL_MANAGER;
WETH9Mock WETH;
GhoVariableDebtToken GHO_DEBT_TOKEN;
GhoAToken GHO_ATOKEN;

// Events to listen
event Transfer(address indexed from, address indexed to, uint256 value);
event Mint(
address indexed caller,
address indexed onBehalfOf,
uint256 value,
uint256 balanceIncrease,
uint256 index
);

function setupGho() public {
bytes memory empty;
ACL_MANAGER = new MockedAclManager();
POOL = new MockedPool(
IPoolAddressesProvider(address(new MockedProvider(address(new MockedAclManager()))))
IPoolAddressesProvider(address(new MockedProvider(address(ACL_MANAGER))))
);
GHO_TOKEN = new GhoToken();
AAVE_TOKEN = new ERC20('AAVE', 'AAVE');
Expand Down Expand Up @@ -103,6 +115,12 @@ contract TestEnv is Test {
IGhoToken(ghoToken).addFacilitator(faucet, facilitatorData);
}

function ghoFaucet(address to, uint256 amount) public {
vm.stopPrank();
vm.prank(faucet);
GHO_TOKEN.mint(to, amount);
}

constructor() {
setupGho();
}
Expand Down
251 changes: 245 additions & 6 deletions src/contracts/foundry-test/TestGhoVariableDebtToken.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,90 @@ import 'forge-std/Test.sol';
import 'forge-std/console.sol';
import './TestEnv.sol';
import {IPool} from '@aave/core-v3/contracts/interfaces/IPool.sol';
import {Errors} from '@aave/core-v3/contracts/protocol/libraries/helpers/Errors.sol';
import {DebtUtils} from './libraries/DebtUtils.sol';

contract TestGhoVariableDebtToken is Test, TestEnv {
address public alice;
address public bob;
address public carlos;
uint256 borrowAmount = 200e18;

function setUp() public {
alice = users[1];
alice = users[0];
bob = users[1];
carlos = users[2];
}

function testBorrow() public {
function testConstructor() public {
GhoVariableDebtToken debtToken = new GhoVariableDebtToken(IPool(address(POOL)));
assertEq(debtToken.name(), 'GHO_VARIABLE_DEBT_TOKEN_IMPL', 'Wrong default ERC20 name');
assertEq(debtToken.symbol(), 'GHO_VARIABLE_DEBT_TOKEN_IMPL', 'Wrong default ERC20 symbol');
assertEq(debtToken.decimals(), 0, 'Wrong default ERC20 decimals');
}

function testInitialize() public {
GhoVariableDebtToken debtToken = new GhoVariableDebtToken(IPool(address(POOL)));
string memory tokenName = 'GHO Variable Debt';
string memory tokenSymbol = 'GhoVarDebt';
bytes memory empty;
debtToken.initialize(
IPool(address(POOL)),
address(GHO_TOKEN),
IAaveIncentivesController(address(0)),
18,
tokenName,
tokenSymbol,
empty
);

assertEq(debtToken.name(), tokenName, 'Wrong initialized name');
assertEq(debtToken.symbol(), tokenSymbol, 'Wrong initialized symbol');
assertEq(debtToken.decimals(), 18, 'Wrong ERC20 decimals');
}

function testReInitRevert() public {
string memory tokenName = 'GHO Variable Debt';
string memory tokenSymbol = 'GhoVarDebt';
bytes memory empty;

vm.expectRevert(bytes('Contract instance has already been initialized'));
GHO_DEBT_TOKEN.initialize(
IPool(address(POOL)),
address(GHO_TOKEN),
IAaveIncentivesController(address(0)),
18,
tokenName,
tokenSymbol,
empty
);
}

function testBorrow(uint256 fuzzAmount) public {
vm.assume(fuzzAmount < 100000000000000000000000001);
vm.assume(fuzzAmount > 0);
vm.startPrank(alice);

POOL.borrow(address(GHO_TOKEN), borrowAmount, 2, 0, alice);
vm.expectEmit(true, true, true, true, address(GHO_DEBT_TOKEN));
emit Transfer(address(0), alice, fuzzAmount);
vm.expectEmit(true, true, true, true, address(GHO_DEBT_TOKEN));
emit Mint(alice, alice, fuzzAmount, 0, 1e27);

// Action
POOL.borrow(address(GHO_TOKEN), fuzzAmount, 2, 0, alice);

assertEq(GHO_TOKEN.balanceOf(alice), borrowAmount, 'Gho amount doest not match borrow');
assertEq(GHO_TOKEN.totalSupply(), borrowAmount, 'Gho total supply does not match borrow');
assertEq(GHO_TOKEN.balanceOf(alice), fuzzAmount, 'Gho amount doest not match borrow');
assertEq(GHO_TOKEN.totalSupply(), fuzzAmount, 'Gho total supply does not match borrow');
assertEq(
GHO_DEBT_TOKEN.scaledBalanceOf(alice),
borrowAmount,
fuzzAmount,
'Gho debt token does not match borrow'
);
assertEq(
GHO_DEBT_TOKEN.getBalanceFromInterest(alice),
0,
'Accumulated interest should be zero'
);
}

function testPartialRepay() public {
Expand All @@ -52,5 +115,181 @@ contract TestGhoVariableDebtToken is Test, TestEnv {
ghoTotalSupply - partialRepayAmount,
'GHO Total Supply should have decreased the repay amount'
);
assertEq(
GHO_DEBT_TOKEN.getBalanceFromInterest(alice),
0,
'Accumulated interest should be zero'
);
}

function testFullRepay() public {
vm.prank(alice);

// Perform borrow
POOL.borrow(address(GHO_TOKEN), borrowAmount, 2, 0, alice);

vm.warp(block.timestamp + 2628000);

uint256 allDebt = GHO_DEBT_TOKEN.balanceOf(alice);

ghoFaucet(alice, 1e18);

uint256 balanceBeforeRepay = GHO_TOKEN.balanceOf(alice);
uint256 ghoTotalSupply = GHO_TOKEN.totalSupply();
uint256 interest = allDebt - borrowAmount;

(uint256 computedInterest, , ) = DebtUtils.computeDebt(
1e27,
POOL.getReserveNormalizedVariableDebt(address(GHO_TOKEN)),
GHO_DEBT_TOKEN.scaledBalanceOf(alice),
0,
0
);

// Perform approve and repay
vm.startPrank(alice);
GHO_TOKEN.approve(address(POOL), type(uint256).max);
POOL.repay(address(GHO_TOKEN), allDebt, 2, alice);

assertEq(
GHO_TOKEN.balanceOf(alice),
balanceBeforeRepay - allDebt,
'Alice GHO balance should have decreasaed the debt amount'
);
assertEq(GHO_DEBT_TOKEN.balanceOf(alice), 0, 'Alice Variable Debt GHO balance should be zero');
assertEq(
GHO_TOKEN.totalSupply(),
ghoTotalSupply - allDebt + interest,
'GHO Total Supply should have decreased the repay amount'
);
assertEq(
GHO_DEBT_TOKEN.getBalanceFromInterest(alice),
0,
'Accumulated interest should be reset to zero'
);
assertEq(interest, computedInterest, 'Computed interest should match interest');
}

function testTransferRevert() public {
vm.startPrank(alice);
vm.expectRevert(bytes(Errors.OPERATION_NOT_SUPPORTED));
GHO_DEBT_TOKEN.transfer(carlos, 1);
}

function testTransferFromRevert() public {
vm.startPrank(alice);
vm.expectRevert(bytes(Errors.OPERATION_NOT_SUPPORTED));
GHO_DEBT_TOKEN.transferFrom(alice, carlos, 1);
}

function testApproveRevert() public {
vm.startPrank(alice);
vm.expectRevert(bytes(Errors.OPERATION_NOT_SUPPORTED));
GHO_DEBT_TOKEN.approve(carlos, 1);
}

function testIncreaseAllowanceRevert() public {
vm.startPrank(alice);
vm.expectRevert(bytes(Errors.OPERATION_NOT_SUPPORTED));
GHO_DEBT_TOKEN.increaseAllowance(carlos, 1);
}

function testDecreaseAllowanceRevert() public {
vm.startPrank(alice);
vm.expectRevert(bytes(Errors.OPERATION_NOT_SUPPORTED));
GHO_DEBT_TOKEN.decreaseAllowance(carlos, 1);
}

function testAllowanceRevert() public {
vm.startPrank(alice);
vm.expectRevert(bytes(Errors.OPERATION_NOT_SUPPORTED));
GHO_DEBT_TOKEN.allowance(carlos, alice);
}

function testUpdateDiscountByOther() public {
vm.startPrank(alice);
vm.expectRevert(bytes('CALLER_NOT_DISCOUNT_TOKEN'));
GHO_DEBT_TOKEN.updateDiscountDistribution(alice, alice, 0, 0, 0);
}

function testDecreaseBalanceByOther() public {
vm.startPrank(alice);
vm.expectRevert(bytes('CALLER_NOT_A_TOKEN'));
GHO_DEBT_TOKEN.decreaseBalanceFromInterest(alice, 1);
}

function testMintByOther() public {
vm.startPrank(alice);
vm.expectRevert(bytes(Errors.CALLER_MUST_BE_POOL));
GHO_DEBT_TOKEN.mint(alice, alice, 0, 0);
}

function testBurnByOther() public {
vm.startPrank(alice);

vm.expectRevert(bytes(Errors.CALLER_MUST_BE_POOL));
GHO_DEBT_TOKEN.burn(alice, 0, 0);
}

function testSetATokenByOther() public {
GhoVariableDebtToken debtToken = new GhoVariableDebtToken(IPool(address(POOL)));

vm.startPrank(alice);
ACL_MANAGER.setState(false);

vm.expectRevert(bytes(Errors.CALLER_NOT_POOL_ADMIN));
debtToken.setAToken(alice);
}

function testUpdateAToken() public {
vm.startPrank(alice);
vm.expectRevert(bytes('ATOKEN_ALREADY_SET'));
GHO_DEBT_TOKEN.setAToken(alice);
}

function testZeroAToken() public {
GhoVariableDebtToken debtToken = new GhoVariableDebtToken(IPool(address(POOL)));

vm.startPrank(alice);
vm.expectRevert(bytes('ZERO_ADDRESS_NOT_VALID'));
debtToken.setAToken(address(0));
}

function testUpdateDiscountRateStrategyByOther() public {
vm.startPrank(alice);
ACL_MANAGER.setState(false);

vm.expectRevert(bytes(Errors.CALLER_NOT_POOL_ADMIN));
GHO_DEBT_TOKEN.updateDiscountRateStrategy(alice);
}

function testUpdateDiscountTokenByOther() public {
vm.startPrank(alice);
ACL_MANAGER.setState(false);

vm.expectRevert(bytes(Errors.CALLER_NOT_POOL_ADMIN));
GHO_DEBT_TOKEN.updateDiscountToken(alice);
}

function testUpdateDiscountTokenToZero() public {
vm.startPrank(alice);
vm.expectRevert(bytes('ZERO_ADDR'));
GHO_DEBT_TOKEN.updateDiscountToken(address(0));
}

function testUpdateDiscountStrategy() public {
vm.startPrank(alice);
GHO_DEBT_TOKEN.updateDiscountRateStrategy(carlos);
assertEq(
GHO_DEBT_TOKEN.getDiscountRateStrategy(),
carlos,
'Discount Rate Strategy should be updated'
);
}

function testUpdateDiscountToken() public {
vm.startPrank(alice);
GHO_DEBT_TOKEN.updateDiscountToken(carlos);
assertEq(GHO_DEBT_TOKEN.getDiscountToken(), carlos, 'Discount token should be updated');
}
}
31 changes: 31 additions & 0 deletions src/contracts/foundry-test/libraries/DebtUtils.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import {SafeCast} from '@aave/core-v3/contracts/dependencies/openzeppelin/contracts/SafeCast.sol';
import {WadRayMath} from '@aave/core-v3/contracts/protocol/libraries/math/WadRayMath.sol';
import {PercentageMath} from '@aave/core-v3/contracts/protocol/libraries/math/PercentageMath.sol';

library DebtUtils {
using WadRayMath for uint256;
using SafeCast for uint256;
using PercentageMath for uint256;

function computeDebt(
uint256 userPreviousIndex,
uint256 index,
uint256 previousScaledBalance,
uint256 accumulatedDebtInterest,
uint256 discountPercent
) external pure returns (uint256, uint256, uint128) {
uint256 balanceIncrease = previousScaledBalance.rayMul(index) -
previousScaledBalance.rayMul(userPreviousIndex);

uint256 discountScaled = 0;
if (balanceIncrease != 0 && discountPercent != 0) {
uint256 discount = balanceIncrease.percentMul(discountPercent);
discountScaled = discount.rayDiv(index);
balanceIncrease = balanceIncrease - discount;
}

uint128 accumulatedDebt = (balanceIncrease + accumulatedDebtInterest).toUint128();

return (balanceIncrease, discountScaled, accumulatedDebt);
}
}
14 changes: 12 additions & 2 deletions src/contracts/foundry-test/mocks/MockedAclManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,17 @@
pragma solidity ^0.8.0;

contract MockedAclManager {
function isPoolAdmin(address) public pure returns (bool) {
return true;
bool state;

constructor() {
state = true;
}

function isPoolAdmin(address) public view returns (bool) {
return state;
}

function setState(bool value) public {
state = value;
}
}
Loading