Skip to content

fix : prevent key collision on KeyValueList add()#901

Merged
miguelmtzinf merged 16 commits intomainfrom
fix/kvl-add-check
Oct 16, 2025
Merged

fix : prevent key collision on KeyValueList add()#901
miguelmtzinf merged 16 commits intomainfrom
fix/kvl-add-check

Conversation

@Kogaroshi
Copy link
Contributor

@Kogaroshi Kogaroshi commented Oct 13, 2025

  • Prevent key collision on KeyValueList add() function by requiring key < _MAX_KEY (instead of <=)
  • This issue anyway should not be present in the current Spoke version, because we are using uint24 for the key (and max _MAX_KEY is 2**32-1).

Fixes #900

@codecov
Copy link

codecov bot commented Oct 13, 2025

The author of this PR, Kogaroshi, is not an activated member of this organization on Codecov.
Please activate this user on Codecov to display this PR comment.
Coverage data is still being uploaded to Codecov.io for purposes of overall coverage calculations.
Please don't hesitate to email us at support@codecov.io with any questions.

@github-actions
Copy link

github-actions bot commented Oct 13, 2025

♻️ Forge Gas Snapshots

Path Value
snapshots/Spoke.Getters.json
getUserAccountData: supplies: 1, borrows: 0 ↓0% (-6) 47,254
getUserAccountData: supplies: 2, borrows: 0 ↓0% (-12) 77,459
getUserAccountData: supplies: 2, borrows: 1 ↓0% (-12) 98,200
getUserAccountData: supplies: 2, borrows: 2 ↓0% (-12) 117,595
snapshots/Spoke.Operations.ZeroRiskPremium.json
borrow: first ↓0% (-6) 199,032
borrow: second action, same reserve ↓0% (-6) 179,553
liquidationCall: full ↓0% (-12) 291,015
liquidationCall: partial ↓0% (-12) 315,109
permitReserve + repay (multicall) ↓0% (-6) 235,800
repay: full ↓0% (-6) 151,764
repay: partial ↓0% (-6) 176,227
updateUserRiskPremium: 1 borrow ↓0% (-6) 95,276
updateUserRiskPremium: 2 borrows ↓0% (-6) 111,368
usingAsCollateral: 1 borrow, disable ↓0% (-6) 105,523
usingAsCollateral: 2 borrows, disable ↓0% (-6) 127,988
withdraw: 0 borrows, partial ↓0% (-6) 132,783
withdraw: 1 borrow, partial ↓0% (-6) 161,765
withdraw: 2 borrows, partial ↓0% (-6) 184,218
snapshots/Spoke.Operations.json
borrow: first ↓0% (-6) 269,201
borrow: second action, same reserve ↓0% (-6) 212,722
liquidationCall: full ↓0% (-12) 324,401
liquidationCall: partial ↓0% (-12) 348,495
permitReserve + repay (multicall) ↓0% (-6) 269,179
repay: full ↓0% (-6) 146,405
repay: partial ↓0% (-6) 209,606
updateUserRiskPremium: 1 borrow ↓0% (-6) 177,363
updateUserRiskPremium: 2 borrows ↓0% (-6) 262,728
usingAsCollateral: 1 borrow, disable ↓0% (-6) 187,610
usingAsCollateral: 2 borrows, disable ↓0% (-6) 287,347
withdraw: 0 borrows, partial ↓0% (-6) 132,783
withdraw: 1 borrow, partial ↓0% (-6) 241,352
withdraw: 2 borrows, partial ↓0% (-6) 341,078
🔕 Unchanged
Path Value
snapshots/Hub.Operations.json
add 113,832
draw 122,026
eliminateDeficit: full 57,818
eliminateDeficit: partial 67,394
payFee 73,744
refreshPremium 96,823
remove: full 75,059
remove: partial 80,306
reportDeficit 118,722
restore: full 97,460
restore: partial 110,890
transferShares 79,425
snapshots/Spoke.Getters.json
getUserAccountData: supplies: 0, borrows: 0 12,164
snapshots/Spoke.Operations.ZeroRiskPremium.json
permitReserve + supply (multicall) 141,050
permitReserve + supply + enable collateral (multicall) 176,287
setUserPositionManagerWithSig: disable 44,918
setUserPositionManagerWithSig: enable 68,947
supply + enable collateral (multicall) 154,229
supply: 0 borrows, collateral disabled 115,784
supply: 0 borrows, collateral enabled 120,181
supply: 1 borrow 120,173
supply: second action, same reserve 103,081
updateUserDynamicConfig: 1 collateral 73,761
updateUserDynamicConfig: 2 collaterals 88,621
usingAsCollateral: 0 borrows, enable 58,976
usingAsCollateral: 1 borrow, enable 32,298
usingAsCollateral: 2 borrows, enable 41,876
withdraw: 0 borrows, full 127,742
withdraw: non collateral 126,851
snapshots/Spoke.Operations.json
permitReserve + supply (multicall) 141,050
permitReserve + supply + enable collateral (multicall) 176,287
setUserPositionManagerWithSig: disable 44,918
setUserPositionManagerWithSig: enable 68,947
supply + enable collateral (multicall) 154,229
supply: 0 borrows, collateral disabled 115,784
supply: 0 borrows, collateral enabled 120,181
supply: 1 borrow 120,173
supply: second action, same reserve 103,081
updateUserDynamicConfig: 1 collateral 73,761
updateUserDynamicConfig: 2 collaterals 88,621
usingAsCollateral: 0 borrows, enable 58,976
usingAsCollateral: 1 borrow, enable 32,298
usingAsCollateral: 2 borrows, enable 41,876
withdraw: 0 borrows, full 127,742
withdraw: non collateral 126,851
@github-actions
Copy link

github-actions bot commented Oct 13, 2025

Forge Build Sizes

Contract Runtime Size (B) Initcode Size (B) Runtime Margin (B) Initcode Margin (B)
MockSpokeInstance ↑0% (+47) 24,127 ↑0% (+47) 24,935 ↓9% (-47) 449 ↓0% (-47) 24,217
NativeTokenGateway ↑2% (+78) 4,869 ↑1% (+78) 5,398 ↓0% (-78) 19,707 ↓0% (-78) 43,754
SignatureGateway ↑1% (+64) 9,835 ↑1% (+64) 10,571 ↓0% (-64) 14,741 ↓0% (-64) 38,581
SpokeInstance ↑0% (+47) 24,065 ↑0% (+47) 24,801 ↓8% (-47) 511 ↓0% (-47) 24,351
TreasurySpoke ↑2% (+41) 2,329 ↑2% (+41) 2,730 ↓0% (-41) 22,247 ↓0% (-41) 46,422
KeyValueListWrapper 802 830 23,774 48,322
🔕 Unchanged
Contract Runtime Size (B) Initcode Size (B) Runtime Margin (B) Initcode Margin (B)
AaveOracle 1,842 2,580 22,734 46,572
AccessManager 10,198 11,423 14,378 37,729
Address 44 94 24,532 49,058
Arrays 44 94 24,532 49,058
AssetInterestRateStrategy 2,349 2,534 22,227 46,618
AssetLogic 44 94 24,532 49,058
AuthorityUtils 44 94 24,532 49,058
Bytes 44 94 24,532 49,058
Comparators 44 94 24,532 49,058
Constants 378 430 24,198 48,722
ECDSA 44 94 24,532 49,058
EIP712Types 44 94 24,532 49,058
ERC1967Proxy 122 934 24,454 48,218
ERC1967Utils 44 94 24,532 49,058
EnumerableSet 44 94 24,532 49,058
Errors 44 94 24,532 49,058
Hub 20,306 20,540 4,270 28,612
HubConfigurator 9,004 9,277 15,572 39,875
JsonBindings 9,244 9,296 15,332 39,856
KeyValueList 44 94 24,532 49,058
LibBit 44 94 24,532 49,058
LiquidationLogic 4,980 5,032 19,596 44,120
LiquidationLogicWrapper 8,354 8,382 16,222 40,770
Math 44 94 24,532 49,058
MathUtils 44 94 24,532 49,058
MockERC1271Wallet 599 733 23,977 48,419
MockERC20 1,913 2,379 22,663 46,773
MockPriceFeed 642 1,300 23,934 47,852
NoncesKeyed 624 652 23,952 48,500
NoncesKeyedMock 735 763 23,841 48,389
Panic 44 94 24,532 49,058
PercentageMath 44 94 24,532 49,058
PercentageMathWrapper 592 620 23,984 48,532
PositionStatusMap 44 94 24,532 49,058
PositionStatusMapWrapper 2,407 2,435 22,169 46,717
ProxyAdmin 977 1,213 23,599 47,939
RescuableWrapper 770 904 23,806 48,248
Roles 153 203 24,423 48,949
SafeCast 44 94 24,532 49,058
SafeERC20 44 94 24,532 49,058
SharesMath 44 94 24,532 49,058
SignatureChecker 44 94 24,532 49,058
SlotDerivation 44 94 24,532 49,058
SpokeConfigurator 7,259 7,532 17,317 41,620
StorageSlot 44 94 24,532 49,058
TestnetERC20 2,810 3,686 21,766 45,466
Time 44 94 24,532 49,058
TransientSlot 44 94 24,532 49,058
TransparentUpgradeableProxy 1,073 3,445 23,503 45,707
UnitPriceFeed 662 1,596 23,914 47,556
Utils 44 94 24,532 49,058
WETH9 1,864 2,330 22,712 46,822
WadRayMath 44 94 24,532 49,058
WadRayMathWrapper 1,252 1,280 23,324 47,872
@github-actions
Copy link

github-actions bot commented Oct 13, 2025

🌈 Test Results
No files changed, compilation skipped

Ran 17 tests for tests/unit/AaveOracle.t.sol:AaveOracleTest
[PASS] test_constructor() (gas: 440456)
[PASS] test_decimals() (gas: 8387)
[PASS] test_deploy_revertsWith_InvalidAddress() (gas: 38089)
[PASS] test_description() (gas: 12094)
[PASS] test_fuzz_constructor(uint8) (runs: 5000, μ: 444413, ~: 444703)
[PASS] test_getReservePrice() (gas: 47409)
[PASS] test_getReservePrice_revertsWith_InvalidPrice() (gas: 46669)
[PASS] test_getReservePrice_revertsWith_InvalidSource() (gas: 10976)
[PASS] test_getReservePrices() (gas: 79551)
[PASS] test_getReservePrices_revertsWith_InvalidSource() (gas: 49352)
[PASS] test_getReserveSource() (gas: 47584)
[PASS] test_setReserveSource() (gas: 44466)
[PASS] test_setReserveSource_revertsWith_InvalidPrice() (gas: 97683)
[PASS] test_setReserveSource_revertsWith_InvalidSource() (gas: 15327)
[PASS] test_setReserveSource_revertsWith_InvalidSourceDecimals() (gas: 15149)
[PASS] test_setReserveSource_revertsWith_OnlySpoke() (gas: 11049)
[PASS] test_spoke() (gas: 10614)
Suite result: ok. 17 passed; 0 failed; 0 skipped; finished in 550.68ms (538.10ms CPU time)

Ran 23 tests for tests/unit/AssetInterestRateStrategy.t.sol:AssetInterestRateStrategyTest
[PASS] test_calculateInterestRate_AtKinkPoint() (gas: 24686)
Logs:
  Bound result 2000
  Bound result 778565440757296803935461404101

[PASS] test_calculateInterestRate_AtMaxUtilization() (gas: 24958)
Logs:
  Bound result 10000
  Bound result 778565440757296803935461404101

[PASS] test_calculateInterestRate_LeftToKinkPoint(uint256) (runs: 5000, μ: 24537, ~: 24690)
[PASS] test_calculateInterestRate_RightToKinkPoint(uint256) (runs: 5000, μ: 25653, ~: 25690)
[PASS] test_calculateInterestRate_ZeroDebtZeroLiquidity() (gas: 18944)
Logs:
  Bound result 0

[PASS] test_calculateInterestRate_fuzz_ZeroDebt(uint256) (runs: 5000, μ: 19167, ~: 18950)
[PASS] test_calculateInterestRate_revertsWith_InterestRateDataNotSet() (gas: 11361)
[PASS] test_deploy_revertsWith_InvalidAddress() (gas: 36318)
[PASS] test_getBaseVariableBorrowRate() (gas: 14864)
[PASS] test_getInterestRateData() (gas: 19653)
[PASS] test_getMaxVariableBorrowRate() (gas: 15312)
[PASS] test_getOptimalUsageRatio() (gas: 14735)
[PASS] test_getVariableRateSlope1() (gas: 14810)
[PASS] test_getVariableRateSlope2() (gas: 14877)
[PASS] test_maxBorrowRate() (gas: 8431)
[PASS] test_maxOptimalRatio() (gas: 8431)
[PASS] test_minOptimalRatio() (gas: 8440)
[PASS] test_setInterestRateData() (gas: 69812)
[PASS] test_setInterestRateData_revertsWith_InvalidMaxRate() (gas: 42072)
[PASS] test_setInterestRateData_revertsWith_InvalidOptimalUsageRatio() (gas: 43120)
[PASS] test_setInterestRateData_revertsWith_InvalidRateData() (gas: 35395)
[PASS] test_setInterestRateData_revertsWith_OnlyHub() (gas: 23786)
[PASS] test_setInterestRateData_revertsWith_Slope2MustBeGteSlope1() (gas: 37980)
Suite result: ok. 23 passed; 0 failed; 0 skipped; finished in 992.07ms (985.85ms CPU time)

Ran 6 tests for tests/unit/Hub/Hub.Access.t.sol:HubAccessTest
[PASS] test_change_authority() (gas: 2314465)
[PASS] test_change_role_responsibility() (gas: 101979)
[PASS] test_hub_access_manager_exposure() (gas: 12706)
[PASS] test_hub_admin_access() (gas: 1134214)
[PASS] test_migrate_role_responsibility() (gas: 397250)
[PASS] test_setInterestRateData_access() (gas: 101156)
Suite result: ok. 6 passed; 0 failed; 0 skipped; finished in 20.18ms (3.70ms CPU time)

Ran 21 tests for tests/unit/Hub/Hub.Add.t.sol:HubAddTest
[PASS] test_add_AddCapReachedButNotExceeded_rounding() (gas: 646962)
[PASS] test_add_fuzz_AddCapReachedButNotExceeded(uint56) (runs: 5000, μ: 156723, ~: 156572)
[PASS] test_add_fuzz_multi_asset_multi_spoke(uint256,uint256,uint256) (runs: 5000, μ: 310067, ~: 310201)
[PASS] test_add_fuzz_revertsWith_AddCapExceeded(uint56) (runs: 5000, μ: 78630, ~: 78479)
[PASS] test_add_fuzz_revertsWith_AddCapExceeded_due_to_interest(uint56,uint256,uint256) (runs: 5000, μ: 283070, ~: 285500)
[PASS] test_add_fuzz_revertsWith_ERC20InsufficientAllowance(uint256) (runs: 5000, μ: 78894, ~: 78622)
[PASS] test_add_fuzz_revertsWith_InvalidShares_due_to_index(uint256,uint256,uint256) (runs: 5000, μ: 216894, ~: 217071)
[PASS] test_add_fuzz_single_asset(uint256,address,uint256) (runs: 5000, μ: 337075, ~: 336995)
[PASS] test_add_fuzz_single_spoke_multi_add(uint256,uint256) (runs: 5000, μ: 819601, ~: 821790)
[PASS] test_add_multi_add_minimal_shares() (gas: 344693)
[PASS] test_add_revertsWith_AmountDowncastOverflow() (gas: 206362)
[PASS] test_add_revertsWith_ERC20InsufficientAllowance() (gas: 75159)
[PASS] test_add_revertsWith_InvalidAddress() (gas: 15722)
[PASS] test_add_revertsWith_InvalidAmount() (gas: 15789)
[PASS] test_add_revertsWith_InvalidShares() (gas: 220762)
[PASS] test_add_revertsWith_SharesDowncastOverflow() (gas: 36540)
[PASS] test_add_revertsWith_SpokeNotActive() (gas: 58210)
[PASS] test_add_revertsWith_SpokePaused() (gas: 58355)
[PASS] test_add_single_asset() (gas: 325001)
Logs:
  Bound result 2
  Bound result 100000000000000000000

[PASS] test_add_with_increased_index() (gas: 324294)
[PASS] test_add_with_increased_index_with_premium() (gas: 670220)
Suite result: ok. 21 passed; 0 failed; 0 skipped; finished in 48.37s (48.35s CPU time)

Ran 5 tests for tests/unit/Spoke/Spoke.Borrow.EdgeCases.t.sol:SpokeBorrowEdgeCasesTest
[PASS] test_borrow_fuzz_rounding_effect(uint256,uint256) (runs: 5000, μ: 1062188, ~: 1062337)
[PASS] test_borrow_fuzz_rounding_effect_inflated_ex_rate(uint256,uint256,uint256) (runs: 5000, μ: 1446437, ~: 1446577)
[PASS] test_borrow_fuzz_rounding_effect_shares(uint256,uint256) (runs: 5000, μ: 1112149, ~: 1111916)
[PASS] test_borrow_rounding_effect_multiple_actions() (gas: 1170448)
[PASS] test_borrow_rounding_effect_shares() (gas: 1111131)
Logs:
  Bound result 5000000000000000000
  Bound result 94608000

Suite result: ok. 5 passed; 0 failed; 0 skipped; finished in 67.43s (67.40s CPU time)

Ran 31 tests for tests/unit/Hub/Hub.Config.t.sol:HubConfigTest
[PASS] test_addAsset_fuzz(address,uint8,address) (runs: 5000, μ: 841731, ~: 841763)
[PASS] test_addAsset_fuzz_revertsWith_InvalidAddress_feeReceiver(address,uint8,address) (runs: 5000, μ: 46647, ~: 46948)
[PASS] test_addAsset_fuzz_revertsWith_InvalidAddress_irStrategy(address,uint8,address) (runs: 5000, μ: 46723, ~: 47024)
[PASS] test_addAsset_fuzz_revertsWith_InvalidAddress_underlying(uint8,address,address) (runs: 5000, μ: 37755, ~: 37755)
[PASS] test_addAsset_fuzz_revertsWith_InvalidAssetDecimals(address,uint8,address,address) (runs: 5000, μ: 47186, ~: 47004)
[PASS] test_addAsset_fuzz_revertsWith_InvalidAssetDecimals_tooLow(address,uint8,address,address) (runs: 5000, μ: 47448, ~: 47681)
[PASS] test_addAsset_fuzz_reverts_InvalidIrData(address,uint8,address,address) (runs: 5000, μ: 39928, ~: 36252)
[PASS] test_addAsset_revertsWith_BlockTimestampDowncastOverflow() (gas: 81092)
[PASS] test_addAsset_revertsWith_DrawnRateDowncastOverflow() (gas: 78065)
[PASS] test_addSpoke_fuzz(uint256,(bool,bool,uint56,uint56)) (runs: 5000, μ: 123698, ~: 123767)
[PASS] test_addSpoke_fuzz_revertsWith_AssetNotListed(uint256,(bool,bool,uint56,uint56)) (runs: 5000, μ: 34534, ~: 34522)
[PASS] test_addSpoke_fuzz_revertsWith_InvalidAddress_spoke(uint256,(bool,bool,uint56,uint56)) (runs: 5000, μ: 33121, ~: 33178)
[PASS] test_addSpoke_revertsWith_SpokeAlreadyListed() (gas: 38659)
[PASS] test_hub_deploy_revertsWith_InvalidAddress() (gas: 47100)
[PASS] test_updateAssetConfig_UseExistingSpokeAndListedAsFeeReceiver_revertsWith_SpokeAlreadyListed() (gas: 60191)
[PASS] test_updateAssetConfig_fuzz(uint256,(address,uint16,address,address)) (runs: 5000, μ: 242525, ~: 242410)
[PASS] test_updateAssetConfig_fuzz_FromZeroLiquidityFee(uint256,uint16) (runs: 5000, μ: 756225, ~: 756145)
[PASS] test_updateAssetConfig_fuzz_LiquidityFee(uint256,uint16) (runs: 5000, μ: 654194, ~: 654115)
[PASS] test_updateAssetConfig_fuzz_NewFeeReceiver(uint256) (runs: 5000, μ: 724352, ~: 724410)
[PASS] test_updateAssetConfig_fuzz_NewInterestRateStrategy(uint256) (runs: 5000, μ: 1127791, ~: 1127896)
[PASS] test_updateAssetConfig_fuzz_ReuseFeeReceiver_revertsWith_SpokeAlreadyListed(uint256) (runs: 5000, μ: 764023, ~: 764080)
[PASS] test_updateAssetConfig_fuzz_Scenario(uint256) (runs: 5000, μ: 605895, ~: 605949)
[PASS] test_updateAssetConfig_fuzz_UseExistingSpokeAsFeeReceiver_revertsWith_SpokeAlreadyListed(uint256) (runs: 5000, μ: 59774, ~: 59774)
[PASS] test_updateAssetConfig_fuzz_revertsWith_InvalidInterestRateStrategy(uint256) (runs: 5000, μ: 57832, ~: 57886)
[PASS] test_updateAssetConfig_fuzz_revertsWith_InvalidLiquidityFee(uint256,(address,uint16,address,address)) (runs: 5000, μ: 41093, ~: 40943)
[PASS] test_updateAssetConfig_fuzz_revertsWith_InvalidReinvestmentController() (gas: 495376)
[PASS] test_updateAssetConfig_fuzz_revertsWith_calculateInterestRateReverts(uint256,(address,uint16,address,address)) (runs: 5000, μ: 191557, ~: 191409)
[PASS] test_updateAssetConfig_fuzz_revertsWith_setInterestRateDataReverts(uint256,(address,uint16,address,address)) (runs: 5000, μ: 65206, ~: 65057)
[PASS] test_updateSpokeConfig_fuzz(uint256,(bool,bool,uint56,uint56)) (runs: 5000, μ: 56488, ~: 56559)
[PASS] test_updateSpokeConfig_fuzz_revertsWith_SpokeNotListed(uint256,address,(bool,bool,uint56,uint56)) (runs: 5000, μ: 40402, ~: 40469)
[PASS] test_updateSpokeConfig_revertsWith_AssetNotListed() (gas: 29297)
Suite result: ok. 31 passed; 0 failed; 0 skipped; finished in 98.17s (98.15s CPU time)

Ran 16 tests for tests/unit/Hub/Hub.Draw.t.sol:HubDrawTest
[PASS] test_draw_DifferentSpokes() (gas: 362695)
[PASS] test_draw_fuzz_IncreasedBorrowRate(uint256,uint256) (runs: 5000, μ: 681255, ~: 681326)
[PASS] test_draw_fuzz_amounts_same_block(uint256,uint256) (runs: 5000, μ: 285592, ~: 285456)
[PASS] test_draw_fuzz_revertsWith_DrawCapExceeded(uint56) (runs: 5000, μ: 79866, ~: 79715)
[PASS] test_draw_fuzz_revertsWith_DrawCapExceeded_due_to_interest(uint56,uint256,uint256) (runs: 5000, μ: 298751, ~: 299033)
[PASS] test_draw_fuzz_revertsWith_InsufficientLiquidity(uint256,uint256) (runs: 5000, μ: 33918, ~: 33721)
[PASS] test_draw_fuzz_revertsWith_InsufficientLiquidity_due_to_draw(uint256) (runs: 5000, μ: 183021, ~: 182748)
[PASS] test_draw_fuzz_revertsWith_InsufficientLiquidity_due_to_remove(uint256) (runs: 5000, μ: 129547, ~: 129352)
[PASS] test_draw_fuzz_revertsWith_InvalidAddress(uint256) (runs: 5000, μ: 15782, ~: 15782)
[PASS] test_draw_revertsWith_DrawCapExceeded_due_to_deficit() (gas: 253903)
[PASS] test_draw_revertsWith_InsufficientLiquidity() (gas: 28022)
[PASS] test_draw_revertsWith_InsufficientLiquidity_due_to_draw() (gas: 179301)
[PASS] test_draw_revertsWith_InsufficientLiquidity_due_to_remove() (gas: 126662)
[PASS] test_draw_revertsWith_InvalidAmount() (gas: 15902)
[PASS] test_draw_revertsWith_SpokeNotActive() (gas: 58166)
[PASS] test_draw_revertsWith_SpokePaused() (gas: 58311)
Suite result: ok. 16 passed; 0 failed; 0 skipped; finished in 26.32s (26.30s CPU time)

Ran 6 tests for tests/unit/Hub/Hub.EliminateDeficit.t.sol:HubEliminateDeficitTest
[PASS] test_eliminateDeficit(uint256) (runs: 5000, μ: 501302, ~: 501302)
[PASS] test_eliminateDeficit_allowSpokePaused() (gas: 336850)
[PASS] test_eliminateDeficit_fuzz_revertsWith_InvalidAmount_Excess(uint256) (runs: 5000, μ: 250786, ~: 250786)
[PASS] test_eliminateDeficit_fuzz_revertsWith_callerSpokeNotActive(address) (runs: 5000, μ: 28893, ~: 28893)
[PASS] test_eliminateDeficit_revertsWith_InvalidAmount_ZeroAmountNoDeficit() (gas: 20023)
[PASS] test_eliminateDeficit_revertsWith_InvalidAmount_ZeroAmountWithDeficit() (gas: 251908)
Suite result: ok. 6 passed; 0 failed; 0 skipped; finished in 12.93s (12.91s CPU time)

Ran 7 tests for tests/gas/Hub.Operations.gas.t.sol:HubOperations_Gas_Tests
[PASS] test_add() (gas: 128872)
[PASS] test_deficit() (gas: 1046512)
[PASS] test_draw() (gas: 372111)
[PASS] test_payFee_transferShares() (gas: 923086)
[PASS] test_refreshPremium() (gas: 124914)
[PASS] test_remove() (gas: 278055)
[PASS] test_restore() (gas: 724573)
Suite result: ok. 7 passed; 0 failed; 0 skipped; finished in 27.20ms (4.48ms CPU time)

Ran 17 tests for tests/unit/Spoke/Spoke.Borrow.HealthFactor.t.sol:SpokeBorrowHealthFactorTest
[PASS] test_borrow_fuzz_revertsWith_HealthFactorBelowThreshold_collateral_price_drop(uint256,uint256) (runs: 5000, μ: 895806, ~: 895874)
[PASS] test_borrow_fuzz_revertsWith_HealthFactorBelowThreshold_multiple_colls(uint256,uint256) (runs: 5000, μ: 855968, ~: 856918)
[PASS] test_borrow_fuzz_revertsWith_HealthFactorBelowThreshold_multiple_colls_with_interest(uint256,uint256,uint256) (runs: 5000, μ: 902332, ~: 899544)
[PASS] test_borrow_fuzz_revertsWith_HealthFactorBelowThreshold_multiple_debts(uint256,uint256) (runs: 5000, μ: 1115654, ~: 1115776)
[PASS] test_borrow_fuzz_revertsWith_HealthFactorBelowThreshold_multiple_debts_with_interest(uint256,uint256,uint256) (runs: 5000, μ: 1178602, ~: 1180128)
[PASS] test_borrow_fuzz_revertsWith_HealthFactorBelowThreshold_with_interest(uint256,uint256) (runs: 5000, μ: 690978, ~: 691609)
[PASS] test_borrow_revertsWith_HealthFactorBelowThreshold() (gas: 646969)
[PASS] test_borrow_revertsWith_HealthFactorBelowThreshold_collateral_price_drop_weth() (gas: 889956)
[PASS] test_borrow_revertsWith_HealthFactorBelowThreshold_multiple_colls() (gas: 850518)
[PASS] test_borrow_revertsWith_HealthFactorBelowThreshold_multiple_colls_collateral_price_drop_dai() (gas: 1104259)
[PASS] test_borrow_revertsWith_HealthFactorBelowThreshold_multiple_colls_collateral_price_drop_weth() (gas: 1104303)
[PASS] test_borrow_revertsWith_HealthFactorBelowThreshold_multiple_colls_with_interest() (gas: 902867)
[PASS] test_borrow_revertsWith_HealthFactorBelowThreshold_multiple_debts() (gas: 1108820)
[PASS] test_borrow_revertsWith_HealthFactorBelowThreshold_multiple_debts_with_interest() (gas: 1172903)
[PASS] test_borrow_revertsWith_HealthFactorBelowThreshold_with_interest() (gas: 686881)
[PASS] test_fuzz_borrow_revertsWith_HealthFactorBelowThreshold_multiple_colls_collateral_price_drop_dai(uint256,uint256,uint256) (runs: 5000, μ: 1107975, ~: 1109037)
[PASS] test_fuzz_borrow_revertsWith_HealthFactorBelowThreshold_multiple_colls_collateral_price_drop_weth(uint256,uint256,uint256) (runs: 5000, μ: 1108592, ~: 1109059)
Suite result: ok. 17 passed; 0 failed; 0 skipped; finished in 133.51s (133.49s CPU time)

Ran 6 tests for tests/unit/Hub/Hub.PayFee.t.sol:HubPayFeeTest
[PASS] test_payFee_fuzz(uint256,uint256) (runs: 5000, μ: 665244, ~: 665219)
[PASS] test_payFee_fuzz_with_interest(uint256,uint256,uint256) (runs: 5000, μ: 665509, ~: 665664)
[PASS] test_payFee_revertsWith_AddedSharesExceeded() (gas: 132719)
[PASS] test_payFee_revertsWith_AddedSharesExceeded_with_interest() (gas: 631536)
[PASS] test_payFee_revertsWith_InvalidShares() (gas: 20168)
[PASS] test_payFee_revertsWith_SpokeNotActive() (gas: 58192)
Suite result: ok. 6 passed; 0 failed; 0 skipped; finished in 23.52s (23.50s CPU time)

Ran 10 tests for tests/unit/Hub/Hub.Reclaim.t.sol:HubReclaimTest
[PASS] test_reclaim() (gas: 678856)
Logs:
  Bound result 1000000000000000000000
  Bound result 500000000000000000000
  Bound result 200000000000000000000

[PASS] test_reclaim_fullAmount() (gas: 659584)
[PASS] test_reclaim_fuzz(uint256,uint256,uint256) (runs: 5000, μ: 680301, ~: 679856)
[PASS] test_reclaim_multipleSweepsAndReclaims() (gas: 787580)
[PASS] test_reclaim_revertsWith_AssetNotListed() (gas: 12402)
[PASS] test_reclaim_revertsWith_InvalidAmount_exceedsSwept() (gas: 92247)
[PASS] test_reclaim_revertsWith_InvalidAmount_exceedsSwept_afterSweep() (gas: 466316)
[PASS] test_reclaim_revertsWith_InvalidAmount_zero() (gas: 90579)
[PASS] test_reclaim_revertsWith_OnlyReinvestmentController(address) (runs: 5000, μ: 91557, ~: 91557)
[PASS] test_reclaim_revertsWith_OnlyReinvestmentController_init() (gas: 37982)
Suite result: ok. 10 passed; 0 failed; 0 skipped; finished in 14.64s (14.63s CPU time)

Ran 8 tests for tests/unit/Hub/Hub.RefreshPremium.t.sol:HubRefreshPremiumTest
[PASS] test_refreshPremium_emitsEvent() (gas: 169682)
[PASS] test_refreshPremium_fuzz_positiveDeltas(int256,int256,int256) (runs: 5000, μ: 58064, ~: 58316)
[PASS] test_refreshPremium_fuzz_withAccrual(uint256,uint256,uint256,uint256) (runs: 5000, μ: 561365, ~: 561535)
[PASS] test_refreshPremium_negativeDeltas(int256,int256) (runs: 5000, μ: 472751, ~: 473238)
[PASS] test_refreshPremium_negativeDeltas_withAccrual(uint256,uint256) (runs: 5000, μ: 543607, ~: 552374)
[PASS] test_refreshPremium_pausedSpokesAllowed() (gas: 107841)
[PASS] test_refreshPremium_revertsWith_SpokeNotActive() (gas: 56015)
[PASS] test_refreshPremium_spokePremiumUpdateIsContained() (gas: 737246)
Suite result: ok. 8 passed; 0 failed; 0 skipped; finished in 20.33s (20.32s CPU time)

Ran 13 tests for tests/unit/Hub/Hub.Remove.t.sol:HubRemoveTest
[PASS] test_remove() (gas: 199825)
Logs:
  Bound result 2
  Bound result 100000000000000000000

[PASS] test_remove_all_with_interest() (gas: 398317)
[PASS] test_remove_fuzz(uint256,uint256) (runs: 5000, μ: 198367, ~: 198171)
[PASS] test_remove_fuzz_all_liquidity_with_interest(uint256,uint256) (runs: 5000, μ: 436092, ~: 438634)
[PASS] test_remove_fuzz_multi_spoke(uint256,uint256) (runs: 5000, μ: 279947, ~: 280098)
[PASS] test_remove_fuzz_multi_spoke_with_interest(uint256,uint256,uint256,uint256) (runs: 5000, μ: 449837, ~: 452927)
[PASS] test_remove_revertsWith_AddedAmountExceeded() (gas: 142218)
[PASS] test_remove_revertsWith_AddedAmountExceeded_zero_added() (gas: 29990)
[PASS] test_remove_revertsWith_InsufficientLiquidity() (gas: 171562)
[PASS] test_remove_revertsWith_InvalidAddress() (gas: 15746)
[PASS] test_remove_revertsWith_InvalidAmount() (gas: 17825)
[PASS] test_remove_revertsWith_SpokeNotActive() (gas: 58225)
[PASS] test_remove_revertsWith_SpokePaused() (gas: 58359)
Suite result: ok. 13 passed; 0 failed; 0 skipped; finished in 31.21s (31.19s CPU time)

Ran 5 tests for tests/unit/Hub/Hub.ReportDeficit.t.sol:HubReportDeficitTest
[PASS] test_reportDeficit_fuzz_revertsWith_SurplusDeficitReported(uint256,uint256,uint256,uint256) (runs: 5000, μ: 160350, ~: 160368)
[PASS] test_reportDeficit_fuzz_with_premium(uint256,uint256,uint256,uint256) (runs: 5000, μ: 333083, ~: 334922)
[PASS] test_reportDeficit_revertsWith_InvalidAmount() (gas: 18170)
[PASS] test_reportDeficit_revertsWith_SpokeNotActive(address) (runs: 5000, μ: 26412, ~: 26412)
[PASS] test_reportDeficit_with_premium() (gas: 333389)
Logs:
  Bound result 10000000000
  Bound result 31536000
  Bound result 5000000000
  Bound result 0

Suite result: ok. 5 passed; 0 failed; 0 skipped; finished in 9.64s (9.62s CPU time)

Ran 20 tests for tests/unit/Hub/Hub.Restore.t.sol:HubRestoreTest
[PASS] test_restore_full_amount_with_interest() (gas: 356168)
Logs:
  Bound result 1000000000000000000000
  Bound result 500000000000000000000
  Bound result 31536000

[PASS] test_restore_full_amount_with_interest_and_premium() (gas: 661755)
Logs:
  Bound result 100000000000000000000
  Bound result 50000000000000000000
  Bound result 31536000
  Bound result 1

[PASS] test_restore_fuzz_full_amount_with_interest(uint256,uint256,uint256) (runs: 5000, μ: 354845, ~: 357385)
[PASS] test_restore_fuzz_full_amount_with_interest_and_premium(uint256,uint256,uint256,uint256) (runs: 5000, μ: 645339, ~: 663181)
[PASS] test_restore_fuzz_revertsWith_SurplusAmountRestored_with_interest(uint256,uint256,uint256) (runs: 5000, μ: 248958, ~: 252730)
[PASS] test_restore_fuzz_revertsWith_SurplusAmountRestored_with_interest_and_premium(uint256,uint256,uint256,uint256) (runs: 5000, μ: 630351, ~: 634033)
[PASS] test_restore_partial_drawn() (gas: 331621)
[PASS] test_restore_partial_same_block() (gas: 310391)
[PASS] test_restore_premiumDeltas_twoWeiIncrease_realizedDelta() (gas: 251394)
[PASS] test_restore_revertsWith_InvalidAmount_zero() (gas: 44804)
[PASS] test_restore_revertsWith_InvalidPremiumChange_premiumIncrease() (gas: 193852)
[PASS] test_restore_revertsWith_InvalidPremiumChange_premiumSharesIncrease() (gas: 193872)
[PASS] test_restore_revertsWith_SpokeNotActive_whenPaused() (gas: 155215)
[PASS] test_restore_revertsWith_SpokePaused() (gas: 85357)
[PASS] test_restore_revertsWith_SurplusAmountRestored() (gas: 338814)
[PASS] test_restore_revertsWith_SurplusAmountRestored_with_interest() (gas: 251692)
Logs:
  Bound result 100000000000000000000
  Bound result 50000000000000000000
  Bound result 15768000

[PASS] test_restore_revertsWith_SurplusAmountRestored_with_interest_and_premium() (gas: 632693)
Logs:
  Bound result 100000000000000000000
  Bound result 50000000000000000000
  Bound result 31536000
  Bound result 1

[PASS] test_restore_revertsWith_underflow_offsetIncrease() (gas: 193861)
[PASS] test_restore_two_wei_shares_delta_increase() (gas: 246063)
[PASS] test_restore_when_asset_frozen() (gas: 412879)
Suite result: ok. 20 passed; 0 failed; 0 skipped; finished in 18.95s (18.93s CPU time)

Ran 1 test for tests/unit/Hub/Hub.Rounding.t.sol:HubRoundingTest
[PASS] test_sharePriceWithMultipleDonations() (gas: 702202707)
Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 3.63s (3.61s CPU time)

Ran 8 tests for tests/unit/Hub/Hub.Sweep.t.sol:HubSweepTest
[PASS] test_sweep() (gas: 484704)
Logs:
  Bound result 1000000000000000000000
  Bound result 1000000000000000000000

[PASS] test_sweep_does_not_impact_utilization(uint256,uint256) (runs: 5000, μ: 648242, ~: 649417)
[PASS] test_sweep_fuzz(uint256,uint256) (runs: 5000, μ: 485217, ~: 485228)
[PASS] test_sweep_revertsWith_AssetNotListed() (gas: 12317)
[PASS] test_sweep_revertsWith_InsufficientLiquidity() (gas: 234857)
[PASS] test_sweep_revertsWith_InvalidAmount() (gas: 101549)
[PASS] test_sweep_revertsWith_OnlyReinvestmentController(address) (runs: 5000, μ: 92083, ~: 92083)
[PASS] test_sweep_revertsWith_OnlyReinvestmentController_init() (gas: 37943)
Suite result: ok. 8 passed; 0 failed; 0 skipped; finished in 17.89s (17.88s CPU time)

Ran 7 tests for tests/unit/Hub/Hub.TransferShares.t.sol:HubTransferSharesTest
[PASS] test_transferShares() (gas: 170871)
Logs:
  Bound result 1000000000000000000000
  Bound result 1000000000000000000000

[PASS] test_transferShares_fuzz(uint256,uint256) (runs: 5000, μ: 174301, ~: 174456)
[PASS] test_transferShares_fuzz_revertsWith_AddedSharesExceeded(uint256) (runs: 5000, μ: 140804, ~: 140532)
[PASS] test_transferShares_revertsWith_AddCapExceeded() (gas: 184283)
[PASS] test_transferShares_revertsWith_SpokeNotActive() (gas: 164956)
[PASS] test_transferShares_revertsWith_SpokePaused() (gas: 167327)
[PASS] test_transferShares_zeroShares_revertsWith_InvalidShares() (gas: 22530)
Suite result: ok. 7 passed; 0 failed; 0 skipped; finished in 6.60s (6.58s CPU time)

Ran 6 tests for tests/unit/Hub/HubAccrueInterest.t.sol:HubAccrueInterestTest
[PASS] test_accrueInterest_NoActionTaken() (gas: 41386)
[PASS] test_accrueInterest_NoInterest_NoDebt(uint32) (runs: 5000, μ: 330495, ~: 330422)
[PASS] test_accrueInterest_NoInterest_OnlyAdd(uint32) (runs: 5000, μ: 187405, ~: 187332)
[PASS] test_accrueInterest_fuzz_BorrowAmountAndElapsed(uint256,uint32) (runs: 5000, μ: 262869, ~: 265179)
[PASS] test_accrueInterest_fuzz_BorrowAmountRateAndElapsed(uint256,uint256,uint32) (runs: 5000, μ: 363246, ~: 366765)
[PASS] test_accrueInterest_fuzz_BorrowAndWait(uint32) (runs: 5000, μ: 264208, ~: 264135)
Suite result: ok. 6 passed; 0 failed; 0 skipped; finished in 21.33s (21.31s CPU time)

Ran 57 tests for tests/unit/HubConfigurator.t.sol:HubConfiguratorTest
[PASS] test_addAsset_fuzz(bool,address,uint8,address,uint16,uint32,uint32,uint32) (runs: 5000, μ: 852253, ~: 852545)
[PASS] test_addAsset_fuzz_revertsWith_InvalidAssetDecimals(bool,address,uint8,address,address) (runs: 5000, μ: 56326, ~: 56767)
[PASS] test_addAsset_fuzz_revertsWith_OwnableUnauthorizedAccount(address) (runs: 5000, μ: 34797, ~: 34798)
[PASS] test_addAsset_revertsWith_InvalidAddress_irStrategy() (gas: 50445)
[PASS] test_addAsset_revertsWith_InvalidAddress_underlying() (gas: 50343)
[PASS] test_addAsset_reverts_invalidIrData() (gas: 44350)
[PASS] test_addSpoke() (gas: 124687)
[PASS] test_addSpokeToAssets() (gas: 219685)
[PASS] test_addSpokeToAssets_revertsWith_MismatchedConfigs() (gas: 24613)
[PASS] test_addSpokeToAssets_revertsWith_OwnableUnauthorizedAccount() (gas: 17213)
[PASS] test_addSpoke_revertsWith_OwnableUnauthorizedAccount() (gas: 16829)
[PASS] test_deactivateAsset() (gas: 155449)
[PASS] test_deactivateAsset_revertsWith_OwnableUnauthorizedAccount() (gas: 18008)
[PASS] test_deactivateSpoke() (gas: 152305)
[PASS] test_deactivateSpoke_revertsWith_OwnableUnauthorizedAccount() (gas: 17950)
[PASS] test_freezeAsset() (gas: 158120)
[PASS] test_freezeAsset_revertsWith_OwnableUnauthorizedAccount() (gas: 17941)
[PASS] test_freezeSpoke() (gas: 155030)
[PASS] test_freezeSpoke_revertsWith_OwnableUnauthorizedAccount() (gas: 18060)
[PASS] test_pauseAsset() (gas: 155446)
[PASS] test_pauseAsset_revertsWith_OwnableUnauthorizedAccount() (gas: 17898)
[PASS] test_pauseSpoke() (gas: 152434)
[PASS] test_pauseSpoke_revertsWith_OwnableUnauthorizedAccount() (gas: 18017)
[PASS] test_updateFeeConfig_Scenario() (gas: 322726)
Logs:
  Bound result 0
  Bound result 1800
  Bound result 0
  Bound result 400
  Bound result 0
  Bound result 0

[PASS] test_updateFeeConfig_fuzz(uint256,uint16,address) (runs: 5000, μ: 174433, ~: 174326)
[PASS] test_updateFeeConfig_fuzz_revertsWith_OwnableUnauthorizedAccount(address) (runs: 5000, μ: 17682, ~: 17683)
[PASS] test_updateFeeConfig_revertsWith_InvalidAddress_spoke() (gas: 48138)
[PASS] test_updateFeeConfig_revertsWith_InvalidLiquidityFee() (gas: 50083)
[PASS] test_updateFeeReceiver_Scenario() (gas: 204758)
[PASS] test_updateFeeReceiver_WithdrawFromOldSpoke() (gas: 967743)
[PASS] test_updateFeeReceiver_correctAccruals() (gas: 995353)
[PASS] test_updateFeeReceiver_fuzz(address) (runs: 5000, μ: 170901, ~: 170901)
[PASS] test_updateFeeReceiver_fuzz_revertsWith_OwnableUnauthorizedAccount(address) (runs: 5000, μ: 17268, ~: 17269)
[PASS] test_updateFeeReceiver_revertsWith_InvalidAddress_spoke() (gas: 52675)
[PASS] test_updateFeeReceiver_revertsWith_SpokeAlreadyListed() (gas: 74330)
[PASS] test_updateInterestRateData() (gas: 71575)
[PASS] test_updateInterestRateData_revertsWith_OwnableUnauthorizedAccount() (gas: 19152)
[PASS] test_updateInterestRateStrategy() (gas: 91080)
[PASS] test_updateInterestRateStrategy_fuzz_revertsWith_OwnableUnauthorizedAccount(address) (runs: 5000, μ: 28658, ~: 28659)
[PASS] test_updateInterestRateStrategy_revertsWith_InterestRateStrategyReverts() (gas: 74619)
[PASS] test_updateInterestRateStrategy_revertsWith_InvalidAddress_irStrategy() (gas: 64366)
[PASS] test_updateInterestRateStrategy_revertsWith_InvalidInterestRateStrategy() (gas: 64861)
[PASS] test_updateLiquidityFee_fuzz(uint256,uint16) (runs: 5000, μ: 84313, ~: 84169)
[PASS] test_updateLiquidityFee_revertsWith_InvalidLiquidityFee() (gas: 52600)
[PASS] test_updateLiquidityFee_revertsWith_OwnableUnauthorizedAccount() (gas: 16633)
[PASS] test_updateReinvestmentController() (gas: 99106)
[PASS] test_updateReinvestmentController_fuzz_revertsWith_OwnableUnauthorizedAccount(address) (runs: 5000, μ: 17270, ~: 17271)
[PASS] test_updateSpokeActive() (gas: 81157)
[PASS] test_updateSpokeActive_revertsWith_OwnableUnauthorizedAccount() (gas: 20241)
[PASS] test_updateSpokeCaps() (gas: 62767)
[PASS] test_updateSpokeCaps_revertsWith_OwnableUnauthorizedAccount() (gas: 20172)
[PASS] test_updateSpokeDrawCap() (gas: 62574)
[PASS] test_updateSpokeDrawCap_revertsWith_OwnableUnauthorizedAccount() (gas: 20245)
[PASS] test_updateSpokePaused() (gas: 84139)
[PASS] test_updateSpokePaused_revertsWith_OwnableUnauthorizedAccount() (gas: 20352)
[PASS] test_updateSpokeSupplyCap() (gas: 62561)
[PASS] test_updateSpokeSupplyCap_revertsWith_OwnableUnauthorizedAccount() (gas: 20193)
Suite result: ok. 57 passed; 0 failed; 0 skipped; finished in 9.36s (9.34s CPU time)

Ran 2 tests for tests/invariant/HubInvariant.t.sol:HubInvariant
[SKIP] invariant_exchangeRateMonotonicallyIncreasing() (runs: 1, calls: 1, reverts: 1)
[SKIP] invariant_reserveTotalAssets() (runs: 1, calls: 1, reverts: 1)
Suite result: ok. 0 passed; 0 failed; 2 skipped; finished in 2.82ms (580.82µs CPU time)

Ran 6 tests for tests/unit/Spoke/Spoke.Borrow.Scenario.t.sol:SpokeBorrowScenarioTest
[PASS] test_borrow_fuzz_multi_spoke_multi_reserves(uint256,uint256,uint256,uint256,uint256) (runs: 5000, μ: 2195601, ~: 2205777)
[PASS] test_borrow_fuzz_single_spoke_multi_reserves(uint256,uint256,uint256,uint256) (runs: 5000, μ: 2360891, ~: 2369903)
[PASS] test_borrow_fuzz_single_spoke_multi_reserves_multi_user(uint256,uint256,uint256,uint256) (runs: 5000, μ: 2748628, ~: 2756961)
[PASS] test_borrow_fuzz_skip_borrow(uint256,uint256,uint256) (runs: 5000, μ: 1078328, ~: 1080613)
[PASS] test_borrow_skip_borrow() (gas: 1079798)
Logs:
  Bound result 10000000000000000000
  Bound result 20000000000000000000
  Bound result 31536000

[PASS] test_userAccountData_does_not_include_zero_cf_collateral() (gas: 1158793)
Suite result: ok. 6 passed; 0 failed; 0 skipped; finished in 181.53s (181.51s CPU time)

Ran 14 tests for tests/unit/Spoke/Spoke.Borrow.Validation.t.sol:SpokeBorrowValidationTest
[PASS] test_borrow_fuzz_revertsWith_DrawCapExceeded(uint256,uint56) (runs: 5000, μ: 106373, ~: 106282)
[PASS] test_borrow_fuzz_revertsWith_DrawCapExceeded_due_to_interest(uint256) (runs: 5000, μ: 697155, ~: 697446)
[PASS] test_borrow_fuzz_revertsWith_InsufficientLiquidity(uint256,uint256,uint256) (runs: 5000, μ: 280771, ~: 280576)
[PASS] test_borrow_fuzz_revertsWith_InvalidAmount(uint256) (runs: 5000, μ: 32674, ~: 32731)
[PASS] test_borrow_fuzz_revertsWith_ReserveFrozen(uint256,uint256) (runs: 5000, μ: 69490, ~: 69288)
[PASS] test_borrow_fuzz_revertsWith_ReserveNotBorrowable(uint256,uint256) (runs: 5000, μ: 69725, ~: 69523)
[PASS] test_borrow_fuzz_revertsWith_ReserveNotListed(uint256,uint256) (runs: 5000, μ: 26073, ~: 25818)
[PASS] test_borrow_fuzz_revertsWith_ReservePaused(uint256,uint256) (runs: 5000, μ: 69347, ~: 69145)
[PASS] test_borrow_revertsWith_InsufficientLiquidity() (gas: 280490)
Logs:
  Bound result 10000000000000000000

[PASS] test_borrow_revertsWith_InvalidAmount() (gas: 34342)
Logs:
  Bound result 2

[PASS] test_borrow_revertsWith_ReserveFrozen() (gas: 70894)
Logs:
  Bound result 2
  Bound result 1

[PASS] test_borrow_revertsWith_ReserveNotBorrowable() (gas: 71083)
Logs:
  Bound result 2
  Bound result 1

[PASS] test_borrow_revertsWith_ReserveNotListed() (gas: 27102)
Logs:
  Bound result 1

[PASS] test_borrow_revertsWith_ReservePaused() (gas: 70771)
Logs:
  Bound result 2
  Bound result 1

Suite result: ok. 14 passed; 0 failed; 0 skipped; finished in 15.65s (15.63s CPU time)

Ran 2 tests for tests/unit/Spoke/Spoke.Borrow.t.sol:SpokeBorrowTest
[PASS] test_borrow() (gas: 1074154)
[PASS] test_borrow_fuzz_amounts(uint256,uint256) (runs: 5000, μ: 1066223, ~: 1066269)
Suite result: ok. 2 passed; 0 failed; 0 skipped; finished in 26.44s (26.43s CPU time)

Ran 24 tests for tests/unit/Spoke/Spoke.Config.t.sol:SpokeConfigTest
[PASS] test_addReserve() (gas: 390303)
[PASS] test_addReserve_fuzz_revertsWith_AssetNotListed() (gas: 245676)
[PASS] test_addReserve_revertsWith_InvalidAddress_hub() (gas: 5958766)
[PASS] test_addReserve_revertsWith_InvalidAddress_oracle() (gas: 5995891)
[PASS] test_addReserve_revertsWith_InvalidAssetId() (gas: 33193)
[PASS] test_addReserve_revertsWith_ReserveExists() (gas: 374834)
[PASS] test_spoke_deploy() (gas: 4892859)
[PASS] test_spoke_deploy_revertsWith_InvalidOracleDecimals() (gas: 46369)
[PASS] test_spoke_deploy_reverts_on_InvalidConstructorInput() (gas: 43770)
[PASS] test_updateLiquidationConfig_fuzz_liqBonusConfig((uint128,uint64,uint16)) (runs: 5000, μ: 52177, ~: 52165)
[PASS] test_updateLiquidationConfig_fuzz_revertsWith_InvalidLiquidationConfig_healthFactorForMaxBonus((uint128,uint64,uint16)) (runs: 5000, μ: 37834, ~: 37971)
[PASS] test_updateLiquidationConfig_fuzz_revertsWith_InvalidLiquidationConfig_liquidationBonusFactor((uint128,uint64,uint16)) (runs: 5000, μ: 37402, ~: 37181)
[PASS] test_updateLiquidationConfig_fuzz_targetHealthFactor(uint128) (runs: 5000, μ: 46886, ~: 47181)
[PASS] test_updateLiquidationConfig_liqBonusConfig() (gas: 51124)
Logs:
  Bound result 900000000000000000
  Bound result 1000
  Bound result 1000000000000000000

[PASS] test_updateLiquidationConfig_revertsWith_InvalidLiquidationConfig_healthFactorForMaxBonus() (gas: 36484)
Logs:
  Bound result 1000000000000000000
  Bound result 1000
  Bound result 1000000000000000000

[PASS] test_updateLiquidationConfig_revertsWith_InvalidLiquidationConfig_liquidationBonusFactor() (gas: 36278)
Logs:
  Bound result 900000000000000000
  Bound result 10001
  Bound result 1000000000000000000

[PASS] test_updateLiquidationConfig_targetHealthFactor() (gas: 46464)
Logs:
  Bound result 1000000000000000001

[PASS] test_updateReserveConfig() (gas: 53904)
[PASS] test_updateReserveConfig_fuzz((bool,bool,bool,uint24)) (runs: 5000, μ: 55321, ~: 55149)
[PASS] test_updateReserveConfig_revertsWith_InvalidCollateralRisk() (gas: 39647)
[PASS] test_updateReserveConfig_revertsWith_ReserveNotListed() (gas: 36296)
[PASS] test_updateReservePriceSource() (gas: 240136)
[PASS] test_updateReservePriceSource_revertsWith_AccessManagedUnauthorized(address) (runs: 5000, μ: 31124, ~: 31125)
[PASS] test_updateReservePriceSource_revertsWith_ReserveNotListed() (gas: 34321)
Suite result: ok. 24 passed; 0 failed; 0 skipped; finished in 3.82s (3.80s CPU time)

Ran 9 tests for tests/unit/KeyValueList.t.sol:KeyValueListTest
[PASS] test_add_unique() (gas: 325391)
[PASS] test_fuzz_add(uint256,uint256) (runs: 5000, μ: 200009, ~: 201361)
[PASS] test_fuzz_add_unique(uint256,uint256) (runs: 5000, μ: 235034, ~: 235413)
[PASS] test_fuzz_get(uint256[]) (runs: 5000, μ: 413030, ~: 411058)
[PASS] test_fuzz_get_uninitialized(uint256[]) (runs: 5000, μ: 263153, ~: 252829)
[PASS] test_fuzz_get_uninitialized_sorted(uint256[]) (runs: 5000, μ: 204936, ~: 185584)
[PASS] test_fuzz_sortByKey(uint256[]) (runs: 5000, μ: 463494, ~: 454253)
[PASS] test_fuzz_sortByKey_length(uint256) (runs: 5000, μ: 201443, ~: 204084)
[PASS] test_fuzz_sortByKey_with_collision(uint256[]) (runs: 5000, μ: 548050, ~: 539502)
Suite result: ok. 9 passed; 0 failed; 0 skipped; finished in 72.57s (72.57s CPU time)

Ran 3 tests for tests/unit/libraries/LiquidationLogic/LiquidationLogic.DebtToLiquidate.t.sol:LiquidationLogicDebtToLiquidateTest
[PASS] test_calculateDebtToLiquidate_fuzz((uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256)) (runs: 5000, μ: 30551, ~: 30489)
[PASS] test_calculateDebtToLiquidate_fuzz_AmountAdjustedDueToDust((uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256)) (runs: 5000, μ: 32289, ~: 32389)
[PASS] test_calculateDebtToLiquidate_fuzz_ImpossibleToAdjustForDust((uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256)) (runs: 5000, μ: 34443, ~: 34418)
Suite result: ok. 3 passed; 0 failed; 0 skipped; finished in 3.39s (3.38s CPU time)

Ran 7 tests for tests/unit/libraries/LiquidationLogic/LiquidationLogic.DebtToTargetHealthFactor.t.sol:LiquidationLogicDebtToTargetHealthFactorTest
[PASS] test_calculateDebtToTargetHealthFactor_HealthFactorEqualsTargetHealthFactor((uint256,uint256,uint256,uint256,uint256,uint256,uint256)) (runs: 5000, μ: 22992, ~: 23049)
[PASS] test_calculateDebtToTargetHealthFactor_NoPrecisionLoss() (gas: 25367)
[PASS] test_calculateDebtToTargetHealthFactor_PrecisionLoss() (gas: 15341)
[PASS] test_calculateDebtToTargetHealthFactor_UnitPrice() (gas: 25300)
[PASS] test_calculateDebtToTargetHealthFactor_fuzz_NoRevert((uint256,uint256,uint256,uint256,uint256,uint256,uint256)) (runs: 5000, μ: 20050, ~: 20107)
[PASS] test_calculateDebtToTargetHealthFactor_fuzz_revertsWith_DivisionByZero_ZeroAssetPrice((uint256,uint256,uint256,uint256,uint256,uint256,uint256)) (runs: 5000, μ: 22749, ~: 22806)
[PASS] test_calculateDebtToTargetHealthFactor_revertsWith_ArithmeticError_TargetHealthFactorLessThanHealthFactor((uint256,uint256,uint256,uint256,uint256,uint256,uint256)) (runs: 5000, μ: 22832, ~: 22889)
Suite result: ok. 7 passed; 0 failed; 0 skipped; finished in 2.78s (2.76s CPU time)

Ran 16 tests for tests/unit/libraries/LiquidationLogic/LiquidationLogic.EvaluateDeficit.t.sol:LiquidationLogicEvaluateDeficitTest
[PASS] test_evaluateDeficit_CRE_SCCM_DRE_BRCM() (gas: 9003)
[PASS] test_evaluateDeficit_CRE_SCCM_DRE_BRCO() (gas: 8971)
[PASS] test_evaluateDeficit_CRE_SCCM_DRN_BRCM() (gas: 8992)
[PASS] test_evaluateDeficit_CRE_SCCM_DRN_BRCO() (gas: 8959)
[PASS] test_evaluateDeficit_CRE_SCCO_DRE_BRCM() (gas: 8985)
[PASS] test_evaluateDeficit_CRE_SCCO_DRE_BRCO() (gas: 9052)
[PASS] test_evaluateDeficit_CRE_SCCO_DRN_BRCM() (gas: 9017)
[PASS] test_evaluateDeficit_CRE_SCCO_DRN_BRCO() (gas: 9005)
[PASS] test_evaluateDeficit_CRN_SCCM_DRE_BRCM() (gas: 9005)
[PASS] test_evaluateDeficit_CRN_SCCM_DRE_BRCO() (gas: 8994)
[PASS] test_evaluateDeficit_CRN_SCCM_DRN_BRCM() (gas: 8928)
[PASS] test_evaluateDeficit_CRN_SCCM_DRN_BRCO() (gas: 8961)
[PASS] test_evaluateDeficit_CRN_SCCO_DRE_BRCM() (gas: 8938)
[PASS] test_evaluateDeficit_CRN_SCCO_DRE_BRCO() (gas: 8995)
[PASS] test_evaluateDeficit_CRN_SCCO_DRN_BRCM() (gas: 8946)
[PASS] test_evaluateDeficit_CRN_SCCO_DRN_BRCO() (gas: 9024)
Suite result: ok. 16 passed; 0 failed; 0 skipped; finished in 17.76ms (924.41µs CPU time)

Ran 3 tests for tests/unit/libraries/LiquidationLogic/LiquidationLogic.LiquidateCollateral.t.sol:LiquidationLogicLiquidateCollateralTest
[PASS] test_liquidateCollateral_fuzz(uint256,uint256) (runs: 5000, μ: 238476, ~: 238953)
[PASS] test_liquidateCollateral_fuzz_revertsWith_ArithmeticUnderflow(uint256,uint256) (runs: 5000, μ: 92447, ~: 92251)
[PASS] test_liquidateCollateral_fuzz_revertsWith_InvalidAmount(uint256) (runs: 5000, μ: 74799, ~: 74720)
Suite result: ok. 3 passed; 0 failed; 0 skipped; finished in 3.99s (3.98s CPU time)

Ran 4 tests for tests/unit/libraries/LiquidationLogic/LiquidationLogic.LiquidateDebt.t.sol:LiquidationLogicLiquidateDebtTest
[PASS] test_liquidateDebt_fuzz(uint256) (runs: 5000, μ: 177750, ~: 177750)
[PASS] test_liquidateDebt_revertsWith_ArithmeticUnderflow() (gas: 142904)
[PASS] test_liquidateDebt_revertsWith_InsufficientAllowance() (gas: 146818)
[PASS] test_liquidateDebt_revertsWith_InsufficientBalance() (gas: 195598)
Suite result: ok. 4 passed; 0 failed; 0 skipped; finished in 2.30s (2.28s CPU time)

Ran 4 tests for tests/unit/libraries/LiquidationLogic/LiquidationLogic.LiquidateUser.t.sol:LiquidationLogicLiquidateUserTest
[PASS] test_liquidateUser() (gas: 350226)
[PASS] test_liquidateUser_revertsWith_InvalidDebtToCover() (gas: 69084)
[PASS] test_liquidateUser_revertsWith_MustNotLeaveDust_Collateral() (gas: 100615)
[PASS] test_liquidateUser_revertsWith_MustNotLeaveDust_Debt() (gas: 109593)
Suite result: ok. 4 passed; 0 failed; 0 skipped; finished in 23.11ms (1.37ms CPU time)

Ran 10 tests for tests/unit/Spoke/Spoke.DynamicConfig.Triggers.t.sol:SpokeDynamicConfigTriggersTest
[PASS] test_borrow_triggers_dynamicConfigUpdate() (gas: 1328446)
[PASS] test_liquidate_does_not_trigger_dynamicConfigUpdate() (gas: 1617480)
[PASS] test_repay_does_not_trigger_dynamicConfigUpdate() (gas: 911594)
[PASS] test_supply_does_not_trigger_dynamicConfigUpdate() (gas: 1069101)
[PASS] test_updateUserDynamicConfig_doesHFCheck() (gas: 801815)
[PASS] test_updateUserDynamicConfig_reverts_when_not_authorized(address) (runs: 5000, μ: 1194204, ~: 1194204)
[PASS] test_updateUserDynamicConfig_triggers_dynamicConfigUpdate() (gas: 676714)
[PASS] test_updateUserDynamicConfig_updatesRP() (gas: 1297564)
[PASS] test_usingAsCollateral_triggers_dynamicConfigUpdate() (gas: 1342946)
[PASS] test_withdraw_triggers_dynamicConfigUpdate() (gas: 1365457)
Suite result: ok. 10 passed; 0 failed; 0 skipped; finished in 27.48s (27.46s CPU time)

Ran 20 tests for tests/unit/Spoke/Spoke.DynamicConfig.t.sol:SpokeDynamicConfigTest
[PASS] test_addDynamicReserveConfig() (gas: 85033)
[PASS] test_addDynamicReserveConfig_fuzz_revertsWith_InvalidCollateralFactorAndMaxLiquidationBonus_incompatible(uint16,uint32) (runs: 5000, μ: 47750, ~: 47918)
[PASS] test_addDynamicReserveConfig_once() (gas: 542097)
[PASS] test_addDynamicReserveConfig_revertsWith_AccessManagedUnauthorized(address) (runs: 5000, μ: 52381, ~: 52383)
[PASS] test_addDynamicReserveConfig_revertsWith_InvalidCollateralFactorAndMaxLiquidationBonus_collateralFactor() (gas: 59450)
[PASS] test_addDynamicReserveConfig_revertsWith_InvalidCollateralFactorAndMaxLiquidationBonus_liquidationBonus() (gas: 41863)
[PASS] test_addDynamicReserveConfig_revertsWith_InvalidLiquidationFee() (gas: 42337)
[PASS] test_addDynamicReserveConfig_revertsWith_ReserveNotListed() (gas: 34306)
[PASS] test_fuzz_addDynamicReserveConfig_spaced_dup_updates(bytes32) (runs: 5000, μ: 154147, ~: 154147)
[PASS] test_fuzz_addDynamicReserveConfig_trailing_order(bytes32) (runs: 5000, μ: 150812, ~: 150812)
[PASS] test_offboardReserve_existing_borrows_remain_unaffected() (gas: 1160865)
[PASS] test_updateDynamicReserveConfig() (gas: 1716730)
[PASS] test_updateDynamicReserveConfig_fuzz_revertsWith_InvalidCollateralFactorAndMaxLiquidationBonus(uint16,uint32) (runs: 5000, μ: 63321, ~: 63489)
[PASS] test_updateDynamicReserveConfig_revertsWith_AccessManagedUnauthorized(address) (runs: 5000, μ: 52360, ~: 52362)
[PASS] test_updateDynamicReserveConfig_revertsWith_ConfigKeyUninitialized() (gas: 54243)
[PASS] test_updateDynamicReserveConfig_revertsWith_InvalidCollateralFactor() (gas: 56433)
[PASS] test_updateDynamicReserveConfig_revertsWith_InvalidCollateralFactorAndMaxLiquidationBonus_collateralFactor() (gas: 57219)
[PASS] test_updateDynamicReserveConfig_revertsWith_InvalidCollateralFactorAndMaxLiquidationBonus_liquidationBonus() (gas: 57367)
[PASS] test_updateDynamicReserveConfig_revertsWith_InvalidLiquidationFee() (gas: 57905)
[PASS] test_updateDynamicReserveConfig_revertsWith_ReserveNotListed() (gas: 34614)
Suite result: ok. 20 passed; 0 failed; 0 skipped; finished in 10.16s (10.14s CPU time)

Ran 5 tests for tests/gas/Spoke.Getters.gas.t.sol:SpokeGetters_Gas_Tests
[PASS] test_getUserAccountData() (gas: 22798)
[PASS] test_getUserAccountData_oneSupplies() (gas: 274176)
[PASS] test_getUserAccountData_twoSupplies() (gas: 499913)
[PASS] test_getUserAccountData_twoSupplies_oneBorrows() (gas: 1029545)
[PASS] test_getUserAccountData_twoSupplies_twoBorrows() (gas: 1595650)
Suite result: ok. 5 passed; 0 failed; 0 skipped; finished in 27.81ms (4.62ms CPU time)

Ran 5 tests for tests/unit/Spoke/Spoke.Getters.t.sol:SpokeGettersTest
[PASS] test_getLiquidationBonus_configured() (gas: 89525)
Logs:
  Bound result 2
  Bound result 1000000000000000000
  Bound result 4000
  Bound result 900000000000000000

[PASS] test_getLiquidationBonus_fuzz_configured(uint256,uint256,uint16,uint64) (runs: 5000, μ: 88204, ~: 88636)
[PASS] test_getLiquidationBonus_fuzz_notConfigured(uint256,uint256) (runs: 5000, μ: 65846, ~: 65600)
[PASS] test_getLiquidationBonus_notConfigured() (gas: 67107)
Logs:
  Bound result 2
  Bound result 1000000000000000000

[PASS] test_protocol_getters() (gas: 278375)
Suite result: ok. 5 passed; 0 failed; 0 skipped; finished in 1.91s (1.89s CPU time)

Ran 8 tests for tests/unit/libraries/LiquidationLogic/LiquidationLogic.LiquidationAmounts.t.sol:LiquidationLogicLiquidationAmountsTest
[PASS] test_calculateLiquidationAmounts_EnoughCollateral() (gas: 15155)
[PASS] test_calculateLiquidationAmounts_InsufficientCollateral() (gas: 15402)
[PASS] test_calculateLiquidationAmounts_fuzz_EnoughCollateral_CollateralDust((uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256)) (runs: 5000, μ: 53894, ~: 53810)
[PASS] test_calculateLiquidationAmounts_fuzz_EnoughCollateral_NoCollateralDust((uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256)) (runs: 5000, μ: 53001, ~: 52999)
[PASS] test_calculateLiquidationAmounts_fuzz_EnoughCollateral_NoDebtLeft((uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256)) (runs: 5000, μ: 69659, ~: 69467)
[PASS] test_calculateLiquidationAmounts_fuzz_InsufficientCollateral((uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256)) (runs: 5000, μ: 56981, ~: 56814)
[PASS] test_calculateLiquidationAmounts_fuzz_revertsWith_MustNotLeaveDust_Collateral((uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256)) (runs: 5000, μ: 52811, ~: 52709)
[PASS] test_calculateLiquidationAmounts_fuzz_revertsWith_MustNotLeaveDust_Debt((uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256)) (runs: 5000, μ: 65115, ~: 65010)
Suite result: ok. 8 passed; 0 failed; 0 skipped; finished in 18.41s (18.39s CPU time)

Ran 4 tests for tests/unit/Spoke/Liquidations/Spoke.LiquidationCall.Dust.t.sol:SpokeLiquidationCallDustTest
[PASS] test_collateralDust_min_debtToTarget() (gas: 7392569)
[PASS] test_debtToCover_exceeds_collateralValue() (gas: 7386066)
[PASS] test_dustColl_allowed() (gas: 7233799)
[PASS] test_dustDebt_allowed() (gas: 7380976)
Suite result: ok. 4 passed; 0 failed; 0 skipped; finished in 46.70ms (22.45ms CPU time)

Ran 4 tests for tests/unit/libraries/LiquidationLogic/LiquidationLogic.LiquidationBonus.t.sol:LiquidationLogicLiquidationBonusTest
[PASS] test_calculateLiquidationBonus_MinBonusDueToRounding() (gas: 9360)
[PASS] test_calculateLiquidationBonus_PartialBonus() (gas: 9381)
[PASS] test_calculateLiquidationBonus_fuzz_ConstantBonus(uint256,uint256,uint256,uint256) (runs: 5000, μ: 17237, ~: 17178)
[PASS] test_calculateLiquidationBonus_fuzz_MaxBonus(uint256,uint256,uint256,uint256) (runs: 5000, μ: 19575, ~: 19506)
Suite result: ok. 4 passed; 0 failed; 0 skipped; finished in 999.04ms (981.45ms CPU time)

Ran 12 tests for tests/unit/libraries/LiquidationLogic/LiquidationLogic.ValidateLiquidationCall.t.sol:LiquidationLogicValidateLiquidationCallTest
[PASS] test_validateLiquidationCall() (gas: 28553)
[PASS] test_validateLiquidationCall_revertsWith_CollateralCannotBeLiquidated_NotUsingAsCollateral() (gas: 29608)
[PASS] test_validateLiquidationCall_revertsWith_CollateralCannotBeLiquidated_ZeroCollateralFactor() (gas: 29657)
[PASS] test_validateLiquidationCall_revertsWith_HealthFactorNotBelowThreshold() (gas: 34372)
[PASS] test_validateLiquidationCall_revertsWith_InvalidDebtToCover() (gas: 29343)
[PASS] test_validateLiquidationCall_revertsWith_ReserveNotBorrowed() (gas: 29742)
[PASS] test_validateLiquidationCall_revertsWith_ReserveNotListed_ZeroCollateralHub() (gas: 29440)
[PASS] test_validateLiquidationCall_revertsWith_ReserveNotListed_ZeroDebtHub() (gas: 29497)
[PASS] test_validateLiquidationCall_revertsWith_ReserveNotSupplied() (gas: 29644)
[PASS] test_validateLiquidationCall_revertsWith_ReservePaused_CollateralPaused() (gas: 34376)
[PASS] test_validateLiquidationCall_revertsWith_ReservePaused_DebtPaused() (gas: 34392)
[PASS] test_validateLiquidationCall_revertsWith_SelfLiquidation() (gas: 36299)
Suite result: ok. 12 passed; 0 failed; 0 skipped; finished in 17.53ms (813.47µs CPU time)

Ran 26 tests for tests/unit/MathUtils.t.sol:MathUtilsTest
[PASS] test_add_edge_cases() (gas: 4788)
[PASS] test_add_negative_operand(uint256,int256) (runs: 5000, μ: 9324, ~: 9561)
[PASS] test_add_positive_operand(uint256,int256) (runs: 5000, μ: 4013, ~: 4010)
[PASS] test_calculateLinearInterest() (gas: 4511)
[PASS] test_calculateLinearInterest_add_edge() (gas: 5087)
[PASS] test_calculateLinearInterest_edge_cases() (gas: 16870)
Logs:
  Bound result 0
  Bound result 1
  Bound result 864000000
  Bound result 864000000

[PASS] test_calculateLinearInterest_reverts_on_past_timestamp(uint32) (runs: 5000, μ: 7587, ~: 7508)
[PASS] test_constants() (gas: 3211)
[PASS] test_fuzz_calculateLinearInterest(uint96,uint32,uint256) (runs: 5000, μ: 8698, ~: 8997)
[PASS] test_fuzz_mulDivDown(uint256,uint256,uint256) (runs: 5000, μ: 3491, ~: 3545)
[PASS] test_fuzz_mulDivUp(uint256,uint256,uint256) (runs: 5000, μ: 3666, ~: 3781)
[PASS] test_min(uint256,uint256) (runs: 5000, μ: 3338, ~: 3339)
[PASS] test_mulDivDown_NoRemainder() (gas: 3324)
[PASS] test_mulDivDown_RevertOnDivByZero() (gas: 3191)
[PASS] test_mulDivDown_RevertOnOverflow() (gas: 3203)
[PASS] test_mulDivDown_WithRemainder() (gas: 3236)
[PASS] test_mulDivDown_ZeroAOrB() (gas: 3768)
[PASS] test_mulDivUp_NoRemainder() (gas: 3350)
[PASS] test_mulDivUp_RevertOnDivByZero() (gas: 3146)
[PASS] test_mulDivUp_RevertOnOverflow() (gas: 3204)
[PASS] test_mulDivUp_WithRemainder() (gas: 3349)
[PASS] test_mulDivUp_ZeroAOrB() (gas: 3818)
[PASS] test_signedSub(uint256,uint256) (runs: 5000, μ: 8638, ~: 8594)
[PASS] test_uncheckedAdd(uint256,uint256) (runs: 5000, μ: 3460, ~: 3452)
[PASS] test_uncheckedExp(uint256,uint256) (runs: 5000, μ: 11414, ~: 7241)
[PASS] test_uncheckedSub(uint256,uint256) (runs: 5000, μ: 3457, ~: 3540)
Suite result: ok. 26 passed; 0 failed; 0 skipped; finished in 1.46s (1.45s CPU time)

Ran 34 tests for tests/unit/NativeTokenGateway.t.sol:NativeTokenGatewayTest
[PASS] test_borrowNative() (gas: 622377)
Logs:
  Bound result 5000000000000000000

[PASS] test_borrowNative_fuzz(uint256) (runs: 5000, μ: 622613, ~: 622406)
[PASS] test_borrowNative_fuzz_otherReceiver(uint256) (runs: 5000, μ: 648570, ~: 648363)
[PASS] test_borrowNative_otherReceiver() (gas: 648228)
Logs:
  Bound result 5000000000000000000

[PASS] test_borrowNative_revertsWith_InvalidAddress() (gas: 30629)
[PASS] test_borrowNative_revertsWith_InvalidAmount() (gas: 30671)
[PASS] test_borrowNative_revertsWith_NotNativeWrappedAsset() (gas: 30754)
[PASS] test_constructor() (gas: 1050731)
[PASS] test_constructor_revertsWith_InvalidAddress() (gas: 130011)
[PASS] test_fallback_revertsWith_UnsupportedAction() (gas: 17453)
[PASS] test_receive_revertsWith_UnsupportedAction() (gas: 17216)
[PASS] test_renouncePositionManagerRole() (gas: 44812)
[PASS] test_renouncePositionManagerRole_revertsWith_OwnableUnauthorizedAccount() (gas: 50961)
[PASS] test_repayNative() (gas: 747449)
Logs:
  Bound result 5000000000000000000

[PASS] test_repayNative_excessAmount() (gas: 639220)
[PASS] test_repayNative_fuzz(uint256) (runs: 5000, μ: 747055, ~: 748106)
[PASS] test_repayNative_fuzz_withInterest(uint256,uint256) (runs: 5000, μ: 649558, ~: 643904)
[PASS] test_repayNative_revertsWith_InvalidAmount() (gas: 30645)
[PASS] test_repayNative_revertsWith_NativeAmountMismatch() (gas: 54864)
[PASS] test_repayNative_revertsWith_NotNativeWrappedAsset() (gas: 37450)
[PASS] test_supplyNative() (gas: 234475)
Logs:
  Bound result 100000000000000000000

[PASS] test_supplyNative_fuzz(uint256) (runs: 5000, μ: 234818, ~: 234547)
[PASS] test_supplyNative_revertsWith_InvalidAmount() (gas: 30647)
[PASS] test_supplyNative_revertsWith_NativeAmountMismatch() (gas: 54697)
[PASS] test_supplyNative_revertsWith_NotNativeWrappedAsset() (gas: 37363)
[PASS] test_withdrawNative() (gas: 280647)
Logs:
  Bound result 100000000000000000000

[PASS] test_withdrawNative_fuzz(uint256) (runs: 5000, μ: 280626, ~: 280697)
[PASS] test_withdrawNative_fuzz_allBalance(uint256) (runs: 5000, μ: 234784, ~: 234590)
[PASS] test_withdrawNative_fuzz_allBalanceWithInterest(uint256,uint256) (runs: 5000, μ: 614813, ~: 615980)
[PASS] test_withdrawNative_fuzz_otherReceiver(uint256) (runs: 5000, μ: 264404, ~: 264210)
[PASS] test_withdrawNative_otherReceiver() (gas: 264217)
Logs:
  Bound result 100000000000000000000

[PASS] test_withdrawNative_revertsWith_InvalidAddress() (gas: 30540)
[PASS] test_withdrawNative_revertsWith_InvalidAmount() (gas: 30591)
[PASS] test_withdrawNative_revertsWith_NotNativeWrappedAsset() (gas: 30623)
Suite result: ok. 34 passed; 0 failed; 0 skipped; finished in 73.80s (73.77s CPU time)

Ran 4 tests for tests/unit/NoncesKeyed.t.sol:NoncesKeyedTest
[PASS] test_useCheckedNonce_monotonic(bytes32) (runs: 5000, μ: 16229, ~: 16229)
[PASS] test_useCheckedNonce_revertsWith_InvalidAccountNonce(bytes32) (runs: 5000, μ: 107533, ~: 107533)
[PASS] test_useNonce_monotonic(bytes32) (runs: 5000, μ: 17035, ~: 17035)
[PASS] test_useNonce_zeroKey_monotonic(bytes32) (runs: 5000, μ: 16983, ~: 16983)
Suite result: ok. 4 passed; 0 failed; 0 skipped; finished in 4.66s (4.65s CPU time)

Ran 10 tests for tests/unit/PercentageMath.t.sol:PercentageMathTests
[PASS] test_constants() (gas: 8664)
[PASS] test_fromBpsDown() (gas: 9678)
[PASS] test_percentDiv() (gas: 15222)
[PASS] test_percentDivUp_ge_value(uint256,uint256) (runs: 5000, μ: 15286, ~: 15509)
[PASS] test_percentDivUp_le_value(uint256,uint256) (runs: 5000, μ: 15669, ~: 15662)
[PASS] test_percentDiv_fuzz(uint256,uint256) (runs: 5000, μ: 12881, ~: 13012)
[PASS] test_percentMul() (gas: 15116)
[PASS] test_percentMulUp_ge_value(uint256,uint256) (runs: 5000, μ: 15652, ~: 15645)
[PASS] test_percentMulUp_le_value(uint256,uint256) (runs: 5000, μ: 15289, ~: 15512)
[PASS] test_percentMul_fuzz(uint256,uint256) (runs: 5000, μ: 11763, ~: 12247)
Suite result: ok. 10 passed; 0 failed; 0 skipped; finished in 1.44s (1.44s CPU time)

Ran 29 tests for tests/unit/libraries/PositionStatusMap.t.sol:PositionStatusMapTest
[PASS] test_bucketId() (gas: 8971)
[PASS] test_collateralCount() (gas: 110158)
[PASS] test_collateralCount(uint256) (runs: 5000, μ: 2080037, ~: 1886431)
[PASS] test_collateralCount_ignoresInvalidBits() (gas: 124482)
[PASS] test_constants() (gas: 44966)
[PASS] test_fls() (gas: 545261)
[PASS] test_fromBitId(uint256,uint256) (runs: 5000, μ: 14110, ~: 14336)
[PASS] test_fuzz_setBorrowing(uint256,bool) (runs: 5000, μ: 22353, ~: 32140)
[PASS] test_fuzz_setUseAsCollateral(uint256,bool) (runs: 5000, μ: 22449, ~: 32236)
[PASS] test_getBucketWord(uint256) (runs: 5000, μ: 14489, ~: 14489)
[PASS] test_isUsingAsCollateralOrBorrowing_slot0() (gas: 108801)
[PASS] test_isUsingAsCollateralOrBorrowing_slot1() (gas: 44065)
[PASS] test_isolateBorrowing(uint256) (runs: 5000, μ: 162282, ~: 162282)
[PASS] test_isolateBorrowingUntil(uint256,uint256) (runs: 5000, μ: 154859, ~: 154843)
[PASS] test_isolateCollateral(uint256) (runs: 5000, μ: 162044, ~: 162044)
[PASS] test_isolateCollateralUntil(uint256,uint256) (runs: 5000, μ: 154838, ~: 154822)
[PASS] test_isolateUntil(uint256,uint256) (runs: 5000, μ: 143623, ~: 143623)
[PASS] test_next(uint256) (runs: 5000, μ: 20427, ~: 20328)
[PASS] test_nextBorrowing(uint256) (runs: 5000, μ: 18226, ~: 18289)
[PASS] test_nextBorrowing_continuous() (gas: 63845326)
[PASS] test_nextCollateral(uint256) (runs: 5000, μ: 18118, ~: 17716)
[PASS] test_nextCollateral_continuous() (gas: 64381718)
[PASS] test_next_continuous() (gas: 91795620)
[PASS] test_popCount(bytes32) (runs: 5000, μ: 38133, ~: 38133)
[PASS] test_setBorrowing_slot0() (gas: 44129)
[PASS] test_setBorrowing_slot1() (gas: 44166)
[PASS] test_setUseAsCollateral_slot0() (gas: 44203)
[PASS] test_setUseAsCollateral_slot1() (gas: 44185)
[PASS] test_setters_use_correct_slot(uint256) (runs: 5000, μ: 22195, ~: 22195)
Suite result: ok. 29 passed; 0 failed; 0 skipped; finished in 102.28s (102.28s CPU time)

Ran 5 tests for tests/unit/Rescuable.t.sol:RescuableTest
[PASS] test_constructor() (gas: 12654)
[PASS] test_rescueNative_fuzz(uint256) (runs: 5000, μ: 33691, ~: 33370)
[PASS] test_rescueNative_revertsWith_OnlyRescueGuardian() (gas: 11400)
[PASS] test_rescueToken_fuzz(uint256) (runs: 5000, μ: 209618, ~: 209387)
[PASS] test_rescueToken_revertsWith_OnlyRescueGuardian() (gas: 183212)
Suite result: ok. 5 passed; 0 failed; 0 skipped; finished in 3.46s (3.44s CPU time)

Ran 10 tests for tests/unit/misc/SignatureGateway/SignatureGateway.Constants.t.sol:SignatureGatewayConstantsTest
[PASS] test_DOMAIN_SEPARATOR() (gas: 2038827)
[PASS] test_borrow_typeHash() (gas: 9902)
[PASS] test_constructor() (gas: 2186349)
[PASS] test_eip712Domain() (gas: 2044411)
[PASS] test_repay_typeHash() (gas: 9959)
[PASS] test_setUsingAsCollateral_typeHash() (gas: 9971)
[PASS] test_supply_typeHash() (gas: 9907)
[PASS] test_updateUserDynamicConfig_typeHash() (gas: 9941)
[PASS] test_updateUserRiskPremium_typeHash() (gas: 9904)
[PASS] test_withdraw_typeHash() (gas: 10037)
Suite result: ok. 10 passed; 0 failed; 0 skipped; finished in 18.73ms (1.86ms CPU time)

Ran 4 tests for tests/unit/misc/SignatureGateway/SignatureGateway.PermitReserve.t.sol:SignatureGatewayPermitReserveTest
[PASS] test_permitReserve() (gas: 102481)
[PASS] test_permitReserve_forwards_correct_call() (gas: 49584)
[PASS] test_permitReserve_ignores_permit_reverts() (gas: 38479)
[PASS] test_permitReserve_revertsWith_ReserveNotListed() (gas: 28403)
Suite result: ok. 4 passed; 0 failed; 0 skipped; finished in 18.42ms (1.68ms CPU time)

Ran 2 tests for tests/unit/misc/SignatureGateway/SignatureGateway.Reverts.InsufficientAllowance.t.sol:SignatureGateway_InsufficientAllowance_Test
[PASS] test_repayWithSig_revertsWith_ERC20InsufficientAllowance() (gas: 467207)
[PASS] test_supplyWithSig_revertsWith_ERC20InsufficientAllowance() (gas: 84290)
Suite result: ok. 2 passed; 0 failed; 0 skipped; finished in 19.70ms (2.44ms CPU time)

Ran 21 tests for tests/unit/misc/SignatureGateway/SignatureGateway.Reverts.InvalidSignature.t.sol:SignatureGatewayInvalidSignatureTest
[PASS] test_borrowWithSig_revertsWith_InvalidAccountNonce(bytes32) (runs: 5000, μ: 186150, ~: 186150)
[PASS] test_borrowWithSig_revertsWith_InvalidSignature_dueTo_ExpiredDeadline() (gas: 36133)
[PASS] test_borrowWithSig_revertsWith_InvalidSignature_dueTo_InvalidSigner() (gas: 34575)
[PASS] test_repayWithSig_revertsWith_InvalidAccountNonce(bytes32) (runs: 5000, μ: 186129, ~: 186129)
[PASS] test_repayWithSig_revertsWith_InvalidSignature_dueTo_ExpiredDeadline() (gas: 36089)
[PASS] test_repayWithSig_revertsWith_InvalidSignature_dueTo_InvalidSigner() (gas: 34664)
[PASS] test_setUsingAsCollateralWithSig_revertsWith_InvalidAccountNonce(bytes32) (runs: 5000, μ: 229417, ~: 229417)
[PASS] test_setUsingAsCollateralWithSig_revertsWith_InvalidSignature_dueTo_ExpiredDeadline() (gas: 36146)
[PASS] test_setUsingAsCollateralWithSig_revertsWith_InvalidSignature_dueTo_InvalidSigner() (gas: 34742)
[PASS] test_supplyWithSig_revertsWith_InvalidAccountNonce(bytes32) (runs: 5000, μ: 186214, ~: 186214)
[PASS] test_supplyWithSig_revertsWith_InvalidSignature_dueTo_ExpiredDeadline() (gas: 36156)
[PASS] test_supplyWithSig_revertsWith_InvalidSignature_dueTo_InvalidSigner() (gas: 34651)
[PASS] test_updateUserDynamicConfigWithSig_revertsWith_InvalidAccountNonce(bytes32) (runs: 5000, μ: 64831, ~: 64831)
[PASS] test_updateUserDynamicConfigWithSig_revertsWith_InvalidSignatureDueTo_InvalidSigner() (gas: 23288)
[PASS] test_updateUserDynamicConfigWithSig_revertsWith_InvalidSignature_dueTo_ExpiredDeadline() (gas: 24720)
[PASS] test_updateUserRiskPremiumWithSig_revertsWith_InvalidAccountNonce(bytes32) (runs: 5000, μ: 64842, ~: 64842)
[PASS] test_updateUserRiskPremiumWithSig_revertsWith_InvalidSignatureDueTo_InvalidSigner() (gas: 23272)
[PASS] test_updateUserRiskPremiumWithSig_revertsWith_InvalidSignature_dueTo_ExpiredDeadline() (gas: 24787)
[PASS] test_withdrawWithSig_revertsWith_InvalidAccountNonce(bytes32) (runs: 5000, μ: 186082, ~: 186082)
[PASS] test_withdrawWithSig_revertsWith_InvalidSignature_dueTo_ExpiredDeadline() (gas: 36132)
[PASS] test_withdrawWithSig_revertsWith_InvalidSignature_dueTo_InvalidSigner() (gas: 34618)
Suite result: ok. 21 passed; 0 failed; 0 skipped; finished in 43.54s (43.53s CPU time)

Ran 7 tests for tests/unit/misc/SignatureGateway/SignatureGateway.Reverts.Unauthorized.t.sol:SignatureGateway_Unauthorized_PositionManagerActive_Test
[PASS] test_borrowWithSig_revertsWith_Unauthorized() (gas: 77382)
[PASS] test_repayWithSig_revertsWith_Unauthorized() (gas: 113914)
[PASS] test_setUsingAsCollateralWithSig_revertsWith_Unauthorized() (gas: 69609)
[PASS] test_supplyWithSig_revertsWith_Unauthorized() (gas: 138366)
[PASS] test_updateUserDynamicConfigWithSig_revertsWith_Unauthorized() (gas: 79232)
[PASS] test_updateUserRiskPremiumWithSig_revertsWith_Unauthorized() (gas: 79152)
[PASS] test_withdrawWithSig_revertsWith_Unauthorized() (gas: 99026)
Suite result: ok. 7 passed; 0 failed; 0 skipped; finished in 25.96ms (4.07ms CPU time)

Ran 7 tests for tests/unit/misc/SignatureGateway/SignatureGateway.Reverts.Unauthorized.t.sol:SignatureGateway_Unauthorized_PositionManagerNotActive_Test
[PASS] test_borrowWithSig_revertsWith_Unauthorized() (gas: 75181)
[PASS] test_repayWithSig_revertsWith_Unauthorized() (gas: 111713)
[PASS] test_setUsingAsCollateralWithSig_revertsWith_Unauthorized() (gas: 67408)
[PASS] test_supplyWithSig_revertsWith_Unauthorized() (gas: 136165)
[PASS] test_updateUserDynamicConfigWithSig_revertsWith_Unauthorized() (gas: 77031)
[PASS] test_updateUserRiskPremiumWithSig_revertsWith_Unauthorized() (gas: 76951)
[PASS] test_withdrawWithSig_revertsWith_Unauthorized() (gas: 96825)
Suite result: ok. 7 passed; 0 failed; 0 skipped; finished in 21.27ms (4.02ms CPU time)

Ran 11 tests for tests/unit/misc/SignatureGateway/SignatureGateway.t.sol:SignatureGatewayTest
[PASS] test_borrowWithSig() (gas: 815414)
[PASS] test_renouncePositionManagerRole() (gas: 26616)
[PASS] test_renouncePositionManagerRole_revertsWith_OnlyOwner() (gas: 16173)
[PASS] test_repayWithSig() (gas: 793922)
[PASS] test_setSelfAsUserPositionManagerWithSig() (gas: 309096)
[PASS] test_setUsingAsCollateralWithSig() (gas: 618128)
[PASS] test_supplyWithSig() (gas: 591462)
[PASS] test_updateUserDynamicConfigWithSig() (gas: 321409)
[PASS] test_updateUserRiskPremiumWithSig() (gas: 908847)
[PASS] test_useNonce_monotonic(bytes32) (runs: 5000, μ: 16888, ~: 16888)
[PASS] test_withdrawWithSig() (gas: 600155)
Suite result: ok. 11 passed; 0 failed; 0 skipped; finished in 444.88ms (427.75ms CPU time)

Ran 3 tests for tests/unit/Spoke/Spoke.Access.t.sol:SpokeAccessTest
[PASS] testAccess_change_authority() (gas: 2612833)
[PASS] testAccess_hub_functions_callable_by_spokes() (gas: 603472)
[PASS] testAccess_spoke_admin_config_access() (gas: 490581)
Suite result: ok. 3 passed; 0 failed; 0 skipped; finished in 19.89ms (3.15ms CPU time)

Ran 1 test for tests/unit/Spoke/Spoke.AccrueInterest.Scenario.t.sol:SpokeAccrueInterestScenarioTest
[SKIP: pending rft] test_accrueInterest_fuzz_RPBorrowAndSkipTime_twoActions((uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256),uint32) (runs: 0, μ: 0, ~: 0)
Suite result: ok. 0 passed; 0 failed; 1 skipped; finished in 21.56ms (4.13ms CPU time)

Ran 7 tests for tests/unit/Spoke/Spoke.AccrueInterest.t.sol:SpokeAccrueInterestTest
[PASS] test_accrueInterest_NoActionTaken() (gas: 138289)
[PASS] test_accrueInterest_NoInterest_NoDebt(uint32) (runs: 5000, μ: 661975, ~: 661889)
[PASS] test_accrueInterest_NoInterest_OnlySupply(uint32) (runs: 5000, μ: 258171, ~: 258476)
[PASS] test_accrueInterest_TenPercentRp(uint256,uint32) (runs: 5000, μ: 596271, ~: 597278)
[PASS] test_accrueInterest_fuzz_BorrowAmountAndSkipTime(uint256,uint32) (runs: 5000, μ: 556561, ~: 557145)
[PASS] test_accrueInterest_fuzz_RPBorrowAndSkipTime((uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256),uint32) (runs: 5000, μ: 3940340, ~: 3955179)
[PASS] test_accrueInterest_fuzz_RatesRPBorrowAndSkipTime((uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256),(uint96,uint96,uint96,uint96),uint32) (runs: 5000, μ: 4001240, ~: 4013607)
Suite result: ok. 7 passed; 0 failed; 0 skipped; finished in 212.03s (212.02s CPU time)

Ran 5 tests for tests/unit/Spoke/Spoke.AccrueLiquidityFee.EdgeCases.t.sol:SpokeAccrueLiquidityFeeEdgeCasesTest
[PASS] test_accrueLiquidityFee_fuzz_maxLiquidityFee_with_premium(uint256,uint256,uint256,uint256) (runs: 5000, μ: 558815, ~: 558979)
[PASS] test_accrueLiquidityFee_fuzz_maxLiquidityFee_with_premium_multiple_users(uint256,uint256,uint256,uint256,uint256) (runs: 5000, μ: 801783, ~: 801781)
[PASS] test_accrueLiquidityFee_maxLiquidityFee_multi_spoke() (gas: 588631164)
[PASS] test_accrueLiquidityFee_maxLiquidityFee_multi_user() (gas: 249898145)
[PASS] test_accrueLiquidityFee_maxLiquidityFee_with_premium() (gas: 559298)
Logs:
  Bound result 500000000000000000000
  Bound result 5000
  Bound result 34560000
  Bound result 2

Suite result: ok. 5 passed; 0 failed; 0 skipped; finished in 21.08s (21.07s CPU time)

Ran 7 tests for tests/unit/Spoke/Spoke.AccrueLiquidityFee.t.sol:SpokeAccrueLiquidityFeeTest
[PASS] test_accrueLiquidityFee() (gas: 849338)
[PASS] test_accrueLiquidityFee_NoActionTaken() (gas: 97951)
[PASS] test_accrueLiquidityFee_NoInterest_OnlySupply(uint32) (runs: 5000, μ: 235977, ~: 236129)
[PASS] test_accrueLiquidityFee_exact() (gas: 838364)
[PASS] test_accrueLiquidityFee_fuzz_BorrowAmountAndSkipTime(uint256,uint32) (runs: 5000, μ: 833898, ~: 862555)
[PASS] test_accrueLiquidityFee_maxLiquidityFee() (gas: 553938)
[PASS] test_accrueLiquidityFee_setUsingAsCollateral() (gas: 883851)
Suite result: ok. 7 passed; 0 failed; 0 skipped; finished in 19.26s (19.24s CPU time)

Ran 10 tests for tests/gas/Spoke.Operations.gas.t.sol:SpokeOperations_Gas_Tests
[PASS] test_borrow() (gas: 1166296)
[PASS] test_liquidation() (gas: 8331201)
[PASS] test_multicall_ops() (gas: 1601424)
[PASS] test_repay() (gas: 960132)
[PASS] test_setUserPositionManagerWithSig() (gas: 294022)
[PASS] test_supply() (gas: 948466)
[PASS] test_updateRiskPremium() (gas: 1432467)
[PASS] test_updateUserDynamicConfig() (gas: 513636)
[PASS] test_usingAsCollateral() (gas: 1613261)
[PASS] test_withdraw() (gas: 2100686)
Suite result:...*[Comment body truncated]*
@Kogaroshi Kogaroshi marked this pull request as ready for review October 13, 2025 14:46
/// @notice Inserts packed `key`, `value` at `idx`. Reverts if data exceeds maximum allowed size.
function add(List memory self, uint256 idx, uint256 key, uint256 value) internal pure {
require(key <= _MAX_KEY && value <= _MAX_VALUE, MaxDataSizeExceeded());
require(key < _MAX_KEY && value < _MAX_VALUE, MaxDataSizeExceeded());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this revert in pack instead? also, let's add a dev docs above

@@ -35,8 +35,9 @@ library KeyValueList {
}

/// @notice Inserts packed `key`, `value` at `idx`. Reverts if data exceeds maximum allowed size.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we update the natspec here or move below into @dev too?

@miguelmtzinf miguelmtzinf merged commit 7f949d1 into main Oct 16, 2025
7 checks passed
@miguelmtzinf miguelmtzinf deleted the fix/kvl-add-check branch October 16, 2025 11:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

4 participants