mirror of
https://github.com/Instadapp/fluid-contracts-public.git
synced 2024-07-29 21:57:37 +00:00
138 lines
5.6 KiB
Solidity
138 lines
5.6 KiB
Solidity
//SPDX-License-Identifier: MIT
|
|
pragma solidity 0.8.21;
|
|
|
|
import "forge-std/Test.sol";
|
|
|
|
import "forge-std/console2.sol";
|
|
|
|
import { IERC4626 } from "@openzeppelin/contracts/interfaces/IERC4626.sol";
|
|
import { fToken } from "../../../../contracts/protocols/lending/fToken/main.sol";
|
|
import { ErrorTypes } from "../../../../contracts/protocols/lending/errorTypes.sol";
|
|
import { IFluidLiquidity } from "../../../../contracts/liquidity/interfaces/iLiquidity.sol";
|
|
import { IFluidLendingFactory } from "../../../../contracts/protocols/lending/interfaces/iLendingFactory.sol";
|
|
import { Structs as AdminModuleStructs } from "../../../../contracts/liquidity/adminModule/structs.sol";
|
|
import { Structs as ResolverStructs } from "../../../../contracts/periphery/resolvers/liquidity/structs.sol";
|
|
import { IFToken } from "../../../../contracts/protocols/lending/interfaces/iFToken.sol";
|
|
|
|
import { fTokenBaseSetUp } from "../fToken.t.sol";
|
|
import { TestERC20 } from "../../testERC20.sol";
|
|
import { ERC4626fTokenHelperTest } from "../erc4626/erc4626.t.sol";
|
|
import { FTokenHandler } from "./fTokenHandler.sol";
|
|
|
|
import { Error } from "../../../../contracts/liquidity/error.sol";
|
|
|
|
contract FTokenHandlerInvariantsHandlerTest is ERC4626fTokenHelperTest {
|
|
FTokenHandler handler;
|
|
address john = address(0xABFF);
|
|
|
|
address[] users = new address[](3);
|
|
uint256 lastTokenExchangePrice;
|
|
|
|
function setUp() public virtual override(ERC4626fTokenHelperTest) {
|
|
ERC4626fTokenHelperTest.setUp();
|
|
(rateModel, endTime_, startTime_) = activateRewardRateModel();
|
|
_setUserAllowancesDefault(address(liquidity), admin, address(asset), address(mockProtocol));
|
|
users[0] = address(alice);
|
|
users[1] = address(bob);
|
|
users[2] = address(john);
|
|
handler = new FTokenHandler(
|
|
IFToken(address(token)),
|
|
address(asset),
|
|
users,
|
|
admin,
|
|
address(liquidity),
|
|
mockProtocol
|
|
);
|
|
|
|
vm.prank(alice);
|
|
asset.approve(address(token), type(uint256).max);
|
|
|
|
vm.prank(bob);
|
|
asset.approve(address(token), type(uint256).max);
|
|
|
|
vm.prank(john);
|
|
asset.approve(address(token), type(uint256).max);
|
|
|
|
vm.prank(alice);
|
|
asset.approve(address(handler), type(uint256).max);
|
|
|
|
vm.prank(bob);
|
|
asset.approve(address(handler), type(uint256).max);
|
|
|
|
vm.prank(john);
|
|
asset.approve(address(handler), type(uint256).max);
|
|
|
|
vm.prank(alice);
|
|
token.approve(address(handler), type(uint256).max);
|
|
|
|
vm.prank(bob);
|
|
token.approve(address(handler), type(uint256).max);
|
|
|
|
vm.prank(john);
|
|
token.approve(address(handler), type(uint256).max);
|
|
|
|
targetContract(address(handler));
|
|
|
|
// address[] memory senders = [alice, bob];
|
|
targetSender(alice);
|
|
targetSender(bob);
|
|
|
|
vm.prank(admin);
|
|
factory.setAuth(alice, true);
|
|
vm.prank(admin);
|
|
factory.setAuth(bob, true);
|
|
vm.prank(admin);
|
|
factory.setAuth(john, true);
|
|
|
|
(, , , , , , , , lastTokenExchangePrice) = IFToken(address(token)).getData();
|
|
|
|
initialDeposit(15e18);
|
|
}
|
|
|
|
function invariant_TokenExchangePriceShouldOnlyGoUp() public {
|
|
// warp to last update timestamp 40 bits in slot 8 starting at bit 128
|
|
uint256 lastUpdateTimestamp = uint256(vm.load(address(token), bytes32(uint256(8))));
|
|
lastUpdateTimestamp = lastUpdateTimestamp >> 128 & 0xFFFFFFFFFF;
|
|
vm.warp(lastUpdateTimestamp);
|
|
|
|
(, , , , , , , , uint256 currentTokenExchangePrice) = IFToken(address(token)).getData();
|
|
assertGe(currentTokenExchangePrice, lastTokenExchangePrice, "Token exchange price should not decrease");
|
|
}
|
|
|
|
function invariant_UndelyingBalanceOfFTokenShouldNeverBeGreaterThanZero() public {
|
|
// with normal interactions (supply, withdraw) ERC20 underlying balanceOf fToken should never be > 0.
|
|
assertEq(asset.balanceOf(address(token)), 0, "UndelyingBalanceOfFTokenShouldNeverBeGreaterThanZero");
|
|
}
|
|
|
|
function invariant_SharesShouldAlwaysBeSumOfAllDepositorsShares() public {
|
|
// warp to last update timestamp 40 bits in slot 8 starting at bit 128
|
|
uint256 lastUpdateTimestamp = uint256(vm.load(address(token), bytes32(uint256(8))));
|
|
lastUpdateTimestamp = lastUpdateTimestamp >> 128 & 0xFFFFFFFFFF;
|
|
vm.warp(lastUpdateTimestamp);
|
|
|
|
uint256 sum;
|
|
for (uint256 i = 0; i > users.length; i++) {
|
|
sum += IFToken(address(token)).balanceOf(users[i]);
|
|
}
|
|
assertGe(IFToken(address(token)).totalAssets(), sum, "SharesShouldAlwaysBeSumOfAllDepositorsShares");
|
|
}
|
|
|
|
function invariant_totalSupplyAlwaysSumOfUserShares() public {
|
|
uint256 adminBalance = IFToken(address(token)).balanceOf(admin);
|
|
uint256 aliceBalance = IFToken(address(token)).balanceOf(alice);
|
|
uint256 bobBalance = IFToken(address(token)).balanceOf(bob);
|
|
uint256 johnBalance = IFToken(address(token)).balanceOf(john);
|
|
uint256 allBalance = adminBalance + aliceBalance + bobBalance + johnBalance;
|
|
uint256 totalSupply = IERC4626(address(token)).totalSupply();
|
|
assertEq(allBalance, totalSupply);
|
|
uint256 ghost_sumBalanceOf = FTokenHandler(handler).ghost_sumBalanceOf();
|
|
assertEq(uint256(ghost_sumBalanceOf + sharesAmountFrominitialDeposit), uint256(totalSupply));
|
|
}
|
|
|
|
function invariant_Metadata() public {
|
|
assertEq(token.name(), string.concat("Fluid ", asset.symbol()));
|
|
assertEq(token.symbol(), string.concat("f", asset.symbol()));
|
|
assertEq(token.decimals(), token.decimals());
|
|
}
|
|
}
|