В процессе знакомства с новым конкурсным проектом заметил новый для себя способ написания тестов, о котором самое время рассказать в рамках этого цикла постов.
Во всех уроках и видео нам говорят, что тесты в Foundry пишутся с пустыми аргументами в функциях, например:
function testIncremet() public {}
А если мы указываем аргументы, то это уже получается фаззинг, в котором Foundry сам подставляет нужные значения.
В протоколе Morpho пошли немного дальше и попытались как бы объединить об этих способа.
У них есть тест для проверки исполнения функции займа:
function testBorrowAssets(
uint256 amountCollateral,
uint256 amountSupplied,
uint256 amountBorrowed,
uint256 priceCollateral
) public {
(amountCollateral, amountBorrowed, priceCollateral) =
_boundHealthyPosition(amountCollateral, amountBorrowed, priceCollateral);
amountSupplied = bound(amountSupplied, amountBorrowed, MAX_TEST_AMOUNT);
_supply(amountSupplied);
oracle.setPrice(priceCollateral);
collateralToken.setBalance(BORROWER, amountCollateral);
vm.startPrank(BORROWER);
morpho.supplyCollateral(marketParams, amountCollateral, BORROWER, hex"");
uint256 expectedBorrowShares = amountBorrowed.toSharesUp(0, 0);
(uint256 returnAssets, uint256 returnShares) =
morpho.borrow(marketParams, amountBorrowed, 0, BORROWER, RECEIVER);
vm.stopPrank();
...
}
И в значения аргументов этой функции записываются результаты работы другой служебной функции из контракта помощника:
function _boundHealthyPosition(uint256 amountCollateral, uint256 amountBorrowed, uint256 priceCollateral)
internal
view
returns (uint256, uint256, uint256)
{
priceCollateral = bound(priceCollateral, MIN_COLLATERAL_PRICE, MAX_COLLATERAL_PRICE);
amountBorrowed = bound(amountBorrowed, MIN_TEST_AMOUNT, MAX_TEST_AMOUNT);
uint256 minCollateral = amountBorrowed.wDivUp(marketParams.lltv).mulDivUp(ORACLE_PRICE_SCALE, priceCollateral);
if (minCollateral <= MAX_COLLATERAL_ASSETS) {
amountCollateral = bound(amountCollateral, minCollateral, MAX_COLLATERAL_ASSETS);
} else {
amountCollateral = MAX_COLLATERAL_ASSETS;
amountBorrowed = Math.min(
amountBorrowed.wMulDown(marketParams.lltv).mulDivDown(priceCollateral, ORACLE_PRICE_SCALE),
MAX_TEST_AMOUNT
);
}
vm.assume(amountBorrowed > 0);
vm.assume(amountCollateral < type(uint256).max / priceCollateral);
return (amountCollateral, amountBorrowed, priceCollateral);
}
Тут они ограничиваются необходимыми рамками, делаются дополнительные проверки и готовые значения передаются для тестов.
На мой взгляд достаточно интересное решение вместо того, чтобы городить полотна кода.
Посмотреть их тесты и разобраться самим можно по ссылке на их репо.
P.S. Репо открыт на время конкурса, не уверен, что будет в доступе постоянно.
#foundry #lesson32