Skip to content

Commit bc24cd2

Browse files
fix: Dynamically calculate asset amounts
1 parent 80490d8 commit bc24cd2

File tree

3 files changed

+68
-32
lines changed

3 files changed

+68
-32
lines changed

tests/Base.t.sol

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -747,6 +747,27 @@ abstract contract Base is Test {
747747
}
748748
}
749749

750+
/// returns the USD value of the reserve normalized by it's decimals, in terms of WAD
751+
function _getValueInBaseCurrency(
752+
uint256 assetId,
753+
uint256 amount
754+
) internal view returns (uint256) {
755+
return
756+
(amount * oracle.getAssetPrice(assetId).wadify()) /
757+
(10 ** hub.getAssetConfig(assetId).decimals);
758+
}
759+
760+
/// @dev Helper function to calculate the equivalent asset amount for a given asset
761+
function _calcEquivalentAssetAmount(
762+
uint256 inputAssetId,
763+
uint256 inputAssetAmount,
764+
uint256 outputAssetId
765+
) internal view returns (uint256) {
766+
uint256 valueOfInputAsset = _getValueInBaseCurrency(inputAssetId, inputAssetAmount);
767+
uint256 valueOfWeiOutput = _getValueInBaseCurrency(outputAssetId, 1);
768+
return valueOfInputAsset / valueOfWeiOutput;
769+
}
770+
750771
/// @dev Helper function to calculate the amount of base and premium debt to restore
751772
// @return baseDebtRestored amount of base debt to restore
752773
// @return premiumDebtRestored amount of premium debt to restore

tests/unit/Spoke/Spoke.RiskPremium.EdgeCases.t.sol

Lines changed: 47 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ contract SpokeRiskPremiumEdgeCasesTest is SpokeBase {
8282
);
8383
}
8484

85-
/// Supply dai2 and dai as collateral, borrow dai2, then remove dai as collateral and risk premium should increase
85+
/// Supply two collaterals, borrow, then remove lower LP collateral and risk premium should increase
8686
function test_riskPremium_increasesAfterCollateralRemoval(
8787
uint256 daiSupplyAmount,
8888
uint256 borrowAmount
@@ -137,7 +137,7 @@ contract SpokeRiskPremiumEdgeCasesTest is SpokeBase {
137137
);
138138
}
139139

140-
/// Supply dai2 and dai as collateral, borrow dai2, then withdraw dai as collateral and risk premium should increase
140+
/// Supply two collaterals, borrow, then withdraw lower LP collateral and risk premium should increase
141141
function test_riskPremium_increasesAfterWithdrawal(
142142
uint256 daiSupplyAmount,
143143
uint256 borrowAmount
@@ -193,7 +193,7 @@ contract SpokeRiskPremiumEdgeCasesTest is SpokeBase {
193193
);
194194
}
195195

196-
/// Supply dai2 and dai as collateral, borrow dai2, then fuzz withdraw dai as collateral and risk premium should increase or remain the same
196+
/// Supply two collaterals, borrow, then fuzz withdraw lower LP collateral and risk premium should increase or remain the same
197197
function test_riskPremium_fuzz_nonDecreasingAfterWithdrawal(
198198
uint256 daiSupplyAmount,
199199
uint256 borrowAmount,
@@ -256,7 +256,11 @@ contract SpokeRiskPremiumEdgeCasesTest is SpokeBase {
256256
function test_riskPremium_decreasesAfterCollateralAccrual() public {
257257
uint256 wbtcSupplyAmount = 1e8;
258258
uint256 wethSupplyAmount = 100e18;
259-
uint256 daiBorrowAmount = 50500e18; // More than price of 1 wbtc
259+
uint256 daiBorrowAmount = _calcEquivalentAssetAmount(
260+
wbtcAssetId,
261+
wbtcSupplyAmount,
262+
daiAssetId
263+
) + 500e18; // More than the value of wbtc collateral
260264

261265
// Deploy liquidity for dai borrow
262266
_deployLiquidity(spoke1, _daiReserveId(spoke1), MAX_SUPPLY_AMOUNT);
@@ -353,16 +357,18 @@ contract SpokeRiskPremiumEdgeCasesTest is SpokeBase {
353357
);
354358
}
355359

356-
/// Debt (weth) is initially covered by 2 collaterals (dai + dai2), then 1 collateral becomes enough to cover the debt due to interest accrual
360+
/// Debt is initially covered by 2 collaterals, then 1 collateral becomes enough to cover the debt due to interest accrual
357361
function test_riskPremium_fuzz_nonIncreasesAfterCollateralAccrual(
358362
uint256 daiSupplyAmount,
359363
uint40 skipTime
360364
) public {
361365
daiSupplyAmount = bound(daiSupplyAmount, 1e18, MAX_SUPPLY_AMOUNT / 2 - 1); // Leave room for Alice to borrow 1 dai
362366
// Determine value of daiSupplyAmount in weth terms
363-
uint256 valueOfSuppliedDai = _getValueInBaseCurrency(daiAssetId, daiSupplyAmount);
364-
uint256 valueOfWeiWeth = _getValueInBaseCurrency(wethAssetId, 1);
365-
uint256 wethBorrowAmount = (valueOfSuppliedDai / valueOfWeiWeth) + 1; // Borrow more than dai supply value so 2 collaterals cover debt
367+
uint256 wethBorrowAmount = _calcEquivalentAssetAmount(
368+
daiAssetId,
369+
daiSupplyAmount,
370+
wethAssetId
371+
) + 1; // Borrow more than dai supply value so 2 collaterals cover debt
366372
uint256 dai2SupplyAmount = MAX_SUPPLY_AMOUNT;
367373
skipTime = uint40(bound(skipTime, 365 days, MAX_SKIP_TIME)); // At least skip one year to ensure sufficient accrual
368374

@@ -442,8 +448,8 @@ contract SpokeRiskPremiumEdgeCasesTest is SpokeBase {
442448
// Bob's current risk premium should be greater than or equal liquidity premium of dai, since debt is not fully covered by it (and due to rounding)
443449
assertGt(
444450
_getValueInBaseCurrency(wethAssetId, wethBorrowAmount),
445-
valueOfSuppliedDai,
446-
'Weth borrow amount'
451+
_getValueInBaseCurrency(daiAssetId, daiSupplyAmount),
452+
'Weth borrow amount greater than dai supply amount'
447453
);
448454
assertGe(
449455
spoke2.getUserRiskPremium(bob),
@@ -470,11 +476,11 @@ contract SpokeRiskPremiumEdgeCasesTest is SpokeBase {
470476
);
471477
}
472478

473-
/// Bob's debt initially fully covered by wbtc collateral. Then interest accrues, so debt must be covered by 2 collaterals
479+
/// Bob's debt initially fully covered by one collateral. Then debt interest accrues, so debt must be covered by 2 collaterals
474480
function test_riskPremium_increasesAfterDebtAccrual() public {
475481
uint256 wbtcSupplyAmount = 1e8;
476482
uint256 wethSupplyAmount = 100e18;
477-
uint256 daiBorrowAmount = 50000e18; // The price of 1 wbtc
483+
uint256 daiBorrowAmount = _calcEquivalentAssetAmount(wbtcAssetId, wbtcSupplyAmount, daiAssetId); // Dai debt to equal wbtc supply value
478484

479485
// Deploy liquidity for dai borrow
480486
_deployLiquidity(spoke1, _daiReserveId(spoke1), daiBorrowAmount);
@@ -538,13 +544,21 @@ contract SpokeRiskPremiumEdgeCasesTest is SpokeBase {
538544
);
539545
}
540546

541-
/// Bob's weth debt initially fully covered by dai collateral. Then interest accrues, so debt must be covered by 2 collaterals (dai + dai2)
547+
/// Debt initially fully covered by one collateral. Then debt interest accrues, so debt must be covered by 2 collaterals
542548
function test_riskPremium_fuzz_increasesAfterDebtAccrual(
543549
uint256 borrowAmount,
544550
uint40 skipTime
545551
) public {
546-
borrowAmount = bound(borrowAmount, 1e18, MAX_SUPPLY_AMOUNT / 4000); // Allow room for dai supply to cover weth debt (2000x)
547-
uint256 daiSupplyAmount = borrowAmount * 2000; // Dai collateral will fully cover initial borrow (weth = 2000 dai)
552+
// Find max supply amount of dai in terms of weth
553+
uint256 maxWethDebt = _calcEquivalentAssetAmount(daiAssetId, MAX_SUPPLY_AMOUNT, wethAssetId);
554+
assertLt(
555+
maxWethDebt,
556+
MAX_SUPPLY_AMOUNT / 2,
557+
'Max weth debt should be less than half max supply amount'
558+
);
559+
borrowAmount = bound(borrowAmount, 1e18, maxWethDebt); // Allow room for dai supply to cover weth debt
560+
// Determine value of borrowAmount in dai terms so dai collateral can fully cover weth debt
561+
uint256 daiSupplyAmount = _calcEquivalentAssetAmount(wethAssetId, borrowAmount, daiAssetId);
548562
uint256 dai2SupplyAmount = MAX_SUPPLY_AMOUNT;
549563
skipTime = uint40(bound(skipTime, 365 days, MAX_SKIP_TIME)); // At least skip one year to ensure sufficient accrual
550564

@@ -613,7 +627,7 @@ contract SpokeRiskPremiumEdgeCasesTest is SpokeBase {
613627
function test_riskPremium_changesAfterAccrual() public {
614628
uint256 wethSupplyAmount = 2e18;
615629
uint256 daiSupplyAmount = 10000e18;
616-
uint256 daiBorrowAmount = 4000e18; // The price of 2 eth
630+
uint256 daiBorrowAmount = _calcEquivalentAssetAmount(wethAssetId, wethSupplyAmount, daiAssetId); // Dai debt to equal weth supply value
617631

618632
// Bob supplies weth and dai collaterals
619633
Utils.supplyCollateral({
@@ -690,14 +704,21 @@ contract SpokeRiskPremiumEdgeCasesTest is SpokeBase {
690704
);
691705
}
692706

693-
/// Initially debt (weth) is covered by 1 collateral (dai), both debt and collateral accrue at different rates, such that finally debt is covered by 2 collaterals
707+
/// Initially debt is covered by 1 collateral, both debt and collateral accrue at different rates, such that finally debt is covered by 2 collaterals
694708
function test_riskPremium_fuzz_changesAfterAccrual(
695709
uint256 wethBorrowAmount,
696710
uint40 skipTime
697711
) public {
698712
uint256 dai2SupplyAmount = MAX_SUPPLY_AMOUNT;
699-
wethBorrowAmount = bound(wethBorrowAmount, 1e18, MAX_SUPPLY_AMOUNT / 4000); // Allow room for dai supply to cover weth debt (2000x)
700-
uint256 daiSupplyAmount = wethBorrowAmount * 2000; // Dai collateral will fully cover initial borrow (weth = 2000 dai)
713+
// Find max supply amount of dai in terms of weth
714+
uint256 maxWethDebt = _calcEquivalentAssetAmount(daiAssetId, MAX_SUPPLY_AMOUNT, wethAssetId);
715+
assertLe(
716+
maxWethDebt,
717+
MAX_SUPPLY_AMOUNT / 2,
718+
'Max weth debt should be less than half max supply amount'
719+
);
720+
wethBorrowAmount = bound(wethBorrowAmount, 1e18, maxWethDebt); // Allow room for dai supply to cover weth debt
721+
uint256 daiSupplyAmount = _calcEquivalentAssetAmount(wethAssetId, wethBorrowAmount, daiAssetId); // Dai collateral will fully cover initial weth borrow
701722
skipTime = uint40(bound(skipTime, 365 days, MAX_SKIP_TIME)); // At least skip one year to ensure sufficient accrual
702723

703724
// Deal bob dai to cover dai and dai2 supply
@@ -785,7 +806,7 @@ contract SpokeRiskPremiumEdgeCasesTest is SpokeBase {
785806
function test_riskPremium_borrowingMoreIncreasesRP() public {
786807
uint256 wbtcSupplyAmount = 1e8;
787808
uint256 wethSupplyAmount = 100e18;
788-
uint256 daiBorrowAmount = 50000e18; // The price of 1 wbtc
809+
uint256 daiBorrowAmount = _calcEquivalentAssetAmount(wbtcAssetId, wbtcSupplyAmount, daiAssetId); // Dai debt to equal wbtc supply value
789810
uint256 additionalDaiBorrowAmount = 1000e18;
790811

791812
// Deploy liquidity for dai borrow
@@ -852,7 +873,7 @@ contract SpokeRiskPremiumEdgeCasesTest is SpokeBase {
852873
);
853874
}
854875

855-
/// Initially debt is covered by 1 collateral (dai), then due to borrowing more, debt is covered by 2 collaterals (dai + dai2)
876+
/// Initially debt is covered by 1 collateral, then due to borrowing more, debt is covered by 2 collaterals
856877
function test_riskPremium_fuzz_borrowingMoreNonDecreasesRP(
857878
uint256 initialBorrowAmount,
858879
uint256 additionalBorrowAmount
@@ -933,7 +954,11 @@ contract SpokeRiskPremiumEdgeCasesTest is SpokeBase {
933954
function test_riskPremium_supplyingLowerLPCollateral_decreasesRP() public {
934955
uint256 wbtcSupplyAmount = 1e8;
935956
uint256 wethSupplyAmount = 10e18;
936-
uint256 daiBorrowAmount = 10000e18; // The price of 5 weth
957+
uint256 daiBorrowAmount = _calcEquivalentAssetAmount(
958+
wethAssetId,
959+
wethSupplyAmount / 2,
960+
daiAssetId
961+
); // Half of the weth collateral value
937962

938963
// Deploy liquidity for dai borrow
939964
_deployLiquidity(spoke1, _daiReserveId(spoke1), daiBorrowAmount);

tests/unit/Spoke/SpokeBase.t.sol

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -401,16 +401,6 @@ contract SpokeBase is Base {
401401
return maxDebt > 1 ? maxDebt - 1 : maxDebt;
402402
}
403403

404-
/// returns the USD value of the reserve normalized by it's decimals, in terms of WAD
405-
function _getValueInBaseCurrency(
406-
uint256 assetId,
407-
uint256 amount
408-
) internal view returns (uint256) {
409-
return
410-
(amount * oracle.getAssetPrice(assetId).wadify()) /
411-
(10 ** hub.getAssetConfig(assetId).decimals);
412-
}
413-
414404
// assert that user's position and debt accounting matches expected
415405
function _assertUserPositionAndDebt(
416406
ISpoke spoke,

0 commit comments

Comments
 (0)