wormhole-lending-examples/evm/test/CrossChainBorrowLend.t.sol

244 lines
8.1 KiB
Solidity

// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.0;
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import {NormalizedAmounts, NormalizedTotalAmounts} from "../src/CrossChainBorrowLendStructs.sol";
import {ExposedCrossChainBorrowLend} from "./helpers/ExposedCrossChainBorrowLend.sol";
import {MyERC20} from "./helpers/MyERC20.sol";
import "forge-std/Test.sol";
import "forge-std/console.sol";
contract CrossChainBorrowLendTest is Test {
MyERC20 collateralToken;
MyERC20 borrowedAssetToken;
ExposedCrossChainBorrowLend borrowLendContract;
bytes32 collateralAssetPythId;
bytes32 borrowingAssetPythId;
uint256 collateralizationRatio;
function setUp() public {
address wormholeAddress = msg.sender;
address mockPythAddress = msg.sender;
bytes32 targetContractAddress = 0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef;
collateralToken = new MyERC20("WBNB", "WBNB", 18);
borrowedAssetToken = new MyERC20("USDC", "USDC", 6);
// 80%
collateralizationRatio = 0.8e18;
// TODO
borrowLendContract = new ExposedCrossChainBorrowLend(
wormholeAddress,
1, // consistencyLevel
mockPythAddress,
2, // targetChainId (ethereum)
targetContractAddress,
address(collateralToken), // collateralAsset
collateralAssetPythId,
collateralizationRatio,
address(borrowedAssetToken),
borrowingAssetPythId,
5 * 60 // gracePeriod (5 minutes)
);
}
function testComputeInterestProportion() public {
// start from zero
vm.warp(0);
uint256 timeStart = block.timestamp;
// warp to 1 year in the future
vm.warp(365 * 24 * 60 * 60);
uint256 secondsElapsed = block.timestamp - timeStart;
// accrue interest with intercept and coefficient
uint256 intercept = 0.02e18; // 2% starting rate
uint256 coefficient = 0.001e18; // increase 10 basis points per 1% borrowed
// fake supply some amount
uint256 deposited = 100e6; // 100 USDC (6 decimals)
borrowLendContract.HACKED_setTotalAssetsDeposited(deposited);
// fake borrow some amount
uint256 borrowed = 50e6; // 50 USDC (6 decimals)
borrowLendContract.HACKED_setTotalAssetsBorrowed(borrowed);
// we expect the interest accrued equal to the intercept
uint256 interestProportion = borrowLendContract
.EXPOSED_computeInterestProportion(
secondsElapsed,
intercept,
coefficient
);
// expect using the correct value (0.0205e18)
{
require(
interestProportion == 0.0205e18,
"interestProportion != expected"
);
}
// expect using calculation
{
uint256 expected = intercept + (coefficient * borrowed) / deposited;
require(
interestProportion == expected,
"interestProportion != expected (computed)"
);
}
// clear
borrowLendContract.HACKED_setTotalAssetsDeposited(0);
borrowLendContract.HACKED_setTotalAssetsBorrowed(0);
}
function testUpdateInterestAccrualIndex() public {
// start from zero
vm.warp(0);
borrowLendContract.HACKED_setLastActivityBlockTimestamp(
block.timestamp
);
// fake supply some amount
uint256 deposited = 200e6; // 200 USDC (6 decimals)
borrowLendContract.HACKED_setTotalAssetsDeposited(deposited);
// fake borrow some amount
uint256 borrowed = 20e6; // 20 USDC (6 decimals)
borrowLendContract.HACKED_setTotalAssetsBorrowed(borrowed);
// warp to 1 year in the future
vm.warp(365 * 24 * 60 * 60);
// trigger accrual
borrowLendContract.EXPOSED_updateInterestAccrualIndex();
{
// expect using the correct value (1.02e18)
require(
borrowLendContract.borrowedInterestAccrualIndex() == 1.02e18,
"borrowedInterestAccrualIndex() != expected (first iteration)"
);
// expect using the correct value (1.002e18)
require(
borrowLendContract.collateralInterestAccrualIndex() == 1.002e18,
"collateralInterestAccrualIndex() != expected (first iteration)"
);
}
// warp to 2 years in the future
vm.warp(2 * 365 * 24 * 60 * 60);
// trigger accrual again
borrowLendContract.EXPOSED_updateInterestAccrualIndex();
{
// expect using the correct value (1.04e18)
require(
borrowLendContract.borrowedInterestAccrualIndex() == 1.04e18,
"borrowedInterestAccrualIndex() != expected (second iteration)"
);
// expect using the correct value (1.004e18)
require(
borrowLendContract.collateralInterestAccrualIndex() == 1.004e18,
"collateralInterestAccrualIndex() != expected (second iteration)"
);
}
// check denormalized deposit and borrowed. should be equal
{
NormalizedTotalAmounts memory amounts = borrowLendContract
.normalizedAmounts();
uint256 accruedDepositedInterest = borrowLendContract
.denormalizeAmount(
amounts.deposited,
borrowLendContract.collateralInterestAccrualIndex()
) - deposited;
uint256 accruedBorrowedInterest = borrowLendContract
.denormalizeAmount(
amounts.borrowed,
borrowLendContract.borrowedInterestAccrualIndex()
) - borrowed;
require(
accruedDepositedInterest == accruedBorrowedInterest,
"accruedDepositedInterest != accruedBorrowedInterest"
);
}
// clear
borrowLendContract.HACKED_setTotalAssetsDeposited(0);
borrowLendContract.HACKED_setTotalAssetsBorrowed(0);
}
function testMaxAllowedToWithdraw() public {
uint64 collateralPrice = 400; // WBNB
uint64 borrowAssetPrice = 1; // USDC
uint256 deposited = 1e18; // 1 WBNB (18 decimals)
borrowLendContract.HACKED_setAccountAssetsDeposited(
msg.sender,
deposited
);
uint256 borrowed = 100e6; // 100 USDC (6 decimals)
borrowLendContract.HACKED_setAccountAssetsBorrowed(
msg.sender,
borrowed
);
uint256 maxAllowed = borrowLendContract
.EXPOSED_maxAllowedToWithdrawWithPrices(
msg.sender,
collateralPrice,
borrowAssetPrice
);
// expect 0.6875e18 (0.6875 WBNB)
{
require(maxAllowed == 0.6875e18, "maxAllowed != expected");
}
// clear
borrowLendContract.HACKED_setAccountAssetsDeposited(msg.sender, 0);
borrowLendContract.HACKED_setAccountAssetsBorrowed(msg.sender, 0);
}
function testMaxAllowedToBorrow() public {
uint64 collateralPrice = 400; // WBNB
uint64 borrowAssetPrice = 1; // USDC
uint256 deposited = 1e18; // 1 WBNB (18 decimals)
borrowLendContract.HACKED_setAccountAssetsDeposited(
msg.sender,
deposited
);
uint256 borrowed = 100e6; // 100 USDC (6 decimals)
borrowLendContract.HACKED_setAccountAssetsBorrowed(
msg.sender,
borrowed
);
uint256 maxAllowed = borrowLendContract
.EXPOSED_maxAllowedToBorrowWithPrices(
msg.sender,
collateralPrice,
borrowAssetPrice
);
// expect 220e6 (220 USDC)
{
require(maxAllowed == 220e6, "maxAllowed != expected");
}
// clear
borrowLendContract.HACKED_setAccountAssetsDeposited(msg.sender, 0);
borrowLendContract.HACKED_setAccountAssetsBorrowed(msg.sender, 0);
}
}