fluid-contracts-public/test/foundry/liquidity/userModule/liquidityOperateCombinations.t.sol
2024-07-11 13:05:09 +00:00

1237 lines
46 KiB
Solidity

//SPDX-License-Identifier: MIT
pragma solidity 0.8.21;
import { LiquidityUserModuleOperateTestSuite } from "./liquidityOperate.t.sol";
import { LiquidityCalcs } from "../../../../contracts/libraries/liquidityCalcs.sol";
/***********************************|
| SUPPLY & BORROW |
|__________________________________*/
contract LiquidityUserModuleSupplyAndBorrowTestSuite is LiquidityUserModuleOperateTestSuite {
function setUp() public virtual override {
super.setUp();
uint256 supplyExchangePrice = EXCHANGE_PRICES_PRECISION;
uint256 borrowExchangePrice = EXCHANGE_PRICES_PRECISION;
uint256 exchangePricesAndConfig;
{
uint256 utilization = (DEFAULT_BORROW_AMOUNT * FOUR_DECIMALS) / DEFAULT_SUPPLY_AMOUNT;
uint256 borrowRate = LiquidityCalcs.calcBorrowRateFromUtilization(
resolver.getRateConfig(address(USDC)),
utilization
);
exchangePricesAndConfig = _simulateExchangePricesWithRatesAndRatios(
resolver,
address(USDC),
supplyExchangePrice,
borrowExchangePrice,
utilization,
borrowRate,
block.timestamp,
0,
0
);
}
_setTestOperateParams(
address(USDC),
int256(DEFAULT_SUPPLY_AMOUNT),
int256(DEFAULT_BORROW_AMOUNT),
alice,
address(0),
alice,
_simulateTotalAmounts(DEFAULT_SUPPLY_AMOUNT, 0, DEFAULT_BORROW_AMOUNT, 0),
exchangePricesAndConfig,
supplyExchangePrice,
borrowExchangePrice,
_simulateUserSupplyData(
resolver,
address(mockProtocol),
address(USDC),
DEFAULT_SUPPLY_AMOUNT,
0, // previous limit
block.timestamp
),
_simulateUserBorrowData(
resolver,
address(mockProtocol),
address(USDC),
DEFAULT_BORROW_AMOUNT,
DEFAULT_BASE_DEBT_CEILING_AFTER_BIGMATH, // base borrow limit will be set as previous limit
block.timestamp
),
true
);
}
}
contract LiquidityUserModuleSupplyAndBorrowTestSuiteInterestFree is LiquidityUserModuleOperateTestSuite {
function setUp() public virtual override {
super.setUp();
_setUserAllowancesDefaultInterestFree(address(liquidity), admin, address(USDC), address(mockProtocol));
uint256 supplyExchangePrice = EXCHANGE_PRICES_PRECISION;
uint256 borrowExchangePrice = EXCHANGE_PRICES_PRECISION;
uint256 exchangePricesAndConfig;
{
uint256 utilization = (DEFAULT_BORROW_AMOUNT * FOUR_DECIMALS) / DEFAULT_SUPPLY_AMOUNT;
uint256 borrowRate = LiquidityCalcs.calcBorrowRateFromUtilization(
resolver.getRateConfig(address(USDC)),
utilization
);
exchangePricesAndConfig = _simulateExchangePricesWithRatesAndRatios(
resolver,
address(USDC),
supplyExchangePrice,
borrowExchangePrice,
utilization,
borrowRate,
block.timestamp,
1,
1
);
}
_setTestOperateParams(
address(USDC),
int256(DEFAULT_SUPPLY_AMOUNT),
int256(DEFAULT_BORROW_AMOUNT),
alice,
address(0),
alice,
_simulateTotalAmounts(0, DEFAULT_SUPPLY_AMOUNT, 0, DEFAULT_BORROW_AMOUNT),
exchangePricesAndConfig,
supplyExchangePrice,
borrowExchangePrice,
_simulateUserSupplyData(
resolver,
address(mockProtocol),
address(USDC),
DEFAULT_SUPPLY_AMOUNT,
0, // previous limit
block.timestamp
),
_simulateUserBorrowData(
resolver,
address(mockProtocol),
address(USDC),
DEFAULT_BORROW_AMOUNT,
DEFAULT_BASE_DEBT_CEILING_AFTER_BIGMATH, // base borrow limit will be set as previous limit
block.timestamp
),
true
);
}
}
contract LiquidityUserModuleSupplyAndBorrowTestSuiteNative is LiquidityUserModuleOperateTestSuite {
function setUp() public virtual override {
super.setUp();
uint256 supplyExchangePrice = EXCHANGE_PRICES_PRECISION;
uint256 borrowExchangePrice = EXCHANGE_PRICES_PRECISION;
uint256 exchangePricesAndConfig;
{
uint256 utilization = (DEFAULT_BORROW_AMOUNT * FOUR_DECIMALS) / DEFAULT_SUPPLY_AMOUNT;
uint256 borrowRate = LiquidityCalcs.calcBorrowRateFromUtilization(
resolver.getRateConfig(NATIVE_TOKEN_ADDRESS),
utilization
);
exchangePricesAndConfig = _simulateExchangePricesWithRatesAndRatios(
resolver,
NATIVE_TOKEN_ADDRESS,
supplyExchangePrice,
borrowExchangePrice,
utilization,
borrowRate,
block.timestamp,
0,
0
);
}
_setTestOperateParams(
NATIVE_TOKEN_ADDRESS,
int256(DEFAULT_SUPPLY_AMOUNT),
int256(DEFAULT_BORROW_AMOUNT),
alice,
address(0),
alice,
_simulateTotalAmounts(DEFAULT_SUPPLY_AMOUNT, 0, DEFAULT_BORROW_AMOUNT, 0),
exchangePricesAndConfig,
supplyExchangePrice,
borrowExchangePrice,
_simulateUserSupplyData(
resolver,
address(mockProtocol),
NATIVE_TOKEN_ADDRESS,
DEFAULT_SUPPLY_AMOUNT,
0, // previous limit
block.timestamp
),
_simulateUserBorrowData(
resolver,
address(mockProtocol),
NATIVE_TOKEN_ADDRESS,
DEFAULT_BORROW_AMOUNT,
DEFAULT_BASE_DEBT_CEILING_AFTER_BIGMATH, // base borrow limit will be set as previous limit
block.timestamp
),
true
);
}
}
contract LiquidityUserModuleSupplyAndBorrowTestSuiteInterestFreeNative is LiquidityUserModuleOperateTestSuite {
function setUp() public virtual override {
super.setUp();
_setUserAllowancesDefaultInterestFree(address(liquidity), admin, NATIVE_TOKEN_ADDRESS, address(mockProtocol));
uint256 supplyExchangePrice = EXCHANGE_PRICES_PRECISION;
uint256 borrowExchangePrice = EXCHANGE_PRICES_PRECISION;
uint256 exchangePricesAndConfig;
{
uint256 utilization = (DEFAULT_BORROW_AMOUNT * FOUR_DECIMALS) / DEFAULT_SUPPLY_AMOUNT;
uint256 borrowRate = LiquidityCalcs.calcBorrowRateFromUtilization(
resolver.getRateConfig(NATIVE_TOKEN_ADDRESS),
utilization
);
exchangePricesAndConfig = _simulateExchangePricesWithRatesAndRatios(
resolver,
NATIVE_TOKEN_ADDRESS,
supplyExchangePrice,
borrowExchangePrice,
utilization,
borrowRate,
block.timestamp,
1,
1
);
}
_setTestOperateParams(
NATIVE_TOKEN_ADDRESS,
int256(DEFAULT_SUPPLY_AMOUNT),
int256(DEFAULT_BORROW_AMOUNT),
alice,
address(0),
alice,
_simulateTotalAmounts(0, DEFAULT_SUPPLY_AMOUNT, 0, DEFAULT_BORROW_AMOUNT),
exchangePricesAndConfig,
supplyExchangePrice,
borrowExchangePrice,
_simulateUserSupplyData(
resolver,
address(mockProtocol),
NATIVE_TOKEN_ADDRESS,
DEFAULT_SUPPLY_AMOUNT,
0, // previous limit
block.timestamp
),
_simulateUserBorrowData(
resolver,
address(mockProtocol),
NATIVE_TOKEN_ADDRESS,
DEFAULT_BORROW_AMOUNT,
DEFAULT_BASE_DEBT_CEILING_AFTER_BIGMATH, // base borrow limit will be set as previous limit
block.timestamp
),
true
);
}
}
/***********************************|
| SUPPLY & PAYBACK |
|__________________________________*/
contract LiquidityUserModuleSupplyAndPaybackTestSuite is LiquidityUserModuleOperateTestSuite {
function setUp() public virtual override {
super.setUp();
// alice supplies USDC liquidity
_supply(mockProtocol, address(USDC), alice, DEFAULT_SUPPLY_AMOUNT);
// alice borrows USDC liquidity
_borrow(mockProtocol, address(USDC), alice, DEFAULT_BORROW_AMOUNT);
// simulate passing time 1 year to get a better predicatable borrow rate and amounts
vm.warp(block.timestamp + PASS_1YEAR_TIME);
uint256 supplyExchangePrice = 1038750000000; // increased half of 7.75% -> 3.875% (because half of supply is borrowed out)
uint256 borrowExchangePrice = 1077500000000; // increased 7.75%
uint256 totalAmounts;
uint256 userBorrowData;
uint256 exchangePricesAndConfig;
uint256 totalSupplyRawInterest;
{
uint256 defaultBorrowAmountAfterRounding = 500000000000000008; // BigMath round up at borrow leads to minor difference
uint256 totalBorrow = (((defaultBorrowAmountAfterRounding * borrowExchangePrice) /
EXCHANGE_PRICES_PRECISION) - DEFAULT_PAYBACK_AMOUNT);
assertEq(totalBorrow, 238750000000000008);
uint256 totalBorrowRawInterest = ((totalBorrow * EXCHANGE_PRICES_PRECISION) / borrowExchangePrice) + 1; // should be 0.221577726218097455 +1 for round up
assertEq(totalBorrowRawInterest, 221577726218097456);
totalSupplyRawInterest =
DEFAULT_SUPPLY_AMOUNT + // previous supply raw
((DEFAULT_SUPPLY_AMOUNT * EXCHANGE_PRICES_PRECISION) / supplyExchangePrice); // new supply adjusted to raw
assertEq(totalSupplyRawInterest, 1962695547533092659);
uint256 totalSupply = ((DEFAULT_SUPPLY_AMOUNT * supplyExchangePrice) / EXCHANGE_PRICES_PRECISION) +
DEFAULT_SUPPLY_AMOUNT;
assertEq(totalSupply, 2038750000000000000); // 1 ether * 1038750000000 + 1 ether
totalAmounts = _simulateTotalAmounts(totalSupplyRawInterest, 0, totalBorrowRawInterest, 0);
userBorrowData = _simulateUserBorrowData(
resolver,
address(mockProtocol),
address(USDC),
totalBorrowRawInterest, // taking interest on borrow amount until payback into account
DEFAULT_BASE_DEBT_CEILING_AFTER_BIGMATH, // base borrow limit will be set as previous limit
block.timestamp
);
// utilization AFTER payback
uint256 utilization = (totalBorrow * FOUR_DECIMALS) / totalSupply; // results in 11,7106 %
assertEq(utilization, 1171);
uint256 borrowRate = LiquidityCalcs.calcBorrowRateFromUtilization(
resolver.getRateConfig(address(USDC)),
utilization
);
assertEq(borrowRate, 487); // expected borrow rate at ~11,71% utilization
exchangePricesAndConfig = _simulateExchangePricesWithRatesAndRatios(
resolver,
address(USDC),
supplyExchangePrice,
borrowExchangePrice,
utilization,
borrowRate,
block.timestamp,
0,
0
);
}
_setTestOperateParams(
address(USDC),
int256(DEFAULT_SUPPLY_AMOUNT),
-int256(DEFAULT_PAYBACK_AMOUNT),
alice,
address(0),
address(0),
totalAmounts,
exchangePricesAndConfig,
supplyExchangePrice,
borrowExchangePrice,
_simulateUserSupplyData(
resolver,
address(mockProtocol),
address(USDC),
totalSupplyRawInterest,
0, // previous limit
block.timestamp
),
userBorrowData,
true
);
}
}
contract LiquidityUserModuleSupplyAndPaybackTestSuiteInterestFree is LiquidityUserModuleOperateTestSuite {
function setUp() public virtual override {
super.setUp();
_setUserAllowancesDefaultInterestFree(address(liquidity), admin, address(USDC), address(mockProtocol));
// alice supplies USDC liquidity
_supply(mockProtocol, address(USDC), alice, DEFAULT_SUPPLY_AMOUNT);
// alice borrows USDC liquidity
_borrow(mockProtocol, address(USDC), alice, DEFAULT_BORROW_AMOUNT);
// simulate passing time 1 year to get a better predicatable borrow rate and amounts
vm.warp(block.timestamp + PASS_1YEAR_TIME);
// exchange prices are not changing because of interest free mode
uint256 supplyExchangePrice = EXCHANGE_PRICES_PRECISION;
uint256 borrowExchangePrice = EXCHANGE_PRICES_PRECISION;
uint256 totalAmounts;
uint256 totalSupply = DEFAULT_SUPPLY_AMOUNT * 2;
uint256 exchangePricesAndConfig;
{
uint256 defaultBorrowAmountAfterRounding = 500000000000000008; // BigMath round up at borrow leads to minor difference
uint256 totalBorrow = defaultBorrowAmountAfterRounding - DEFAULT_PAYBACK_AMOUNT;
totalAmounts = _simulateTotalAmounts(0, totalSupply, 0, totalBorrow);
// utilization AFTER payback
uint256 utilization = (totalBorrow * FOUR_DECIMALS) / totalSupply; // results in 10%
assertEq(utilization, 1000);
uint256 borrowRate = LiquidityCalcs.calcBorrowRateFromUtilization(
resolver.getRateConfig(address(USDC)),
utilization
);
assertEq(borrowRate, 475); // expected borrow rate at 10% utilization
exchangePricesAndConfig = _simulateExchangePricesWithRatesAndRatios(
resolver,
address(USDC),
supplyExchangePrice,
borrowExchangePrice,
utilization,
borrowRate,
block.timestamp,
1, // supplyRatio = 1 for mode set to total supply with interest < interest free
1 // borrowRatio = 1 for mode set to total supply with interest < interest free
);
}
uint256 userSupplyData = _simulateUserSupplyData(
resolver,
address(mockProtocol),
address(USDC),
totalSupply,
0, // previous limit
block.timestamp
);
_setTestOperateParams(
address(USDC),
int256(DEFAULT_SUPPLY_AMOUNT),
-int256(DEFAULT_PAYBACK_AMOUNT),
alice,
address(0),
address(0),
totalAmounts,
exchangePricesAndConfig,
supplyExchangePrice,
borrowExchangePrice,
userSupplyData,
_simulateUserBorrowData(
resolver,
address(mockProtocol),
address(USDC),
DEFAULT_BORROW_AMOUNT_AFTER_BIGMATH - DEFAULT_PAYBACK_AMOUNT,
DEFAULT_BASE_DEBT_CEILING_AFTER_BIGMATH, // base borrow limit will be set as previous limit
block.timestamp
),
true
);
}
}
contract LiquidityUserModuleSupplyAndPaybackTestSuiteNative is LiquidityUserModuleOperateTestSuite {
function setUp() public virtual override {
super.setUp();
// alice supplies liquidity
_supplyNative(mockProtocol, alice, DEFAULT_SUPPLY_AMOUNT);
// alice borrows liquidity
_borrowNative(mockProtocol, alice, DEFAULT_BORROW_AMOUNT);
// simulate passing time 1 year to get a better predicatable borrow rate and amounts
vm.warp(block.timestamp + PASS_1YEAR_TIME);
uint256 supplyExchangePrice = 1038750000000; // increased half of 7.75% -> 3.875% (because half of supply is borrowed out)
uint256 borrowExchangePrice = 1077500000000; // increased 7.75%
uint256 totalAmounts;
uint256 userBorrowData;
uint256 exchangePricesAndConfig;
uint256 totalSupplyRawInterest;
{
uint256 defaultBorrowAmountAfterRounding = 500000000000000008; // BigMath round up at borrow leads to minor difference
uint256 totalBorrow = (((defaultBorrowAmountAfterRounding * borrowExchangePrice) /
EXCHANGE_PRICES_PRECISION) - DEFAULT_PAYBACK_AMOUNT);
assertEq(totalBorrow, 238750000000000008);
uint256 totalBorrowRawInterest = ((totalBorrow * EXCHANGE_PRICES_PRECISION) / borrowExchangePrice) + 1; // should be 0.221577726218097455 +1 for round up
assertEq(totalBorrowRawInterest, 221577726218097456);
totalSupplyRawInterest =
DEFAULT_SUPPLY_AMOUNT + // previous supply raw
((DEFAULT_SUPPLY_AMOUNT * EXCHANGE_PRICES_PRECISION) / supplyExchangePrice); // new supply adjusted to raw
assertEq(totalSupplyRawInterest, 1962695547533092659);
uint256 totalSupply = ((DEFAULT_SUPPLY_AMOUNT * supplyExchangePrice) / EXCHANGE_PRICES_PRECISION) +
DEFAULT_SUPPLY_AMOUNT;
assertEq(totalSupply, 2038750000000000000); // 1 ether * 1038750000000 + 1 ether
totalAmounts = _simulateTotalAmounts(totalSupplyRawInterest, 0, totalBorrowRawInterest, 0);
userBorrowData = _simulateUserBorrowData(
resolver,
address(mockProtocol),
NATIVE_TOKEN_ADDRESS,
totalBorrowRawInterest, // taking interest on borrow amount until payback into account
DEFAULT_BASE_DEBT_CEILING_AFTER_BIGMATH, // base borrow limit will be set as previous limit
block.timestamp
);
// utilization AFTER payback
uint256 utilization = (totalBorrow * FOUR_DECIMALS) / totalSupply; // results in 11,7106 %
assertEq(utilization, 1171);
uint256 borrowRate = LiquidityCalcs.calcBorrowRateFromUtilization(
resolver.getRateConfig(NATIVE_TOKEN_ADDRESS),
utilization
);
assertEq(borrowRate, 487); // expected borrow rate at ~11,71% utilization
exchangePricesAndConfig = _simulateExchangePricesWithRatesAndRatios(
resolver,
NATIVE_TOKEN_ADDRESS,
supplyExchangePrice,
borrowExchangePrice,
utilization,
borrowRate,
block.timestamp,
0,
0
);
}
_setTestOperateParams(
NATIVE_TOKEN_ADDRESS,
int256(DEFAULT_SUPPLY_AMOUNT),
-int256(DEFAULT_PAYBACK_AMOUNT),
alice,
address(0),
address(0),
totalAmounts,
exchangePricesAndConfig,
supplyExchangePrice,
borrowExchangePrice,
_simulateUserSupplyData(
resolver,
address(mockProtocol),
NATIVE_TOKEN_ADDRESS,
totalSupplyRawInterest,
0, // previous limit
block.timestamp
),
userBorrowData,
true
);
}
}
contract LiquidityUserModuleSupplyAndPaybackTestSuiteInterestFreeNative is LiquidityUserModuleOperateTestSuite {
function setUp() public virtual override {
super.setUp();
_setUserAllowancesDefaultInterestFree(address(liquidity), admin, NATIVE_TOKEN_ADDRESS, address(mockProtocol));
_supplyNative(mockProtocol, alice, DEFAULT_SUPPLY_AMOUNT);
// alice borrows liquidity
_borrowNative(mockProtocol, alice, DEFAULT_BORROW_AMOUNT);
// simulate passing time 1 year to get a better predicatable borrow rate and amounts
vm.warp(block.timestamp + PASS_1YEAR_TIME);
// exchange prices are not changing because of interest free mode
uint256 supplyExchangePrice = EXCHANGE_PRICES_PRECISION;
uint256 borrowExchangePrice = EXCHANGE_PRICES_PRECISION;
uint256 totalAmounts;
uint256 totalSupply = DEFAULT_SUPPLY_AMOUNT * 2;
uint256 exchangePricesAndConfig;
{
uint256 defaultBorrowAmountAfterRounding = 500000000000000008; // BigMath round up at borrow leads to minor difference
uint256 totalBorrow = defaultBorrowAmountAfterRounding - DEFAULT_PAYBACK_AMOUNT;
totalAmounts = _simulateTotalAmounts(0, totalSupply, 0, totalBorrow);
// utilization AFTER payback
uint256 utilization = (totalBorrow * FOUR_DECIMALS) / totalSupply; // results in 10%
assertEq(utilization, 1000);
uint256 borrowRate = LiquidityCalcs.calcBorrowRateFromUtilization(
resolver.getRateConfig(NATIVE_TOKEN_ADDRESS),
utilization
);
assertEq(borrowRate, 475); // expected borrow rate at 10% utilization
exchangePricesAndConfig = _simulateExchangePricesWithRatesAndRatios(
resolver,
NATIVE_TOKEN_ADDRESS,
supplyExchangePrice,
borrowExchangePrice,
utilization,
borrowRate,
block.timestamp,
1, // supplyRatio = 1 for mode set to total supply with interest < interest free
1 // borrowRatio = 1 for mode set to total supply with interest < interest free
);
}
uint256 userSupplyData = _simulateUserSupplyData(
resolver,
address(mockProtocol),
NATIVE_TOKEN_ADDRESS,
totalSupply,
0, // previous limit
block.timestamp
);
_setTestOperateParams(
NATIVE_TOKEN_ADDRESS,
int256(DEFAULT_SUPPLY_AMOUNT),
-int256(DEFAULT_PAYBACK_AMOUNT),
alice,
address(0),
address(0),
totalAmounts,
exchangePricesAndConfig,
supplyExchangePrice,
borrowExchangePrice,
userSupplyData,
_simulateUserBorrowData(
resolver,
address(mockProtocol),
NATIVE_TOKEN_ADDRESS,
DEFAULT_BORROW_AMOUNT_AFTER_BIGMATH - DEFAULT_PAYBACK_AMOUNT,
DEFAULT_BASE_DEBT_CEILING_AFTER_BIGMATH, // base borrow limit will be set as previous limit
block.timestamp
),
true
);
}
}
/***********************************|
| WITHDRAW & BORROW |
|__________________________________*/
contract LiquidityUserModuleWithdrawAndBorrowTestSuite is LiquidityUserModuleOperateTestSuite {
function setUp() public virtual override {
super.setUp();
// alice supplies USDC liquidity
_supply(mockProtocol, address(USDC), alice, DEFAULT_SUPPLY_AMOUNT);
uint256 supplyExchangePrice = EXCHANGE_PRICES_PRECISION;
uint256 borrowExchangePrice = EXCHANGE_PRICES_PRECISION;
uint256 exchangePricesAndConfig;
{
uint256 utilization = (DEFAULT_BORROW_AMOUNT * FOUR_DECIMALS) /
(DEFAULT_SUPPLY_AMOUNT - DEFAULT_WITHDRAW_AMOUNT);
uint256 borrowRate = LiquidityCalcs.calcBorrowRateFromUtilization(
resolver.getRateConfig(address(USDC)),
utilization
);
exchangePricesAndConfig = _simulateExchangePricesWithRatesAndRatios(
resolver,
address(USDC),
supplyExchangePrice,
borrowExchangePrice,
utilization,
borrowRate,
block.timestamp,
0,
0
);
}
_setTestOperateParams(
address(USDC),
-int256(DEFAULT_WITHDRAW_AMOUNT),
int256(DEFAULT_BORROW_AMOUNT),
alice,
alice,
alice,
_simulateTotalAmounts(DEFAULT_SUPPLY_AMOUNT - DEFAULT_WITHDRAW_AMOUNT, 0, DEFAULT_BORROW_AMOUNT, 0),
exchangePricesAndConfig,
supplyExchangePrice,
borrowExchangePrice,
_simulateUserSupplyData(
resolver,
address(mockProtocol),
address(USDC),
DEFAULT_SUPPLY_AMOUNT - DEFAULT_WITHDRAW_AMOUNT,
0, // previous limit
block.timestamp
),
_simulateUserBorrowData(
resolver,
address(mockProtocol),
address(USDC),
DEFAULT_BORROW_AMOUNT,
DEFAULT_BASE_DEBT_CEILING_AFTER_BIGMATH, // base borrow limit will be set as previous limit
block.timestamp
),
true
);
}
}
contract LiquidityUserModuleWithdrawAndBorrowTestSuiteInterestFree is LiquidityUserModuleOperateTestSuite {
function setUp() public virtual override {
super.setUp();
_setUserAllowancesDefaultInterestFree(address(liquidity), admin, address(USDC), address(mockProtocol));
// alice supplies USDC liquidity
_supply(mockProtocol, address(USDC), alice, DEFAULT_SUPPLY_AMOUNT);
uint256 supplyExchangePrice = EXCHANGE_PRICES_PRECISION;
uint256 borrowExchangePrice = EXCHANGE_PRICES_PRECISION;
uint256 exchangePricesAndConfig;
{
uint256 utilization = (DEFAULT_BORROW_AMOUNT * FOUR_DECIMALS) /
(DEFAULT_SUPPLY_AMOUNT - DEFAULT_WITHDRAW_AMOUNT);
uint256 borrowRate = LiquidityCalcs.calcBorrowRateFromUtilization(
resolver.getRateConfig(address(USDC)),
utilization
);
exchangePricesAndConfig = _simulateExchangePricesWithRatesAndRatios(
resolver,
address(USDC),
supplyExchangePrice,
borrowExchangePrice,
utilization,
borrowRate,
block.timestamp,
1,
1
);
}
_setTestOperateParams(
address(USDC),
-int256(DEFAULT_WITHDRAW_AMOUNT),
int256(DEFAULT_BORROW_AMOUNT),
alice,
alice,
alice,
_simulateTotalAmounts(0, DEFAULT_SUPPLY_AMOUNT - DEFAULT_WITHDRAW_AMOUNT, 0, DEFAULT_BORROW_AMOUNT),
exchangePricesAndConfig,
supplyExchangePrice,
borrowExchangePrice,
_simulateUserSupplyData(
resolver,
address(mockProtocol),
address(USDC),
DEFAULT_SUPPLY_AMOUNT - DEFAULT_WITHDRAW_AMOUNT,
0, // previous limit
block.timestamp
),
_simulateUserBorrowData(
resolver,
address(mockProtocol),
address(USDC),
DEFAULT_BORROW_AMOUNT,
DEFAULT_BASE_DEBT_CEILING_AFTER_BIGMATH, // base borrow limit will be set as previous limit
block.timestamp
),
true
);
}
}
contract LiquidityUserModuleWithdrawAndBorrowTestSuiteNative is LiquidityUserModuleOperateTestSuite {
function setUp() public virtual override {
super.setUp();
// alice supplies liquidity
_supplyNative(mockProtocol, alice, DEFAULT_SUPPLY_AMOUNT);
uint256 supplyExchangePrice = EXCHANGE_PRICES_PRECISION;
uint256 borrowExchangePrice = EXCHANGE_PRICES_PRECISION;
uint256 exchangePricesAndConfig;
{
uint256 utilization = (DEFAULT_BORROW_AMOUNT * FOUR_DECIMALS) /
(DEFAULT_SUPPLY_AMOUNT - DEFAULT_WITHDRAW_AMOUNT);
uint256 borrowRate = LiquidityCalcs.calcBorrowRateFromUtilization(
resolver.getRateConfig(NATIVE_TOKEN_ADDRESS),
utilization
);
exchangePricesAndConfig = _simulateExchangePricesWithRatesAndRatios(
resolver,
NATIVE_TOKEN_ADDRESS,
supplyExchangePrice,
borrowExchangePrice,
utilization,
borrowRate,
block.timestamp,
0,
0
);
}
_setTestOperateParams(
NATIVE_TOKEN_ADDRESS,
-int256(DEFAULT_WITHDRAW_AMOUNT),
int256(DEFAULT_BORROW_AMOUNT),
alice,
alice,
alice,
_simulateTotalAmounts(DEFAULT_SUPPLY_AMOUNT - DEFAULT_WITHDRAW_AMOUNT, 0, DEFAULT_BORROW_AMOUNT, 0),
exchangePricesAndConfig,
supplyExchangePrice,
borrowExchangePrice,
_simulateUserSupplyData(
resolver,
address(mockProtocol),
NATIVE_TOKEN_ADDRESS,
DEFAULT_SUPPLY_AMOUNT - DEFAULT_WITHDRAW_AMOUNT,
0, // previous limit
block.timestamp
),
_simulateUserBorrowData(
resolver,
address(mockProtocol),
NATIVE_TOKEN_ADDRESS,
DEFAULT_BORROW_AMOUNT,
DEFAULT_BASE_DEBT_CEILING_AFTER_BIGMATH, // base borrow limit will be set as previous limit
block.timestamp
),
true
);
}
}
contract LiquidityUserModuleWithdrawAndBorrowTestSuiteInterestFreeNative is LiquidityUserModuleOperateTestSuite {
function setUp() public virtual override {
super.setUp();
_setUserAllowancesDefaultInterestFree(address(liquidity), admin, NATIVE_TOKEN_ADDRESS, address(mockProtocol));
// alice supplies liquidity
_supplyNative(mockProtocol, alice, DEFAULT_SUPPLY_AMOUNT);
uint256 supplyExchangePrice = EXCHANGE_PRICES_PRECISION;
uint256 borrowExchangePrice = EXCHANGE_PRICES_PRECISION;
uint256 exchangePricesAndConfig;
{
uint256 utilization = (DEFAULT_BORROW_AMOUNT * FOUR_DECIMALS) /
(DEFAULT_SUPPLY_AMOUNT - DEFAULT_WITHDRAW_AMOUNT);
uint256 borrowRate = LiquidityCalcs.calcBorrowRateFromUtilization(
resolver.getRateConfig(NATIVE_TOKEN_ADDRESS),
utilization
);
exchangePricesAndConfig = _simulateExchangePricesWithRatesAndRatios(
resolver,
NATIVE_TOKEN_ADDRESS,
supplyExchangePrice,
borrowExchangePrice,
utilization,
borrowRate,
block.timestamp,
1,
1
);
}
_setTestOperateParams(
NATIVE_TOKEN_ADDRESS,
-int256(DEFAULT_WITHDRAW_AMOUNT),
int256(DEFAULT_BORROW_AMOUNT),
alice,
alice,
alice,
_simulateTotalAmounts(0, DEFAULT_SUPPLY_AMOUNT - DEFAULT_WITHDRAW_AMOUNT, 0, DEFAULT_BORROW_AMOUNT),
exchangePricesAndConfig,
supplyExchangePrice,
borrowExchangePrice,
_simulateUserSupplyData(
resolver,
address(mockProtocol),
NATIVE_TOKEN_ADDRESS,
DEFAULT_SUPPLY_AMOUNT - DEFAULT_WITHDRAW_AMOUNT,
0, // previous limit
block.timestamp
),
_simulateUserBorrowData(
resolver,
address(mockProtocol),
NATIVE_TOKEN_ADDRESS,
DEFAULT_BORROW_AMOUNT,
DEFAULT_BASE_DEBT_CEILING_AFTER_BIGMATH, // base borrow limit will be set as previous limit
block.timestamp
),
true
);
}
}
/***********************************|
| WITHDRAW & PAYBACK |
|__________________________________*/
contract LiquidityUserModuleWithdrawAndPaybackTestSuite is LiquidityUserModuleOperateTestSuite {
function setUp() public virtual override {
super.setUp();
// alice supplies USDC liquidity
_supply(mockProtocol, address(USDC), alice, DEFAULT_SUPPLY_AMOUNT);
// alice borrows USDC liquidity
_borrow(mockProtocol, address(USDC), alice, DEFAULT_BORROW_AMOUNT);
// simulate passing time 1 year to get a better predicatable borrow rate and amounts
vm.warp(block.timestamp + PASS_1YEAR_TIME);
uint256 supplyExchangePrice = 1038750000000; // increased half of 7.75% -> 3.875% (because half of supply is borrowed out)
uint256 borrowExchangePrice = 1077500000000; // increased 7.75%
uint256 totalAmounts;
uint256 userBorrowData;
uint256 exchangePricesAndConfig;
uint256 totalSupplyRawInterest;
{
uint256 defaultBorrowAmountAfterRounding = 500000000000000008; // BigMath round up at borrow leads to minor difference
uint256 totalBorrow = (((defaultBorrowAmountAfterRounding * borrowExchangePrice) /
EXCHANGE_PRICES_PRECISION) - DEFAULT_PAYBACK_AMOUNT);
assertEq(totalBorrow, 238750000000000008);
uint256 totalBorrowRawInterest = ((totalBorrow * EXCHANGE_PRICES_PRECISION) / borrowExchangePrice) + 1; // should be 0.221577726218097455 +1 for round up
assertEq(totalBorrowRawInterest, 221577726218097456);
totalSupplyRawInterest =
DEFAULT_SUPPLY_AMOUNT - // previous supply raw
((DEFAULT_WITHDRAW_AMOUNT * EXCHANGE_PRICES_PRECISION) / supplyExchangePrice); // new supply adjusted to raw
assertEq(totalSupplyRawInterest, 518652226233453671);
uint256 totalSupply = ((DEFAULT_SUPPLY_AMOUNT * supplyExchangePrice) / EXCHANGE_PRICES_PRECISION) -
DEFAULT_WITHDRAW_AMOUNT;
assertEq(totalSupply, 538750000000000000); // 1 ether * 1038750000000 - 0.5 ether
totalAmounts = _simulateTotalAmounts(totalSupplyRawInterest, 0, totalBorrowRawInterest, 0);
userBorrowData = _simulateUserBorrowData(
resolver,
address(mockProtocol),
address(USDC),
totalBorrowRawInterest, // taking interest on borrow amount until payback into account
DEFAULT_BASE_DEBT_CEILING_AFTER_BIGMATH, // base borrow limit will be set as previous limit
block.timestamp
);
// utilization AFTER payback
uint256 utilization = (totalBorrow * FOUR_DECIMALS) / totalSupply; // results in 44,31554 %
assertEq(utilization, 4431);
uint256 borrowRate = LiquidityCalcs.calcBorrowRateFromUtilization(
resolver.getRateConfig(address(USDC)),
utilization
);
assertEq(borrowRate, 732); // expected borrow rate at ~44,31% utilization
exchangePricesAndConfig = _simulateExchangePricesWithRatesAndRatios(
resolver,
address(USDC),
supplyExchangePrice,
borrowExchangePrice,
utilization,
borrowRate,
block.timestamp,
0,
0
);
}
_setTestOperateParams(
address(USDC),
-int256(DEFAULT_WITHDRAW_AMOUNT),
-int256(DEFAULT_PAYBACK_AMOUNT),
alice,
alice,
address(0),
totalAmounts,
exchangePricesAndConfig,
supplyExchangePrice,
borrowExchangePrice,
_simulateUserSupplyData(
resolver,
address(mockProtocol),
address(USDC),
totalSupplyRawInterest,
0, // previous limit
block.timestamp
),
userBorrowData,
true
);
}
}
contract LiquidityUserModuleWithdrawAndPaybackTestSuiteInterestFree is LiquidityUserModuleOperateTestSuite {
function setUp() public virtual override {
super.setUp();
_setUserAllowancesDefaultInterestFree(address(liquidity), admin, address(USDC), address(mockProtocol));
// alice supplies USDC liquidity
_supply(mockProtocol, address(USDC), alice, DEFAULT_SUPPLY_AMOUNT);
// alice borrows USDC liquidity
_borrow(mockProtocol, address(USDC), alice, DEFAULT_BORROW_AMOUNT);
// simulate passing time 1 year to get a better predicatable borrow rate and amounts
vm.warp(block.timestamp + PASS_1YEAR_TIME);
// exchange prices are not changing because of interest free mode
uint256 supplyExchangePrice = EXCHANGE_PRICES_PRECISION;
uint256 borrowExchangePrice = EXCHANGE_PRICES_PRECISION;
uint256 totalAmounts;
uint256 totalSupply = DEFAULT_SUPPLY_AMOUNT - DEFAULT_WITHDRAW_AMOUNT;
uint256 exchangePricesAndConfig;
{
uint256 defaultBorrowAmountAfterRounding = 500000000000000008; // BigMath round up at borrow leads to minor difference
uint256 totalBorrow = defaultBorrowAmountAfterRounding - DEFAULT_PAYBACK_AMOUNT;
totalAmounts = _simulateTotalAmounts(0, totalSupply, 0, totalBorrow);
// utilization AFTER payback
uint256 utilization = (totalBorrow * FOUR_DECIMALS) / totalSupply; // results in 40%
assertEq(utilization, 4000);
uint256 borrowRate = LiquidityCalcs.calcBorrowRateFromUtilization(
resolver.getRateConfig(address(USDC)),
utilization
);
assertEq(borrowRate, 700); // expected borrow rate at 40% utilization
exchangePricesAndConfig = _simulateExchangePricesWithRatesAndRatios(
resolver,
address(USDC),
supplyExchangePrice,
borrowExchangePrice,
utilization,
borrowRate,
block.timestamp,
1, // supplyRatio = 1 for mode set to total supply with interest < interest free
1 // borrowRatio = 1 for mode set to total supply with interest < interest free
);
}
uint256 userSupplyData = _simulateUserSupplyData(
resolver,
address(mockProtocol),
address(USDC),
totalSupply,
0, // previous limit
block.timestamp
);
_setTestOperateParams(
address(USDC),
-int256(DEFAULT_WITHDRAW_AMOUNT),
-int256(DEFAULT_PAYBACK_AMOUNT),
alice,
alice,
address(0),
totalAmounts,
exchangePricesAndConfig,
supplyExchangePrice,
borrowExchangePrice,
userSupplyData,
_simulateUserBorrowData(
resolver,
address(mockProtocol),
address(USDC),
DEFAULT_BORROW_AMOUNT_AFTER_BIGMATH - DEFAULT_PAYBACK_AMOUNT,
DEFAULT_BASE_DEBT_CEILING_AFTER_BIGMATH, // base borrow limit will be set as previous limit
block.timestamp
),
true
);
}
}
contract LiquidityUserModuleWithdrawAndPaybackTestSuiteNative is LiquidityUserModuleOperateTestSuite {
function setUp() public virtual override {
super.setUp();
// alice supplies liquidity
_supplyNative(mockProtocol, alice, DEFAULT_SUPPLY_AMOUNT);
// alice borrows liquidity
_borrowNative(mockProtocol, alice, DEFAULT_BORROW_AMOUNT);
// simulate passing time 1 year to get a better predicatable borrow rate and amounts
vm.warp(block.timestamp + PASS_1YEAR_TIME);
uint256 supplyExchangePrice = 1038750000000; // increased half of 7.75% -> 3.875% (because half of supply is borrowed out)
uint256 borrowExchangePrice = 1077500000000; // increased 7.75%
uint256 totalAmounts;
uint256 userBorrowData;
uint256 exchangePricesAndConfig;
uint256 totalSupplyRawInterest;
{
uint256 defaultBorrowAmountAfterRounding = 500000000000000008; // BigMath round up at borrow leads to minor difference
uint256 totalBorrow = (((defaultBorrowAmountAfterRounding * borrowExchangePrice) /
EXCHANGE_PRICES_PRECISION) - DEFAULT_PAYBACK_AMOUNT);
assertEq(totalBorrow, 238750000000000008);
uint256 totalBorrowRawInterest = ((totalBorrow * EXCHANGE_PRICES_PRECISION) / borrowExchangePrice) + 1; // should be 0.221577726218097455 +1 for round up
assertEq(totalBorrowRawInterest, 221577726218097456);
totalSupplyRawInterest =
DEFAULT_SUPPLY_AMOUNT - // previous supply raw
((DEFAULT_WITHDRAW_AMOUNT * EXCHANGE_PRICES_PRECISION) / supplyExchangePrice); // new supply adjusted to raw
assertEq(totalSupplyRawInterest, 518652226233453671);
uint256 totalSupply = ((DEFAULT_SUPPLY_AMOUNT * supplyExchangePrice) / EXCHANGE_PRICES_PRECISION) -
DEFAULT_WITHDRAW_AMOUNT;
assertEq(totalSupply, 538750000000000000); // 1 ether * 1038750000000 - 0.5 ether
totalAmounts = _simulateTotalAmounts(totalSupplyRawInterest, 0, totalBorrowRawInterest, 0);
userBorrowData = _simulateUserBorrowData(
resolver,
address(mockProtocol),
NATIVE_TOKEN_ADDRESS,
totalBorrowRawInterest, // taking interest on borrow amount until payback into account
DEFAULT_BASE_DEBT_CEILING_AFTER_BIGMATH, // base borrow limit will be set as previous limit
block.timestamp
);
// utilization AFTER payback
uint256 utilization = (totalBorrow * FOUR_DECIMALS) / totalSupply; // results in 44,31554 %
assertEq(utilization, 4431);
uint256 borrowRate = LiquidityCalcs.calcBorrowRateFromUtilization(
resolver.getRateConfig(NATIVE_TOKEN_ADDRESS),
utilization
);
assertEq(borrowRate, 732); // expected borrow rate at ~44,31% utilization
exchangePricesAndConfig = _simulateExchangePricesWithRatesAndRatios(
resolver,
NATIVE_TOKEN_ADDRESS,
supplyExchangePrice,
borrowExchangePrice,
utilization,
borrowRate,
block.timestamp,
0,
0
);
}
_setTestOperateParams(
NATIVE_TOKEN_ADDRESS,
-int256(DEFAULT_WITHDRAW_AMOUNT),
-int256(DEFAULT_PAYBACK_AMOUNT),
alice,
alice,
address(0),
totalAmounts,
exchangePricesAndConfig,
supplyExchangePrice,
borrowExchangePrice,
_simulateUserSupplyData(
resolver,
address(mockProtocol),
NATIVE_TOKEN_ADDRESS,
totalSupplyRawInterest,
0, // previous limit
block.timestamp
),
userBorrowData,
true
);
}
}
contract LiquidityUserModuleWithdrawAndPaybackTestSuiteInterestFreeNative is LiquidityUserModuleOperateTestSuite {
function setUp() public virtual override {
super.setUp();
_setUserAllowancesDefaultInterestFree(address(liquidity), admin, NATIVE_TOKEN_ADDRESS, address(mockProtocol));
// alice supplies liquidity
_supplyNative(mockProtocol, alice, DEFAULT_SUPPLY_AMOUNT);
// alice borrows liquidity
_borrowNative(mockProtocol, alice, DEFAULT_BORROW_AMOUNT);
// simulate passing time 1 year to get a better predicatable borrow rate and amounts
vm.warp(block.timestamp + PASS_1YEAR_TIME);
// exchange prices are not changing because of interest free mode
uint256 supplyExchangePrice = EXCHANGE_PRICES_PRECISION;
uint256 borrowExchangePrice = EXCHANGE_PRICES_PRECISION;
uint256 totalAmounts;
uint256 totalSupply = DEFAULT_SUPPLY_AMOUNT - DEFAULT_WITHDRAW_AMOUNT;
uint256 exchangePricesAndConfig;
{
uint256 defaultBorrowAmountAfterRounding = 500000000000000008; // BigMath round up at borrow leads to minor difference
uint256 totalBorrow = defaultBorrowAmountAfterRounding - DEFAULT_PAYBACK_AMOUNT;
totalAmounts = _simulateTotalAmounts(0, totalSupply, 0, totalBorrow);
// utilization AFTER payback
uint256 utilization = (totalBorrow * FOUR_DECIMALS) / totalSupply; // results in 40%
assertEq(utilization, 4000);
uint256 borrowRate = LiquidityCalcs.calcBorrowRateFromUtilization(
resolver.getRateConfig(NATIVE_TOKEN_ADDRESS),
utilization
);
assertEq(borrowRate, 700); // expected borrow rate at 40% utilization
exchangePricesAndConfig = _simulateExchangePricesWithRatesAndRatios(
resolver,
NATIVE_TOKEN_ADDRESS,
supplyExchangePrice,
borrowExchangePrice,
utilization,
borrowRate,
block.timestamp,
1, // supplyRatio = 1 for mode set to total supply with interest < interest free
1 // borrowRatio = 1 for mode set to total supply with interest < interest free
);
}
uint256 userSupplyData = _simulateUserSupplyData(
resolver,
address(mockProtocol),
NATIVE_TOKEN_ADDRESS,
totalSupply,
0, // previous limit
block.timestamp
);
_setTestOperateParams(
NATIVE_TOKEN_ADDRESS,
-int256(DEFAULT_WITHDRAW_AMOUNT),
-int256(DEFAULT_PAYBACK_AMOUNT),
alice,
alice,
address(0),
totalAmounts,
exchangePricesAndConfig,
supplyExchangePrice,
borrowExchangePrice,
userSupplyData,
_simulateUserBorrowData(
resolver,
address(mockProtocol),
NATIVE_TOKEN_ADDRESS,
DEFAULT_BORROW_AMOUNT_AFTER_BIGMATH - DEFAULT_PAYBACK_AMOUNT,
DEFAULT_BASE_DEBT_CEILING_AFTER_BIGMATH, // base borrow limit will be set as previous limit
block.timestamp
),
true
);
}
}