Skip to content

Conversation

@Kogaroshi
Copy link
Contributor

@Kogaroshi Kogaroshi commented Dec 8, 2025

New Position Managers :

  • SupplyRepayPositionManager : allows any user to supply and/or repay on behalf of any other user that activated this PositionManager, with no other permissions or approval required.
  • AllowancePositionManager : allows an user to give withdrawal allowance on their position, as well as credit delegation (all allowance/delegation as given for a specific Spoke and ReserveId pair for each spender), allowing the spender to withdraw from the user position or borrow on the position based on the given allowances/delegations. This PositionManager is also inheriting ERC721, allowing to EIP712-typed intent to grant the allowance/delegation to spenders.
  • PositionConfigPositionManager : allows an user to grand permissions to other users to call setUsingAsCollateral, updateUserRiskPremiumO & updateUserDynamicConfig on their behalf

@github-actions
Copy link

github-actions bot commented Dec 8, 2025

🌈 Test Results
No files changed, compilation skipped

Ran 7 tests for tests/unit/position-managers/SignatureGateway/SignatureGateway.Reverts.Unauthorized.t.sol:SignatureGateway_Unauthorized_PositionManagerNotActive_Test
[PASS] test_borrowWithSig_revertsWith_Unauthorized() (gas: 77610)
[PASS] test_repayWithSig_revertsWith_Unauthorized() (gas: 110918)
[PASS] test_setUsingAsCollateralWithSig_revertsWith_Unauthorized() (gas: 70732)
[PASS] test_supplyWithSig_revertsWith_Unauthorized() (gas: 138527)
[PASS] test_updateUserDynamicConfigWithSig_revertsWith_Unauthorized() (gas: 80289)
[PASS] test_updateUserRiskPremiumWithSig_revertsWith_Unauthorized() (gas: 80141)
[PASS] test_withdrawWithSig_revertsWith_Unauthorized() (gas: 77732)
Suite result: ok. 7 passed; 0 failed; 0 skipped; finished in 23.24ms (4.51ms CPU time)

Ran 4 tests for tests/unit/position-managers/SignatureGateway/SignatureGateway.SetSelfAsUserPositionManagerWithSig.t.sol:SignatureGatewaySetSelfAsUserPositionManagerTest
[PASS] test_setSelfAsUserPositionManagerWithSig() (gas: 136283)
[PASS] test_setSelfAsUserPositionManagerWithSig_forwards_correct_call() (gas: 30879)
[PASS] test_setSelfAsUserPositionManagerWithSig_ignores_underlying_spoke_reverts() (gas: 29894)
[PASS] test_setSelfAsUserPositionManagerWithSig_revertsWith_SpokeNotRegistered() (gas: 16971)
Suite result: ok. 4 passed; 0 failed; 0 skipped; finished in 19.57ms (1.04ms CPU time)

Ran 3 tests for tests/unit/Spoke/Spoke.Access.t.sol:SpokeAccessTest
[PASS] testAccess_change_authority() (gas: 2616614)
[PASS] testAccess_hub_functions_callable_by_spokes() (gas: 579019)
[PASS] testAccess_spoke_admin_config_access() (gas: 494131)
Suite result: ok. 3 passed; 0 failed; 0 skipped; finished in 21.65ms (3.05ms 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),uint40) (runs: 0, μ: 0, ~: 0)
Suite result: ok. 0 passed; 0 failed; 1 skipped; finished in 24.54ms (4.56ms 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, μ: 24542, ~: 24690)
[PASS] test_calculateInterestRate_RightToKinkPoint(uint256) (runs: 5000, μ: 25642, ~: 25690)
[PASS] test_calculateInterestRate_ZeroDebtZeroLiquidity() (gas: 18944)
Logs:
  Bound result 0

[PASS] test_calculateInterestRate_fuzz_ZeroDebt(uint256) (runs: 5000, μ: 19189, ~: 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 1.04s (1.03s CPU time)

Ran 15 tests for tests/unit/position-managers/PositionManagerBase.t.sol:PositionManagerBaseTest
[PASS] test_constructor() (gas: 17626)
[PASS] test_getReserveUnderlying_fuzz(uint256) (runs: 5000, μ: 36272, ~: 36326)
[PASS] test_getReserveUnderlying_revertsWith_ReserveNotListed() (gas: 25378)
[PASS] test_permitReserveUnderlying() (gas: 131453)
[PASS] test_permitReserveUnderlying_forwards_correct_call() (gas: 78385)
[PASS] test_permitReserveUnderlying_ignores_permit_reverts() (gas: 67318)
[PASS] test_permitReserveUnderlying_revertsWith_ReserveNotListed() (gas: 58331)
[PASS] test_registerSpoke_fuzz(address) (runs: 5000, μ: 42113, ~: 42113)
[PASS] test_registerSpoke_revertsWith_InvalidAddress() (gas: 13260)
[PASS] test_registerSpoke_revertsWith_OwnableUnauthorizedAccount() (gas: 14080)
[PASS] test_registerSpoke_unregister() (gas: 36696)
[PASS] test_renouncePositionManagerRole() (gas: 65254)
[PASS] test_renouncePositionManagerRole_revertsWith_InvalidAddress() (gas: 76602)
[PASS] test_renouncePositionManagerRole_revertsWith_OwnableUnauthorizedAccount() (gas: 76896)
[PASS] test_setSelfAsUserPositionManagerWithSig() (gas: 128641)
Suite result: ok. 15 passed; 0 failed; 0 skipped; finished in 872.47ms (853.16ms CPU time)

Ran 8 tests for tests/gas/PositionManagers.Operations.gas.t.sol:AllowancePositionManager_Gas_Tests
[PASS] test_approveWithdraw() (gas: 73889)
[PASS] test_approveWithdrawWithSig() (gas: 239523)
[PASS] test_borrowOnBehalfOf() (gas: 766682)
[PASS] test_creditDelegation() (gas: 73879)
[PASS] test_creditDelegationWithSig() (gas: 239381)
[PASS] test_renounceCreditDelegation() (gas: 98594)
[PASS] test_renounceWithdrawAllowance() (gas: 98634)
[PASS] test_withdrawOnBehalfOf() (gas: 593032)
Suite result: ok. 8 passed; 0 failed; 0 skipped; finished in 36.81ms (3.69ms CPU time)

Ran 5 tests for tests/unit/position-managers/libraries/ConfigPermissions.t.sol:ConfigPermissionsTests
[PASS] test_constants() (gas: 12214)
[PASS] test_setCanSetUsingAsCollateral_fuzz(uint8,bool) (runs: 5000, μ: 10617, ~: 10605)
[PASS] test_setCanUpdateUserDynamicConfig_fuzz(uint8,bool) (runs: 5000, μ: 10641, ~: 10629)
[PASS] test_setCanUpdateUserRiskPremium_fuzz(uint8,bool) (runs: 5000, μ: 10584, ~: 10572)
[PASS] test_setFullPermissions_fuzz(uint8,bool) (runs: 5000, μ: 13546, ~: 13536)
Suite result: ok. 5 passed; 0 failed; 0 skipped; finished in 816.02ms (815.79ms CPU time)

Ran 10 tests for tests/unit/position-managers/libraries/EIP712Hash.t.sol:EIP712HashTest
[PASS] test_constants() (gas: 6214)
[PASS] test_hash_borrow_fuzz((address,uint256,uint256,address,uint256,uint256)) (runs: 5000, μ: 4637, ~: 4637)
[PASS] test_hash_creditDelegation_fuzz((address,uint256,address,address,uint256,uint256,uint256)) (runs: 5000, μ: 5010, ~: 5010)
[PASS] test_hash_repay_fuzz((address,uint256,uint256,address,uint256,uint256)) (runs: 5000, μ: 4615, ~: 4615)
[PASS] test_hash_setUsingAsCollateral_fuzz((address,uint256,bool,address,uint256,uint256)) (runs: 5000, μ: 4880, ~: 4880)
[PASS] test_hash_supply_fuzz((address,uint256,uint256,address,uint256,uint256)) (runs: 5000, μ: 4703, ~: 4703)
[PASS] test_hash_updateUserDynamicConfig_fuzz((address,address,uint256,uint256)) (runs: 5000, μ: 4441, ~: 4441)
[PASS] test_hash_updateUserRiskPremium_fuzz((address,address,uint256,uint256)) (runs: 5000, μ: 4462, ~: 4462)
[PASS] test_hash_withdrawPermit_fuzz((address,uint256,address,address,uint256,uint256,uint256)) (runs: 5000, μ: 5032, ~: 5032)
[PASS] test_hash_withdraw_fuzz((address,uint256,uint256,address,uint256,uint256)) (runs: 5000, μ: 4681, ~: 4681)
Suite result: ok. 10 passed; 0 failed; 0 skipped; finished in 1.29s (1.29s CPU time)

Ran 5 tests for tests/gas/Gateways.Operations.gas.t.sol:NativeTokenGateway_Gas_Tests
[PASS] test_borrowNative() (gas: 921631)
[PASS] test_repayNative() (gas: 996126)
[PASS] test_supplyAndCollateralNative() (gas: 306628)
[PASS] test_supplyNative() (gas: 288375)
[PASS] test_withdrawNative() (gas: 511108)
Suite result: ok. 5 passed; 0 failed; 0 skipped; finished in 36.75ms (4.41ms CPU time)

Ran 17 tests for tests/unit/AaveOracle.t.sol:AaveOracleTest
[PASS] testDECIMALS() (gas: 8379)
[PASS] test_constructor() (gas: 440478)
[PASS] test_deploy_revertsWith_InvalidAddress() (gas: 38111)
[PASS] test_description() (gas: 12049)
[PASS] test_fuzz_constructor(uint8) (runs: 5000, μ: 444403, ~: 444725)
[PASS] test_getReservePrice() (gas: 47398)
[PASS] test_getReservePrice_revertsWith_InvalidPrice() (gas: 46691)
[PASS] test_getReservePrice_revertsWith_InvalidSource() (gas: 10998)
[PASS] test_getReservePrices() (gas: 79462)
[PASS] test_getReservePrices_revertsWith_InvalidSource() (gas: 49374)
[PASS] test_getReserveSource() (gas: 47628)
[PASS] test_setReserveSource() (gas: 44488)
[PASS] test_setReserveSource_revertsWith_InvalidPrice() (gas: 97705)
[PASS] test_setReserveSource_revertsWith_InvalidSource() (gas: 15349)
[PASS] test_setReserveSource_revertsWith_InvalidSourceDecimals() (gas: 15171)
[PASS] test_setReserveSource_revertsWith_OnlySpoke() (gas: 10984)
[PASS] test_spoke() (gas: 10559)
Suite result: ok. 17 passed; 0 failed; 0 skipped; finished in 3.68s (3.67s CPU time)

Ran 11 tests for tests/gas/PositionManagers.Operations.gas.t.sol:PositionConfigPositionManager_Gas_Tests
[PASS] test_renounceGlobalPermission() (gas: 95825)
[PASS] test_renounceUserDynamicConfigPermission() (gas: 95846)
[PASS] test_renounceUserRiskPremiumPermission() (gas: 95848)
[PASS] test_renounceUsingAsCollateralPermission() (gas: 95781)
[PASS] test_setGlobalPermission() (gas: 71610)
[PASS] test_setUserDynamicConfigPermission() (gas: 71557)
[PASS] test_setUserRiskPremiumPermission() (gas: 71604)
[PASS] test_setUsingAsCollateralOnBehalfOf_fuzz_withGlobalPermission() (gas: 146946)
[PASS] test_setUsingAsCollateralPermission() (gas: 71561)
[PASS] test_updateUserDynamicConfigOnBehalfOf_withGlobalPermission() (gas: 122460)
[PASS] test_updateUserRiskPremiumOnBehalfOf_withGlobalPermission() (gas: 715126)
Suite result: ok. 11 passed; 0 failed; 0 skipped; finished in 34.70ms (2.17ms CPU time)

Ran 1 test for tests/gas/PositionManagers.Operations.gas.t.sol:PositionManager_Gas_Tests
[PASS] test_setSelfAsUserPositionManagerWithSig() (gas: 214823)
Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 33.46ms (650.17µs CPU time)

Ran 2 tests for tests/gas/PositionManagers.Operations.gas.t.sol:SupplyRepayPositionManager_Gas_Tests
[PASS] test_repayOnBehalfOf() (gas: 929659)
[PASS] test_supplyOnBehalfOf() (gas: 289260)
Suite result: ok. 2 passed; 0 failed; 0 skipped; finished in 33.98ms (1.84ms CPU time)

Ran 8 tests for tests/gas/Gateways.Operations.gas.t.sol:SignatureGateway_Gas_Tests
[PASS] test_borrowWithSig() (gas: 754995)
[PASS] test_repayWithSig() (gas: 991682)
[PASS] test_setSelfAsUserPositionManagerWithSig() (gas: 208311)
[PASS] test_setUsingAsCollateralWithSig() (gas: 296278)
[PASS] test_supplyWithSig() (gas: 468533)
[PASS] test_updateUserDynamicConfigWithSig() (gas: 145441)
[PASS] test_updateUserRiskPremiumWithSig() (gas: 143002)
[PASS] test_withdrawWithSig() (gas: 418536)
Suite result: ok. 8 passed; 0 failed; 0 skipped; finished in 83.68ms (17.46ms CPU time)

Ran 6 tests for tests/unit/Hub/Hub.Access.t.sol:HubAccessTest
[PASS] test_change_authority() (gas: 2312388)
[PASS] test_change_role_responsibility() (gas: 122065)
[PASS] test_hub_access_manager_exposure() (gas: 12684)
[PASS] test_hub_admin_access() (gas: 1205062)
[PASS] test_migrate_role_responsibility() (gas: 682280)
[PASS] test_setInterestRateData_access() (gas: 103546)
Suite result: ok. 6 passed; 0 failed; 0 skipped; finished in 45.23ms (6.90ms CPU time)

Ran 19 tests for tests/unit/Hub/Hub.Add.t.sol:HubAddTest
[PASS] test_add_AddCapReachedButNotExceeded_rounding() (gas: 674997)
[PASS] test_add_fuzz_AddCapReachedButNotExceeded(uint40) (runs: 5000, μ: 160181, ~: 160147)
[PASS] test_add_fuzz_multi_asset_multi_spoke(uint256,uint256,uint256) (runs: 5000, μ: 330232, ~: 330441)
[PASS] test_add_fuzz_revertsWith_AddCapExceeded(uint40) (runs: 5000, μ: 112996, ~: 112962)
[PASS] test_add_fuzz_revertsWith_AddCapExceeded_due_to_interest(uint40,uint256,uint256) (runs: 5000, μ: 274500, ~: 274376)
[PASS] test_add_fuzz_revertsWith_InvalidShares_due_to_index(uint256,uint256,uint256) (runs: 5000, μ: 229995, ~: 230208)
[PASS] test_add_fuzz_single_asset(uint256,address,uint256) (runs: 5000, μ: 345559, ~: 345452)
[PASS] test_add_fuzz_single_spoke_multi_add(uint256,uint256) (runs: 5000, μ: 822159, ~: 822213)
[PASS] test_add_multi_add_minimal_shares() (gas: 328544)
[PASS] test_add_revertsWith_AmountDowncastOverflow() (gas: 368149)
[PASS] test_add_revertsWith_InsufficientTransferred() (gas: 64867)
[PASS] test_add_revertsWith_InvalidAmount() (gas: 13475)
[PASS] test_add_revertsWith_InvalidShares() (gas: 230124)
[PASS] test_add_revertsWith_SharesDowncastOverflow() (gas: 228043)
[PASS] test_add_revertsWith_SpokeNotActive() (gas: 98590)
[PASS] test_add_revertsWith_SpokePaused() (gas: 98707)
[PASS] test_add_single_asset() (gas: 333479)
Logs:
  Bound result 2
  Bound result 100000000000000000000

[PASS] test_add_with_increased_index() (gas: 308110)
[PASS] test_add_with_increased_index_with_premium() (gas: 688370)
Suite result: ok. 19 passed; 0 failed; 0 skipped; finished in 46.96s (46.93s CPU time)

Ran 9 tests for tests/unit/libraries/KeyValueList.t.sol:KeyValueListTest
[PASS] test_add_unique() (gas: 325391)
[PASS] test_fuzz_add(uint256,uint256) (runs: 5000, μ: 200301, ~: 201361)
[PASS] test_fuzz_add_unique(uint256,uint256) (runs: 5000, μ: 266156, ~: 271836)
[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, μ: 204938, ~: 185091)
[PASS] test_fuzz_sortByKey(uint256[]) (runs: 5000, μ: 464376, ~: 454152)
[PASS] test_fuzz_sortByKey_length(uint256) (runs: 5000, μ: 231682, ~: 241359)
[PASS] test_fuzz_sortByKey_with_collision(uint256[]) (runs: 5000, μ: 547973, ~: 537658)
Suite result: ok. 9 passed; 0 failed; 0 skipped; finished in 72.99s (124.48s 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, μ: 30636, ~: 30638)
[PASS] test_calculateDebtToLiquidate_fuzz_AmountAdjustedDueToDust((uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256)) (runs: 5000, μ: 32368, ~: 32390)
[PASS] test_calculateDebtToLiquidate_fuzz_ImpossibleToAdjustForDust((uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256)) (runs: 5000, μ: 34482, ~: 34400)
Suite result: ok. 3 passed; 0 failed; 0 skipped; finished in 3.29s (5.55s 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, μ: 23059, ~: 23016)
[PASS] test_calculateDebtToTargetHealthFactor_NoPrecisionLoss() (gas: 25208)
[PASS] test_calculateDebtToTargetHealthFactor_PrecisionLoss() (gas: 15209)
[PASS] test_calculateDebtToTargetHealthFactor_UnitPrice() (gas: 25141)
[PASS] test_calculateDebtToTargetHealthFactor_fuzz_NoRevert((uint256,uint256,uint256,uint256,uint256,uint256,uint256)) (runs: 5000, μ: 20120, ~: 20077)
[PASS] test_calculateDebtToTargetHealthFactor_fuzz_revertsWith_DivisionByZero_ZeroAssetPrice((uint256,uint256,uint256,uint256,uint256,uint256,uint256)) (runs: 5000, μ: 22819, ~: 22776)
[PASS] test_calculateDebtToTargetHealthFactor_revertsWith_ArithmeticError_TargetHealthFactorLessThanHealthFactor((uint256,uint256,uint256,uint256,uint256,uint256,uint256)) (runs: 5000, μ: 22902, ~: 22859)
Suite result: ok. 7 passed; 0 failed; 0 skipped; finished in 2.72s (4.72s CPU time)

Ran 16 tests for tests/unit/libraries/LiquidationLogic/LiquidationLogic.EvaluateDeficit.t.sol:LiquidationLogicEvaluateDeficitTest
[PASS] test_evaluateDeficit_CRE_SCCM_DRE_BRCM() (gas: 9012)
[PASS] test_evaluateDeficit_CRE_SCCM_DRE_BRCO() (gas: 8980)
[PASS] test_evaluateDeficit_CRE_SCCM_DRN_BRCM() (gas: 9001)
[PASS] test_evaluateDeficit_CRE_SCCM_DRN_BRCO() (gas: 8968)
[PASS] test_evaluateDeficit_CRE_SCCO_DRE_BRCM() (gas: 8994)
[PASS] test_evaluateDeficit_CRE_SCCO_DRE_BRCO() (gas: 9061)
[PASS] test_evaluateDeficit_CRE_SCCO_DRN_BRCM() (gas: 9026)
[PASS] test_evaluateDeficit_CRE_SCCO_DRN_BRCO() (gas: 9014)
[PASS] test_evaluateDeficit_CRN_SCCM_DRE_BRCM() (gas: 9014)
[PASS] test_evaluateDeficit_CRN_SCCM_DRE_BRCO() (gas: 9003)
[PASS] test_evaluateDeficit_CRN_SCCM_DRN_BRCM() (gas: 8937)
[PASS] test_evaluateDeficit_CRN_SCCM_DRN_BRCO() (gas: 8970)
[PASS] test_evaluateDeficit_CRN_SCCO_DRE_BRCM() (gas: 8947)
[PASS] test_evaluateDeficit_CRN_SCCO_DRE_BRCO() (gas: 9004)
[PASS] test_evaluateDeficit_CRN_SCCO_DRN_BRCM() (gas: 8955)
[PASS] test_evaluateDeficit_CRN_SCCO_DRN_BRCO() (gas: 9033)
Suite result: ok. 16 passed; 0 failed; 0 skipped; finished in 20.54ms (944.52µs CPU time)

Ran 5 tests for tests/unit/libraries/LiquidationLogic/LiquidationLogic.LiquidateCollateral.t.sol:LiquidationLogicLiquidateCollateralTest
[PASS] test_liquidateCollateral_fuzz(uint256,uint256) (runs: 5000, μ: 268330, ~: 269280)
[PASS] test_liquidateCollateral_fuzz_CollateralToLiquidatorIsZero(uint256) (runs: 5000, μ: 110221, ~: 110942)
[PASS] test_liquidateCollateral_fuzz_receiveShares_sharesToLiquidator(uint256,uint256) (runs: 5000, μ: 754671, ~: 755973)
[PASS] test_liquidateCollateral_fuzz_revertsWith_ArithmeticUnderflow(uint256,uint256) (runs: 5000, μ: 100459, ~: 100270)
[PASS] test_liquidateCollateral_receiveShares_sharesToLiquidatorIsZero() (gas: 741483)
Suite result: ok. 5 passed; 0 failed; 0 skipped; finished in 13.19s (14.53s 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, μ: 2027843, ~: 1810514)
[PASS] test_collateralCount_ignoresInvalidBits() (gas: 124482)
[PASS] test_constants() (gas: 44966)
[PASS] test_fls() (gas: 545261)
[PASS] test_fromBitId(uint256,uint256) (runs: 5000, μ: 14156, ~: 14452)
[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: 109180)
[PASS] test_isUsingAsCollateralOrBorrowing_slot1() (gas: 44203)
[PASS] test_isolateBorrowing(uint256) (runs: 5000, μ: 162282, ~: 162282)
[PASS] test_isolateBorrowingUntil(uint256,uint256) (runs: 5000, μ: 153516, ~: 153033)
[PASS] test_isolateCollateral(uint256) (runs: 5000, μ: 162044, ~: 162044)
[PASS] test_isolateCollateralUntil(uint256,uint256) (runs: 5000, μ: 153495, ~: 153012)
[PASS] test_isolateUntil(uint256,uint256) (runs: 5000, μ: 143593, ~: 143583)
[PASS] test_next(uint256) (runs: 5000, μ: 20236, ~: 19157)
[PASS] test_nextBorrowing(uint256) (runs: 5000, μ: 18188, ~: 18289)
[PASS] test_nextBorrowing_continuous() (gas: 63845326)
[PASS] test_nextCollateral(uint256) (runs: 5000, μ: 17949, ~: 17116)
[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 99.17s (99.16s CPU time)

Ran 34 tests for tests/unit/position-managers/PositionConfigPositionManager.t.sol:PositionConfigPositionManagerTest
[PASS] test_renounceGlobalPermission() (gas: 42892)
[PASS] test_renounceGlobalPermission_revertsWith_SpokeNotRegistered() (gas: 17627)
[PASS] test_renounceUserDynamicConfigPermission() (gas: 41532)
[PASS] test_renounceUserDynamicConfigPermission_revertsWith_SpokeNotRegistered() (gas: 17757)
[PASS] test_renounceUserRiskPremiumPermission() (gas: 41568)
[PASS] test_renounceUserRiskPremiumPermission_revertsWith_SpokeNotRegistered() (gas: 17628)
[PASS] test_renounceUsingAsCollateralPermission() (gas: 41505)
[PASS] test_renounceUsingAsCollateralPermission_revertsWith_SpokeNotRegistered() (gas: 17693)
[PASS] test_setGlobalPermission() (gas: 56206)
[PASS] test_setGlobalPermission_fuzz(bool) (runs: 5000, μ: 38309, ~: 24641)
[PASS] test_setGlobalPermission_removeAllPermissions() (gas: 43048)
[PASS] test_setGlobalPermission_removePreviousPermissions() (gas: 47222)
[PASS] test_setGlobalPermission_revertsWith_SpokeNotRegistered() (gas: 17829)
[PASS] test_setUserDynamicConfigPermission() (gas: 54323)
[PASS] test_setUserDynamicConfigPermission_remove() (gas: 41689)
[PASS] test_setUserDynamicConfigPermission_revertsWith_SpokeNotRegistered() (gas: 17784)
[PASS] test_setUserRiskPremiumPermission() (gas: 54304)
[PASS] test_setUserRiskPremiumPermission_remove() (gas: 41710)
[PASS] test_setUserRiskPremiumPermission_revertsWith_SpokeNotRegistered() (gas: 17828)
[PASS] test_setUsingAsCollateralOnBehalfOf_fuzz_withGlobalPermission(uint256,bool) (runs: 5000, μ: 103913, ~: 108894)
[PASS] test_setUsingAsCollateralOnBehalfOf_fuzz_withPermission(uint256,bool) (runs: 5000, μ: 103870, ~: 108851)
[PASS] test_setUsingAsCollateralOnBehalfOf_revertsWith_CallerNotAllowed() (gas: 22561)
[PASS] test_setUsingAsCollateralOnBehalfOf_revertsWith_SpokeNotRegistered() (gas: 17877)
[PASS] test_setUsingAsCollateralPermission() (gas: 54271)
[PASS] test_setUsingAsCollateralPermission_remove() (gas: 41648)
[PASS] test_setUsingAsCollateralPermission_revertsWith_SpokeNotRegistered() (gas: 17786)
[PASS] test_updateUserDynamicConfigOnBehalfOf_revertsWith_CallerNotAllowed() (gas: 20113)
[PASS] test_updateUserDynamicConfigOnBehalfOf_revertsWith_SpokeNotRegistered() (gas: 17715)
[PASS] test_updateUserDynamicConfigOnBehalfOf_withGlobalPermission() (gas: 69242)
[PASS] test_updateUserDynamicConfigOnBehalfOf_withPermission() (gas: 69240)
[PASS] test_updateUserRiskPremiumOnBehalfOf_revertsWith_CallerNotAllowed() (gas: 20180)
[PASS] test_updateUserRiskPremiumOnBehalfOf_revertsWith_SpokeNotRegistered() (gas: 17738)
[PASS] test_updateUserRiskPremiumOnBehalfOf_withGlobalPermission() (gas: 682814)
[PASS] test_updateUserRiskPremiumOnBehalfOf_withPermission() (gas: 682836)
Suite result: ok. 34 passed; 0 failed; 0 skipped; finished in 109.21s (109.18s CPU time)

Ran 8 tests for tests/unit/libraries/LiquidationLogic/LiquidationLogic.LiquidationAmounts.t.sol:LiquidationLogicLiquidationAmountsTest
[PASS] test_calculateLiquidationAmounts_EnoughCollateral() (gas: 15487)
[PASS] test_calculateLiquidationAmounts_InsufficientCollateral() (gas: 15739)
[PASS] test_calculateLiquidationAmounts_fuzz_EnoughCollateral_CollateralDust((uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256)) (runs: 5000, μ: 57015, ~: 56825)
[PASS] test_calculateLiquidationAmounts_fuzz_EnoughCollateral_NoCollateralDust((uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256)) (runs: 5000, μ: 56020, ~: 56003)
[PASS] test_calculateLiquidationAmounts_fuzz_EnoughCollateral_NoDebtLeft((uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256)) (runs: 5000, μ: 72627, ~: 72483)
[PASS] test_calculateLiquidationAmounts_fuzz_InsufficientCollateral((uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256)) (runs: 5000, μ: 59626, ~: 59507)
[PASS] test_calculateLiquidationAmounts_fuzz_revertsWith_MustNotLeaveDust_Collateral((uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256)) (runs: 5000, μ: 56340, ~: 56155)
[PASS] test_calculateLiquidationAmounts_fuzz_revertsWith_MustNotLeaveDust_Debt((uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256)) (runs: 5000, μ: 69164, ~: 69097)
Suite result: ok. 8 passed; 0 failed; 0 skipped; finished in 17.31s (17.29s CPU time)

Ran 4 tests for tests/unit/libraries/LiquidationLogic/LiquidationLogic.LiquidationBonus.t.sol:LiquidationLogicLiquidationBonusTest
[PASS] test_calculateLiquidationBonus_MinBonusDueToRounding() (gas: 9317)
[PASS] test_calculateLiquidationBonus_PartialBonus() (gas: 9338)
[PASS] test_calculateLiquidationBonus_fuzz_ConstantBonus(uint256,uint256,uint256,uint256) (runs: 5000, μ: 17336, ~: 17135)
[PASS] test_calculateLiquidationBonus_fuzz_MaxBonus(uint256,uint256,uint256,uint256) (runs: 5000, μ: 19623, ~: 19420)
Suite result: ok. 4 passed; 0 failed; 0 skipped; finished in 978.44ms (959.20ms CPU time)

Ran 12 tests for tests/unit/libraries/LiquidationLogic/LiquidationLogic.ValidateLiquidationCall.t.sol:LiquidationLogicValidateLiquidationCallTest
[PASS] test_validateLiquidationCall() (gas: 26157)
[PASS] test_validateLiquidationCall_revertsWith_CannotReceiveShares() (gas: 262562)
[PASS] test_validateLiquidationCall_revertsWith_CollateralCannotBeLiquidated() (gas: 46049)
[PASS] test_validateLiquidationCall_revertsWith_HealthFactorNotBelowThreshold() (gas: 32053)
[PASS] test_validateLiquidationCall_revertsWith_InvalidDebtToCover() (gas: 27026)
[PASS] test_validateLiquidationCall_revertsWith_ReserveNotBorrowed() (gas: 27145)
[PASS] test_validateLiquidationCall_revertsWith_ReserveNotEnabledAsCollateral_NotUsingAsCollateral() (gas: 27266)
[PASS] test_validateLiquidationCall_revertsWith_ReserveNotEnabledAsCollateral_ZeroCollateralFactor() (gas: 27282)
[PASS] test_validateLiquidationCall_revertsWith_ReserveNotSupplied() (gas: 27112)
[PASS] test_validateLiquidationCall_revertsWith_ReservePaused_CollateralPaused() (gas: 32175)
[PASS] test_validateLiquidationCall_revertsWith_ReservePaused_DebtPaused() (gas: 32175)
[PASS] test_validateLiquidationCall_revertsWith_SelfLiquidation() (gas: 33938)
Suite result: ok. 12 passed; 0 failed; 0 skipped; finished in 30.96ms (1.46ms CPU time)

Ran 26 tests for tests/unit/MathUtils.t.sol:MathUtilsTest
[PASS] test_add_edge_cases() (gas: 4854)
[PASS] test_add_negative_operand(uint256,int256) (runs: 5000, μ: 9258, ~: 9012)
[PASS] test_add_positive_operand(uint256,int256) (runs: 5000, μ: 4015, ~: 4010)
[PASS] test_calculateLinearInterest() (gas: 4467)
[PASS] test_calculateLinearInterest_add_edge() (gas: 5043)
[PASS] test_calculateLinearInterest_edge_cases() (gas: 16815)
Logs:
  Bound result 0
  Bound result 1
  Bound result 864000000
  Bound result 864000000

[PASS] test_calculateLinearInterest_reverts_on_past_timestamp(uint40) (runs: 5000, μ: 7700, ~: 7550)
[PASS] test_constants() (gas: 3167)
[PASS] test_fuzz_calculateLinearInterest(uint96,uint40,uint256) (runs: 5000, μ: 8754, ~: 8996)
[PASS] test_fuzz_mulDivDown(uint256,uint256,uint256) (runs: 5000, μ: 3577, ~: 3634)
[PASS] test_fuzz_mulDivUp(uint256,uint256,uint256) (runs: 5000, μ: 3660, ~: 3781)
[PASS] test_min(uint256,uint256) (runs: 5000, μ: 3338, ~: 3339)
[PASS] test_mulDivDown_NoRemainder() (gas: 3302)
[PASS] test_mulDivDown_RevertOnDivByZero() (gas: 3147)
[PASS] test_mulDivDown_RevertOnOverflow() (gas: 3181)
[PASS] test_mulDivDown_WithRemainder() (gas: 3236)
[PASS] test_mulDivDown_ZeroAOrB() (gas: 3768)
[PASS] test_mulDivUp_NoRemainder() (gas: 3306)
[PASS] test_mulDivUp_RevertOnDivByZero() (gas: 3102)
[PASS] test_mulDivUp_RevertOnOverflow() (gas: 3160)
[PASS] test_mulDivUp_WithRemainder() (gas: 3305)
[PASS] test_mulDivUp_ZeroAOrB() (gas: 3884)
[PASS] test_signedSub(uint256,uint256) (runs: 5000, μ: 8714, ~: 8661)
[PASS] test_uncheckedAdd(uint256,uint256) (runs: 5000, μ: 3416, ~: 3408)
[PASS] test_uncheckedExp(uint256,uint256) (runs: 5000, μ: 11998, ~: 9316)
[PASS] test_uncheckedSub(uint256,uint256) (runs: 5000, μ: 3435, ~: 3518)
Suite result: ok. 26 passed; 0 failed; 0 skipped; finished in 1.76s (1.75s CPU time)

Ran 5 tests for tests/unit/Rescuable.t.sol:RescuableTest
[PASS] test_constructor() (gas: 12654)
[PASS] test_rescueNative_fuzz(uint256) (runs: 5000, μ: 33714, ~: 33899)
[PASS] test_rescueNative_revertsWith_OnlyRescueGuardian() (gas: 11400)
[PASS] test_rescueToken_fuzz(uint256) (runs: 5000, μ: 209645, ~: 209774)
[PASS] test_rescueToken_revertsWith_OnlyRescueGuardian() (gas: 183215)
Suite result: ok. 5 passed; 0 failed; 0 skipped; finished in 3.30s (6.23s CPU time)

Ran 10 tests for tests/unit/position-managers/SignatureGateway/SignatureGateway.Constants.t.sol:SignatureGatewayConstantsTest
[PASS] test_DOMAIN_SEPARATOR() (gas: 2049139)
[PASS] test_borrow_typeHash() (gas: 9874)
[PASS] test_constructor() (gas: 53326)
[PASS] test_eip712Domain() (gas: 2054726)
[PASS] test_repay_typeHash() (gas: 9975)
[PASS] test_setUsingAsCollateral_typeHash() (gas: 9943)
[PASS] test_supply_typeHash() (gas: 9945)
[PASS] test_updateUserDynamicConfig_typeHash() (gas: 9915)
[PASS] test_updateUserRiskPremium_typeHash() (gas: 9876)
[PASS] test_withdraw_typeHash() (gas: 9919)
Suite result: ok. 10 passed; 0 failed; 0 skipped; finished in 20.32ms (1.77ms CPU time)

Ran 5 tests for tests/unit/position-managers/SignatureGateway/SignatureGateway.PermitReserve.t.sol:SignatureGatewayPermitReserveTest
[PASS] test_permitReserve() (gas: 103953)
[PASS] test_permitReserve_forwards_correct_call() (gas: 51093)
[PASS] test_permitReserve_ignores_permit_reverts() (gas: 39973)
[PASS] test_permitReserve_revertsWith_ReserveNotListed() (gas: 30938)
[PASS] test_permitReserve_revertsWith_SpokeNotRegistered() (gas: 29497)
Suite result: ok. 5 passed; 0 failed; 0 skipped; finished in 20.32ms (1.34ms CPU time)

Ran 8 tests for tests/unit/ReserveFlags.t.sol:ReserveFlagsTests
[PASS] test_constants() (gas: 13620)
[PASS] test_create_fuzz(bool,bool,bool,bool,bool) (runs: 5000, μ: 16485, ~: 16492)
[PASS] test_setBorrowable_fuzz(uint8) (runs: 5000, μ: 13414, ~: 13414)
[PASS] test_setFrozen_fuzz(uint8) (runs: 5000, μ: 13422, ~: 13422)
[PASS] test_setLiquidatable_fuzz(uint8) (runs: 5000, μ: 13422, ~: 13422)
[PASS] test_setPaused_fuzz(uint8) (runs: 5000, μ: 13297, ~: 13297)
[PASS] test_setReceiveSharesEnabled_fuzz(uint8) (runs: 5000, μ: 13405, ~: 13405)
[PASS] test_set_flags() (gas: 95757)
Suite result: ok. 8 passed; 0 failed; 0 skipped; finished in 1.67s (2.18s CPU time)

Ran 2 tests for tests/unit/position-managers/SignatureGateway/SignatureGateway.Reverts.InsufficientAllowance.t.sol:SignatureGateway_InsufficientAllowance_Test
[PASS] test_repayWithSig_revertsWith_ERC20InsufficientAllowance() (gas: 455775)
[PASS] test_supplyWithSig_revertsWith_ERC20InsufficientAllowance() (gas: 84051)
Suite result: ok. 2 passed; 0 failed; 0 skipped; finished in 22.75ms (3.47ms CPU time)

Ran 21 tests for tests/unit/position-managers/SignatureGateway/SignatureGateway.Reverts.InvalidSignature.t.sol:SignatureGatewayInvalidSignatureTest
[PASS] test_borrowWithSig_revertsWith_InvalidAccountNonce(bytes32) (runs: 5000, μ: 186190, ~: 186190)
[PASS] test_borrowWithSig_revertsWith_InvalidSignature_dueTo_ExpiredDeadline() (gas: 38493)
[PASS] test_borrowWithSig_revertsWith_InvalidSignature_dueTo_InvalidSigner() (gas: 36935)
[PASS] test_repayWithSig_revertsWith_InvalidAccountNonce(bytes32) (runs: 5000, μ: 186146, ~: 186146)
[PASS] test_repayWithSig_revertsWith_InvalidSignature_dueTo_ExpiredDeadline() (gas: 38426)
[PASS] test_repayWithSig_revertsWith_InvalidSignature_dueTo_InvalidSigner() (gas: 37001)
[PASS] test_setUsingAsCollateralWithSig_revertsWith_InvalidAccountNonce(bytes32) (runs: 5000, μ: 228362, ~: 228362)
[PASS] test_setUsingAsCollateralWithSig_revertsWith_InvalidSignature_dueTo_ExpiredDeadline() (gas: 38409)
[PASS] test_setUsingAsCollateralWithSig_revertsWith_InvalidSignature_dueTo_InvalidSigner() (gas: 37005)
[PASS] test_supplyWithSig_revertsWith_InvalidAccountNonce(bytes32) (runs: 5000, μ: 186209, ~: 186209)
[PASS] test_supplyWithSig_revertsWith_InvalidSignature_dueTo_ExpiredDeadline() (gas: 38471)
[PASS] test_supplyWithSig_revertsWith_InvalidSignature_dueTo_InvalidSigner() (gas: 36966)
[PASS] test_updateUserDynamicConfigWithSig_revertsWith_InvalidAccountNonce(bytes32) (runs: 5000, μ: 67401, ~: 67401)
[PASS] test_updateUserDynamicConfigWithSig_revertsWith_InvalidSignatureDueTo_InvalidSigner() (gas: 25553)
[PASS] test_updateUserDynamicConfigWithSig_revertsWith_InvalidSignature_dueTo_ExpiredDeadline() (gas: 26985)
[PASS] test_updateUserRiskPremiumWithSig_revertsWith_InvalidAccountNonce(bytes32) (runs: 5000, μ: 67356, ~: 67356)
[PASS] test_updateUserRiskPremiumWithSig_revertsWith_InvalidSignatureDueTo_InvalidSigner() (gas: 25470)
[PASS] test_updateUserRiskPremiumWithSig_revertsWith_InvalidSignature_dueTo_ExpiredDeadline() (gas: 26985)
[PASS] test_withdrawWithSig_revertsWith_InvalidAccountNonce(bytes32) (runs: 5000, μ: 186165, ~: 186165)
[PASS] test_withdrawWithSig_revertsWith_InvalidSignature_dueTo_ExpiredDeadline() (gas: 38535)
[PASS] test_withdrawWithSig_revertsWith_InvalidSignature_dueTo_InvalidSigner() (gas: 37021)
Suite result: ok. 21 passed; 0 failed; 0 skipped; finished in 42.84s (67.02s CPU time)

Ran 36 tests for tests/unit/Hub/Hub.Config.t.sol:HubConfigTest
[PASS] test_addAsset_fuzz(address,uint8,address) (runs: 5000, μ: 916150, ~: 916184)
[PASS] test_addAsset_fuzz_revertsWith_InvalidAddress_feeReceiver(address,uint8,address) (runs: 5000, μ: 46606, ~: 46787)
[PASS] test_addAsset_fuzz_revertsWith_InvalidAddress_irStrategy(address,uint8,address) (runs: 5000, μ: 46637, ~: 46818)
[PASS] test_addAsset_fuzz_revertsWith_InvalidAddress_underlying(uint8,address,address) (runs: 5000, μ: 37590, ~: 37590)
[PASS] test_addAsset_fuzz_revertsWith_InvalidAssetDecimals(address,uint8,address,address) (runs: 5000, μ: 47157, ~: 46949)
[PASS] test_addAsset_fuzz_revertsWith_InvalidAssetDecimals_tooLow(address,uint8,address,address) (runs: 5000, μ: 47408, ~: 47648)
[PASS] test_addAsset_fuzz_reverts_InvalidIrData(address,uint8,address,address) (runs: 5000, μ: 40970, ~: 36219)
[PASS] test_addAsset_revertsWith_BlockTimestampDowncastOverflow() (gas: 767690)
[PASS] test_addAsset_revertsWith_DrawnRateDowncastOverflow() (gas: 764636)
[PASS] test_addAsset_reverts_UnderlyingAlreadyListed() (gas: 47752)
[PASS] test_addSpoke_fuzz(uint256,(uint40,uint40,uint24,bool,bool)) (runs: 5000, μ: 125864, ~: 125918)
[PASS] test_addSpoke_fuzz_revertsWith_AssetNotListed(uint256,(uint40,uint40,uint24,bool,bool)) (runs: 5000, μ: 34744, ~: 34731)
[PASS] test_addSpoke_fuzz_revertsWith_InvalidAddress_spoke(uint256,(uint40,uint40,uint24,bool,bool)) (runs: 5000, μ: 33333, ~: 33387)
[PASS] test_addSpoke_revertsWith_SpokeAlreadyListed() (gas: 38876)
[PASS] test_hub_deploy_revertsWith_InvalidAddress() (gas: 47579)
[PASS] test_hub_max_riskPremium() (gas: 8570)
[PASS] test_updateAssetConfig_NewFeeReceiver_noFees() (gas: 731780)
[PASS] test_updateAssetConfig_NewFeeReceiver_revertsWith_SpokeNotActive_noFees() (gas: 625973)
[PASS] test_updateAssetConfig_UseExistingSpokeAndListedAsFeeReceiver_revertsWith_SpokeAlreadyListed() (gas: 72068)
[PASS] test_updateAssetConfig_fuzz(uint256,(address,uint16,address,address)) (runs: 5000, μ: 269281, ~: 269552)
[PASS] test_updateAssetConfig_fuzz_FromZeroLiquidityFee(uint256,uint16) (runs: 5000, μ: 823120, ~: 823071)
[PASS] test_updateAssetConfig_fuzz_LiquidityFee(uint256,uint16) (runs: 5000, μ: 725275, ~: 725226)
[PASS] test_updateAssetConfig_fuzz_NewFeeReceiver(uint256) (runs: 5000, μ: 831445, ~: 831564)
[PASS] test_updateAssetConfig_fuzz_NewInterestRateStrategy(uint256) (runs: 5000, μ: 1208198, ~: 1208317)
[PASS] test_updateAssetConfig_fuzz_ReuseFeeReceiver_revertsWith_SpokeAlreadyListed(uint256) (runs: 5000, μ: 883691, ~: 883810)
[PASS] test_updateAssetConfig_fuzz_Scenario(uint256) (runs: 5000, μ: 682861, ~: 682913)
[PASS] test_updateAssetConfig_fuzz_UseExistingSpokeAsFeeReceiver_revertsWith_SpokeAlreadyListed(uint256) (runs: 5000, μ: 71740, ~: 71740)
[PASS] test_updateAssetConfig_fuzz_revertsWith_InvalidInterestRateStrategy(uint256) (runs: 5000, μ: 59943, ~: 59995)
[PASS] test_updateAssetConfig_fuzz_revertsWith_InvalidLiquidityFee(uint256,(address,uint16,address,address)) (runs: 5000, μ: 41406, ~: 41307)
[PASS] test_updateAssetConfig_fuzz_revertsWith_InvalidReinvestmentController() (gas: 490561)
[PASS] test_updateAssetConfig_fuzz_revertsWith_calculateInterestRateReverts(uint256,(address,uint16,address,address)) (runs: 5000, μ: 202679, ~: 202951)
[PASS] test_updateAssetConfig_fuzz_revertsWith_setInterestRateDataReverts(uint256,(address,uint16,address,address)) (runs: 5000, μ: 65521, ~: 65421)
[PASS] test_updateAssetConfig_oldFeeReceiver_flags() (gas: 844758)
Logs:
  Bound result 1
  Bound result 500
  Bound result 3
  Bound result 1000
  Bound result 5
  Bound result 500
  Bound result 3
  Bound result 1000

[PASS] test_updateSpokeConfig_fuzz(uint256,(uint40,uint40,uint24,bool,bool)) (runs: 5000, μ: 58475, ~: 58537)
[PASS] test_updateSpokeConfig_fuzz_revertsWith_SpokeNotListed(uint256,address,(uint40,uint40,uint24,bool,bool)) (runs: 5000, μ: 40444, ~: 40504)
[PASS] test_updateSpokeConfig_revertsWith_AssetNotListed() (gas: 29356)
Suite result: ok. 36 passed; 0 failed; 0 skipped; finished in 97.72s (97.70s CPU time)

Ran 7 tests for tests/unit/position-managers/SignatureGateway/SignatureGateway.Reverts.SpokeNotRegistered.t.sol:SignatureGateway_SpokeNotRegistered_Test
[PASS] test_borrowWithSig_revertsWith_SpokeNotRegistered((address,uint256,uint256,address,uint256,uint256)) (runs: 5000, μ: 13878, ~: 13878)
[PASS] test_repayWithSig_revertsWith_SpokeNotRegistered((address,uint256,uint256,address,uint256,uint256)) (runs: 5000, μ: 13878, ~: 13878)
[PASS] test_setUsingAsCollateralWithSig_revertsWith_SpokeNotRegistered((address,uint256,bool,address,uint256,uint256)) (runs: 5000, μ: 13879, ~: 13879)
[PASS] test_supplyWithSig_revertsWith_SpokeNotRegistered((address,uint256,uint256,address,uint256,uint256)) (runs: 5000, μ: 13876, ~: 13876)
[PASS] test_updateUserDynamicConfigWithSig_revertsWith_SpokeNotRegistered((address,address,uint256,uint256)) (runs: 5000, μ: 14112, ~: 14112)
[PASS] test_updateUserRiskPremiumWithSig_revertsWith_SpokeNotRegistered((address,address,uint256,uint256)) (runs: 5000, μ: 14024, ~: 14024)
[PASS] test_withdrawWithSig_revertsWith_SpokeNotRegistered((address,uint256,uint256,address,uint256,uint256)) (runs: 5000, μ: 13965, ~: 13965)
Suite result: ok. 7 passed; 0 failed; 0 skipped; finished in 8.89s (13.45s CPU time)

Ran 7 tests for tests/unit/position-managers/SignatureGateway/SignatureGateway.Reverts.Unauthorized.t.sol:SignatureGateway_Unauthorized_PositionManagerActive_Test
[PASS] test_borrowWithSig_revertsWith_Unauthorized() (gas: 79811)
[PASS] test_repayWithSig_revertsWith_Unauthorized() (gas: 113119)
[PASS] test_setUsingAsCollateralWithSig_revertsWith_Unauthorized() (gas: 72933)
[PASS] test_supplyWithSig_revertsWith_Unauthorized() (gas: 140728)
[PASS] test_updateUserDynamicConfigWithSig_revertsWith_Unauthorized() (gas: 82490)
[PASS] test_updateUserRiskPremiumWithSig_revertsWith_Unauthorized() (gas: 82342)
[PASS] test_withdrawWithSig_revertsWith_Unauthorized() (gas: 79933)
Suite result: ok. 7 passed; 0 failed; 0 skipped; finished in 23.81ms (4.14ms CPU time)

Ran 1 test for tests/unit/Spoke/Spoke.MultipleHub.IsolationMode.t.sol:SpokeMultipleHubIsolationModeTest
[PASS] test_isolation_mode() (gas: 1443256)
Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 10.42ms (2.46ms CPU time)

Ran 1 test for tests/unit/Spoke/Spoke.MultipleHub.SiloedBorrowing.t.sol:SpokeMultipleHubSiloedBorrowingTest
[PASS] test_siloed_borrowing() (gas: 667131)
Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 8.65ms (1.15ms CPU time)

Ran 2 tests for tests/unit/Spoke/Spoke.MultipleHub.t.sol:SpokeMultipleHubTest
[PASS] test_borrow_secondHub() (gas: 895549)
[PASS] test_borrow_thirdHub() (gas: 737841)
Suite result: ok. 2 passed; 0 failed; 0 skipped; finished in 26.94ms (3.68ms CPU time)

Ran 13 tests for tests/gas/Spoke.Operations.gas.t.sol:SpokeOperations_Gas_Tests
[PASS] test_borrow() (gas: 1335928)
[PASS] test_liquidation_full() (gas: 1891814)
[PASS] test_liquidation_partial() (gas: 1891523)
[PASS] test_liquidation_receiveShares_full() (gas: 1881508)
[PASS] test_liquidation_receiveShares_partial() (gas: 1881225)
[PASS] test_multicall_ops() (gas: 1410878)
[PASS] test_repay() (gas: 875638)
[PASS] test_setUserPositionManagerWithSig() (gas: 303733)
[PASS] test_supply() (gas: 542220)
[PASS] test_updateRiskPremium() (gas: 1327300)
[PASS] test_updateUserDynamicConfig() (gas: 581796)
[PASS] test_usingAsCollateral() (gas: 1481373)
[PASS] test_withdraw() (gas: 1962523)
Suite result: ok. 13 passed; 0 failed; 0 skipped; finished in 65.06ms (30.70ms CPU time)

Ran 13 tests for tests/gas/Spoke.Operations.gas.t.sol:SpokeOperations_ZeroRiskPremium_Gas_Tests
[PASS] test_borrow() (gas: 1096592)
[PASS] test_liquidation_full() (gas: 1754099)
[PASS] test_liquidation_partial() (gas: 1753808)
[PASS] test_liquidation_receiveShares_full() (gas: 1743793)
[PASS] test_liquidation_receiveShares_partial() (gas: 1743510)
[PASS] test_multicall_ops() (gas: 1327357)
[PASS] test_repay() (gas: 783166)
[PASS] test_setUserPositionManagerWithSig() (gas: 308181)
[PASS] test_supply() (gas: 544892)
[PASS] test_updateRiskPremium() (gas: 942460)
[PASS] test_updateUserDynamicConfig() (gas: 586244)
[PASS] test_usingAsCollateral() (gas: 1087205)
[PASS] test_withdraw() (gas: 1593456)
Suite result: ok. 13 passed; 0 failed; 0 skipped; finished in 60.31ms (26.22ms CPU time)

Ran 4 tests for tests/unit/Spoke/Spoke.PermitReserve.t.sol:SpokePermitReserveTest
[PASS] test_permitReserve() (gas: 89200)
[PASS] test_permitReserve_forwards_correct_call() (gas: 36410)
[PASS] test_permitReserve_ignores_permit_reverts() (gas: 25167)
[PASS] test_permitReserve_revertsWith_ReserveNotListedIn() (gas: 23207)
Suite result: ok. 4 passed; 0 failed; 0 skipped; finished in 19.67ms (1.02ms CPU time)

Ran 33 tests for tests/unit/position-managers/NativeTokenGateway.t.sol:NativeTokenGatewayTest
[PASS] test_borrowNative() (gas: 666032)
Logs:
  Bound result 5000000000000000000

[PASS] test_borrowNative_fuzz(uint256) (runs: 5000, μ: 665221, ~: 666038)
[PASS] test_borrowNative_revertsWith_InvalidAmount() (gas: 32287)
[PASS] test_borrowNative_revertsWith_NotNativeWrappedAsset() (gas: 32370)
[PASS] test_borrowNative_revertsWith_SpokeNotRegistered() (gas: 25342)
[PASS] test_constructor() (gas: 1274233)
[PASS] test_constructor_revertsWith_InvalidAddress() (gas: 65710)
[PASS] test_fallback_revertsWith_UnsupportedAction() (gas: 17874)
[PASS] test_multicall_revertsWith_UnsupportedAction() (gas: 11501)
[PASS] test_receive_revertsWith_UnsupportedAction() (gas: 17647)
[PASS] test_repayNative() (gas: 753359)
Logs:
  Bound result 5000000000000000000

[PASS] test_repayNative_excessAmount() (gas: 665347)
[PASS] test_repayNative_fuzz(uint256) (runs: 5000, μ: 748058, ~: 753701)
[PASS] test_repayNative_fuzz_withInterest(uint256,uint256) (runs: 5000, μ: 676146, ~: 671501)
[PASS] test_repayNative_revertsWith_InvalidAmount() (gas: 32601)
[PASS] test_repayNative_revertsWith_NativeAmountMismatch() (gas: 30659)
[PASS] test_repayNative_revertsWith_NotNativeWrappedAsset() (gas: 39407)
[PASS] test_repayNative_revertsWith_SpokeNotRegistered() (gas: 39286)
[PASS] test_supplyAndCollateralNative() (gas: 332046)
Logs:
  Bound result 100000000000000000000

[PASS] test_supplyAndCollateralNative_fuzz(uint256) (runs: 5000, μ: 332330, ~: 332052)
[PASS] test_supplyNative() (gas: 304370)
Logs:
  Bound result 100000000000000000000

[PASS] test_supplyNative_fuzz(uint256) (runs: 5000, μ: 304764, ~: 304486)
[PASS] test_supplyNative_revertsWith_InvalidAmount() (gas: 32588)
[PASS] test_supplyNative_revertsWith_NativeAmountMismatch() (gas: 30413)
[PASS] test_supplyNative_revertsWith_NotNativeWrappedAsset() (gas: 39283)
[PASS] test_supplyNative_revertsWith_SpokeNotRegistered() (gas: 39197)
[PASS] test_withdrawNative() (gas: 330567)
Logs:
  Bound result 100000000000000000000

[PASS] test_withdrawNative_fuzz(uint256) (runs: 5000, μ: 330064, ~: 330639)
[PASS] test_withdrawNative_fuzz_allBalance(uint256) (runs: 5000, μ: 268742, ~: 268547)
[PASS] test_withdrawNative_fuzz_allBalanceWithInterest(uint256,uint256) (runs: 5000, μ: 620364, ~: 620362)
[PASS] test_withdrawNative_revertsWith_InvalidAmount() (gas: 32329)
[PASS] test_withdrawNative_revertsWith_NotNativeWrappedAsset() (gas: 32414)
[PASS] test_withdrawNative_revertsWith_SpokeNotRegistered() (gas: 25408)
Suite result: ok. 33 passed; 0 failed; 0 skipped; finished in 65.53s (65.51s CPU time)

Ran 7 tests for tests/unit/Spoke/Spoke.Repay.EdgeCases.t.sol:SpokeRepayEdgeCaseTest
[PASS] test_fuzz_repay_effect_on_ex_rates(uint256,uint256) (runs: 5000, μ: 695310, ~: 695153)
[PASS] test_repay_less_than_share() (gas: 584163)
[PASS] test_repay_only_base_debt_interest() (gas: 757312)
[PASS] test_repay_only_base_debt_no_premium() (gas: 641179)
[PASS] test_repay_supply_ex_rate_decr() (gas: 1483810)
[PASS] test_repay_supply_ex_rate_decr_skip_time() (gas: 1481138)
[PASS] test_repay_zero_shares_nonzero_premium_debt() (gas: 761319)
Suite result: ok. 7 passed; 0 failed; 0 skipped; finished in 15.40s (15.38s CPU time)

Ran 16 tests for tests/unit/Hub/Hub.Draw.t.sol:HubDrawTest
[PASS] test_draw_DifferentSpokes() (gas: 362336)
[PASS] test_draw_fuzz_IncreasedBorrowRate(uint256,uint256) (runs: 5000, μ: 704773, ~: 704809)
[PASS] test_draw_fuzz_amounts_same_block(uint256,uint256) (runs: 5000, μ: 289006, ~: 288910)
[PASS] test_draw_fuzz_revertsWith_DrawCapExceeded(uint40) (runs: 5000, μ: 81416, ~: 81382)
[PASS] test_draw_fuzz_revertsWith_DrawCapExceeded_due_to_interest(uint40,uint256,uint256) (runs: 5000, μ: 293870, ~: 294131)
[PASS] test_draw_fuzz_revertsWith_InsufficientLiquidity(uint256,uint256) (runs: 5000, μ: 34070, ~: 33863)
[PASS] test_draw_fuzz_revertsWith_InsufficientLiquidity_due_to_draw(uint256) (runs: 5000, μ: 175326, ~: 175045)
[PASS] test_draw_fuzz_revertsWith_InsufficientLiquidity_due_to_remove(uint256) (runs: 5000, μ: 136213, ~: 136016)
[PASS] test_draw_fuzz_revertsWith_InvalidAddress(uint256) (runs: 5000, μ: 15757, ~: 15757)
[PASS] test_draw_revertsWith_DrawCapExceeded_due_to_deficit() (gas: 274491)
[PASS] test_draw_revertsWith_InsufficientLiquidity() (gas: 28097)
[PASS] test_draw_revertsWith_InsufficientLiquidity_due_to_draw() (gas: 171620)
[PASS] test_draw_revertsWith_InsufficientLiquidity_due_to_remove() (gas: 133323)
[PASS] test_draw_revertsWith_InvalidAmount() (gas: 15877)
[PASS] test_draw_revertsWith_SpokeNotActive() (gas: 59712)
[PASS] test_draw_revertsWith_SpokePaused() (gas: 59785)
Suite result: ok. 16 passed; 0 failed; 0 skipped; finished in 24.46s (24.44s CPU time)

Ran 3 tests for tests/unit/NoncesKeyed.t.sol:NoncesKeyedTest
[PASS] test_useCheckedNonce_monotonic(bytes32) (runs: 5000, μ: 13319, ~: 13319)
[PASS] test_useCheckedNonce_revertsWith_InvalidAccountNonce(bytes32) (runs: 5000, μ: 102401, ~: 102401)
[PASS] test_useNonce_monotonic(bytes32) (runs: 5000, μ: 14081, ~: 14081)
Suite result: ok. 3 passed; 0 failed; 0 skipped; finished in 4.32s (4.32s 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, μ: 15344, ~: 15509)
[PASS] test_percentDivUp_le_value(uint256,uint256) (runs: 5000, μ: 15671, ~: 15662)
[PASS] test_percentDiv_fuzz(uint256,uint256) (runs: 5000, μ: 12867, ~: 13012)
[PASS] test_percentMul() (gas: 15116)
[PASS] test_percentMulUp_ge_value(uint256,uint256) (runs: 5000, μ: 15654, ~: 15645)
[PASS] test_percentMulUp_le_value(uint256,uint256) (runs: 5000, μ: 15347, ~: 15512)
[PASS] test_percentMul_fuzz(uint256,uint256) (runs: 5000, μ: 11730, ~: 12247)
Suite result: ok. 10 passed; 0 failed; 0 skipped; finished in 1.52s (1.52s CPU time)

Ran 4 tests for tests/unit/libraries/LiquidationLogic/LiquidationLogic.LiquidateDebt.t.sol:LiquidationLogicLiquidateDebtTest
[PASS] test_liquidateDebt_fuzz(uint256) (runs: 5000, μ: 232952, ~: 232952)
[PASS] test_liquidateDebt_revertsWith_ArithmeticUnderflow() (gas: 97214)
[PASS] test_liquidateDebt_revertsWith_InsufficientAllowance() (gas: 124353)
[PASS] test_liquidateDebt_revertsWith_InsufficientBalance() (gas: 182249)
Suite result: ok. 4 passed; 0 failed; 0 skipped; finished in 94.57s (94.55s CPU time)

Ran 4 tests for tests/unit/libraries/LiquidationLogic/LiquidationLogic.LiquidateUser.t.sol:LiquidationLogicLiquidateUserTest
[PASS] test_liquidateUser() (gas: 368104)
[PASS] test_liquidateUser_revertsWith_InvalidDebtToCover() (gas: 76753)
[PASS] test_liquidateUser_revertsWith_MustNotLeaveDust_Collateral() (gas: 110465)
[PASS] test_liquidateUser_revertsWith_MustNotLeaveDust_Debt() (gas: 119743)
Suite result: ok. 4 passed; 0 failed; 0 skipped; finished in 27.02ms (1.43ms CPU time)

Ran 7 tests for tests/unit/Spoke/Spoke.AccrueInterest.t.sol:SpokeAccrueInterestTest
[PASS] test_accrueInterest_NoActionTaken() (gas: 132063)
[PASS] test_accrueInterest_NoInterest_NoDebt(uint40) (runs: 5000, μ: 638506, ~: 638347)
[PASS] test_accrueInterest_NoInterest_OnlySupply(uint40) (runs: 5000, μ: 252251, ~: 252281)
[PASS] test_accrueInterest_TenPercentRp(uint256,uint40) (runs: 5000, μ: 584318, ~: 584803)
[PASS] test_accrueInterest_fuzz_BorrowAmountAndSkipTime(uint256,uint40) (runs: 5000, μ: 541912, ~: 542197)
[PASS] test_accrueInterest_fuzz_RPBorrowAndSkipTime((uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256),uint40) (runs: 5000, μ: 3862168, ~: 3879702)
[PASS] test_accrueInterest_fuzz_RatesRPBorrowAndSkipTime((uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256),(uint96,uint96,uint96,uint96),uint40) (runs: 5000, μ: 3930999, ~: 3946698)
Suite result: ok. 7 passed; 0 failed; 0 skipped; finished in 198.04s (198.02s CPU time)

Ran 6 tests for tests/unit/Hub/Hub.EliminateDeficit.t.sol:HubEliminateDeficitTest
[PASS] test_eliminateDeficit(uint256) (runs: 5000, μ: 656628, ~: 656628)
[PASS] test_eliminateDeficit_allowSpokePaused() (gas: 429180)
[PASS] test_eliminateDeficit_fuzz_revertsWith_ArithmeticUnderflow_CallerSpokeNoFunds(uint256) (runs: 5000, μ: 343306, ~: 343306)
[PASS] test_eliminateDeficit_fuzz_revertsWith_callerSpokeNotActive(address) (runs: 5000, μ: 28908, ~: 28908)
[PASS] test_eliminateDeficit_revertsWith_InvalidAmount_ZeroAmountNoDeficit() (gas: 20068)
[PASS] test_eliminateDeficit_revertsWith_InvalidAmount_ZeroAmountWithDeficit() (gas: 340316)
Suite result: ok. 6 passed; 0 failed; 0 skipped; finished in 16.90s (16.88s CPU time)

Ran 5 tests for tests/unit/Hub/Hub.MintFeeShares.t.sol:HubMintFeeSharesTest
[PASS] test_mintFeeShares() (gas: 312892)
[PASS] test_mintFeeShares_noFees() (gas: 370166)
[PASS] test_mintFeeShares_noShares() (gas: 301138)
[PASS] test_mintFeeShares_revertsWith_AccessManagedUnauthorized() (gas: 25025)
[PASS] test_mintFeeShares_revertsWith_SpokeNotActive() (gas: 245875)
Suite result: ok. 5 passed; 0 failed; 0 skipped; finished in 23.30ms (4.15ms CPU time)

Ran 8 tests for tests/unit/AccessManagerEnumerable.t.sol:AccessManagerEnumerableTest
[PASS] test_getRoleMembers_fuzz(uint256,uint256) (runs: 5000, μ: 1921298, ~: 1920052)
[PASS] test_getRoleTargetFunctions_fuzz(uint256,uint256) (runs: 5000, μ: 1118550, ~: 1117552)
[PASS] test_grantRole() (gas: 239205)
[PASS] test_grantRole_fuzz(uint64,uint256) (runs: 5000, μ: 856794, ~: 851108)
[PASS] test_revokeRole() (gas: 259646)
[PASS] test_setTargetFunctionRole() (gas: 274815)
[PASS] test_setTargetFunctionRole_skipAddToAdminRole() (gas: 29820)
[PASS] test_setTargetFunctionRole_withReplace() (gas: 336391)
Suite result: ok. 8 passed; 0 failed; 0 skipped; finished in 198.56s (201.44s CPU time)

Ran 12 tests for tests/unit/Spoke/Spoke.SetUserPositionManagerWithSig.t.sol:SpokeSetUserPositionManagerWithSigTest
[PASS] test_DOMAIN_SEPARATOR() (gas: 6014797)
[PASS] test_eip712Domain() (gas: 6020337)
[PASS] test_setUserPositionManagerWithSig() (gas: 295887)
[PASS] test_setUserPositionManagerWithSig_ERC1271() (gas: 326752)
[PASS] test_setUserPositionManagerWithSig_ERC1271_revertsWith_InvalidAccountNonce(bytes32) (runs: 5000, μ: 322090, ~: 322090)
[PASS] test_setUserPositionManagerWithSig_ERC1271_revertsWith_InvalidSignature_dueTo_ExpiredDeadline() (gas: 228741)
[PASS] test_setUserPositionManagerWithSig_ERC1271_revertsWith_InvalidSignature_dueTo_InvalidHash() (gas: 279413)
[PASS] test_setUserPositionManagerWithSig_revertsWith_InvalidAccountNonce(bytes32) (runs: 5000, μ: 285297, ~: 285297)
[PASS] test_setUserPositionManagerWithSig_revertsWith_InvalidSignature_dueTo_ExpiredDeadline() (gas: 30686)
[PASS] test_setUserPositionManagerWithSig_revertsWith_InvalidSignature_dueTo_InvalidSigner() (gas: 31970)
[PASS] test_setUserPositionManager_typeHash() (gas: 4015)
[PASS] test_useNonce_monotonic(bytes32) (runs: 5000, μ: 17972, ~: 17972)
Suite result: ok. 12 passed; 0 failed; 0 skipped; finished in 16.19s (26.88s CPU time)

Ran 5 tests for tests/unit/Spoke/Spoke.SetUsingAsCollateral.t.sol:SpokeConfigTest
[PASS] test_setUsingAsCollateral() (gas: 313686)
[PASS] test_setUsingAsCollateral_collateralStatusUnchanged() (gas: 454124)
[PASS] test_setUsingAsCollateral_revertsWith_ReserveFrozen() (gas: 105264)
[PASS] test_setUsingAsCollateral_revertsWith_ReserveNotListed() (gas: 21986)
[PASS] test_setUsingAsCollateral_revertsWith_ReservePaused() (gas: 64656)
Suite result: ok. 5 passed; 0 failed; 0 skipped; finished in 24.31ms (4.61ms 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, μ: 540238, ~: 540307)
[PASS] test_accrueLiquidityFee_fuzz_maxLiquidityFee_with_premium_multiple_users(uint256,uint256,uint256,uint256,uint256) (runs: 5000, μ: 791581, ~: 791636)
[PASS] test_accrueLiquidityFee_maxLiquidityFee_multi_spoke() (gas: 647619185)
[PASS] test_accrueLiquidityFee_maxLiquidityFee_multi_user() (gas: 260580011)
[PASS] test_accrueLiquidityFee_maxLiquidityFee_with_premium() (gas: 540591)
Logs:
  Bound result 500000000000000000000
  Bound result 5000
  Bound result 34560000
  Bound result 2

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

Ran 11 tests for tests/unit/position-managers/SignatureGateway/SignatureGateway.t.sol:SignatureGatewayTest
[PASS] test_borrowWithSig() (gas: 792728)
[PASS] test_renouncePositionManagerRole() (gas: 26851)
[PASS] test_renouncePositionManagerRole_revertsWith_OnlyOwner() (gas: 18352)
[PASS] test_repayWithSig() (gas: 794049)
[PASS] test_setSelfAsUserPositionManagerWithSig() (gas: 298104)
[PASS] test_setUsingAsCollateralWithSig() (gas: 613309)
[PASS] test_supplyWithSig() (gas: 584522)
[PASS] test_updateUserDynamicConfigWithSig() (gas: 310881)
[PASS] test_updateUserRiskPremiumWithSig() (gas: 880672)
[PASS] test_useNonce_monotonic(bytes32) (runs: 5000, μ: 13899, ~: 13899)
[PASS] test_withdrawWithSig() (gas: 585126)
Suite result: ok. 11 passed; 0 failed; 0 skipped; finished in 218.07s (218.05s CPU time)

Ran 7 tests for tests/unit/Spoke/Spoke.AccrueLiquidityFee.t.sol:SpokeAccrueLiquidityFeeTest
[PASS] test_accrueLiquidityFee() (gas: 880876)
[PASS] test_accrueLiquidityFee_NoActionTaken() (gas: 120065)
[PASS] test_accrueLiquidityFee_NoInterest_OnlySupply(uint40) (runs: 5000, μ: 247276, ~: 247256)
[PASS] test_accrueLiquidityFee_exact() (gas: 887419)
[PASS] test_accrueLiquidityFee_fuzz_BorrowAmountAndSkipTime(uint256,uint40) (runs: 5000, μ: 957848, ~: 980335)
[PASS] test_accrueLiquidityFee_maxLiquidityFee() (gas: 546465)
[PASS] test_accrueLiquidityFee_setUsingAsCollateral() (gas: 900263)
Suite result: ok. 7 passed; 0 failed; 0 skipped; finished in 21.22s (38.87s CPU time)

Ran 14 tests for tests/unit/Spoke/Spoke.Supply.t.sol:SpokeSupplyTest
[PASS] test_fuzz_supply_effect_on_ex_rates(uint256,uint256) (runs: 5000, μ: 706413, ~: 707495)
[PASS] test_supply() (gas: 302919)
[PASS] test_supply_does_not_update_risk_premium() (gas: 1657602)
[PASS] test_supply_fuzz_amounts(uint256) (runs: 5000, μ: 430558, ~: 430231)
[PASS] test_supply_fuzz_index_increase_no_premium(uint256,uint256,uint256,uint256) (runs: 5000, μ: 662744, ~: 663030)
[PASS] test_supply_fuzz_index_increase_with_premium(uint256,uint256,uint256,uint256) (runs: 5000, μ: 759255, ~: 759399)
[PASS] test_supply_fuzz_revertsWith_ERC20InsufficientBalance(uint256) (runs: 5000, μ: 62266, ~: 61986)
[PASS] test_supply_index_increase_no_premium() (gas: 864815)
[PASS] test_supply_index_increase_with_premium() (gas: 923445)
[PASS] test_supply_revertsWith_ERC20InsufficientAllowance() (gas: 39740)
[PASS] test_supply_revertsWith_InvalidSupplyAmount() (gas: 41953)
[PASS] test_supply_revertsWith_ReserveFrozen() (gas: 65102)
[PASS] test_supply_revertsWith_ReserveNotListed() (gas: 22091)
[PASS] test_supply_revertsWith_ReservePaused() (gas: 65022)
Suite result: ok. 14 passed; 0 failed; 0 skipped; finished in 48.58s (89.67s CPU time)

Ran 9 tests for tests/gas/Hub.Operations.gas.t.sol:HubOperations_Gas_Tests
[PASS] test_add() (gas: 273543)
[PASS] test_deficit() (gas: 1181116)
[PASS] test_draw() (gas: 423925)
[PASS] test_mintFeeShares() (gas: 506169)
[PASS] test_payFee_transferShares() (gas: 975173)
[PASS] test_refreshPremium() (gas: 636225)
[PASS] test_remove() (gas: 314977)
[PASS] test_restore() (gas: 891658)
[PASS] test_restore_with_transfer() (gas: 892326)
Suite result: ok. 9 passed; 0 failed; 0 skipped; finished in 40.36ms (7.83ms CPU time)

Ran 8 tests for tests/unit/Spoke/Spoke.Upgradeable.t.sol:SpokeUpgradeableTest
[PASS] test_implementation_constructor_fuzz(uint64) (runs: 5000, μ: 5010667, ~: 5010667)
[PASS] test_proxy_constructor_fuzz(uint64) (runs: 5000, μ: 5653678, ~: 5653672)
[PASS] test_proxy_constructor_fuzz_revertsWith_InvalidInitialization(uint64) (runs: 5000, μ: 10634925, ~: 10634919)
[PASS] test_proxy_constructor_revertsWith_InvalidAddress() (gas: 5066857)
[PASS] test_proxy_constructor_revertsWith_InvalidInitialization_ZeroRevision() (gas: 5067062)
[PASS] test_proxy_reinitialization_fuzz(uint64) (runs: 5000, μ: 11551857, ~: 11551844)
[PASS] test_proxy_reinitialization_revertsWith_CallerNotProxyAdmin() (gas: 10604905)
[PASS] test_proxy_reinitialization_revertsWith_InvalidAddress() (gas: 10606623)
Suite result: ok. 8 passed; 0 failed; 0 skipped; finished in 18.29s (32.14s CPU time)

Ran 6 tests for tests/unit/Spoke/Spoke.UserAccountData.t.sol:SpokeUserAccountDataTest
[PASS] test_userAccountData_scenario1() (gas: 499849)
[PASS] test_userAccountData_scenario2() (gas: 561970)
[PASS] test_userAccountData_scenario3() (gas: 562245)
[PASS] test_userAccountData_scenario4() (gas: 838871)
[PASS] test_userAccountData_scenario5() (gas: 717637)
[PASS] test_userAccountData_scenario6() (gas: 690081)
Suite result: ok. 6 passed; 0 failed; 0 skipped; finished in 25.75ms (4.39ms CPU time)

Ran 6 tests for tests/unit/Hub/Hub.PayFee.t.sol:HubPayFeeTest
[PASS] test_payFee_fuzz(uint256,uint256) (runs: 5000, μ: 707709, ~: 707842)
[PASS] test_payFee_fuzz_with_interest(uint256,uint256,uint256) (runs: 5000, μ: 708167, ~: 708441)
[PASS] test_payFee_revertsWith_InvalidShares() (gas: 20137)
[PASS] test_payFee_revertsWith_SpokeNotActive() (gas: 59678)
[PASS] test_payFee_revertsWith_underflow_added_shares_exceeded() (gas: 138907)
[PASS] test_payFee_revertsWith_underflow_added_shares_exceeded_with_interest() (gas: 652789)
Suite result: ok. 6 passed; 0 failed; 0 skipped; finished in 25.50s (25.48s CPU time)

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

[PASS] test_reclaim_fullAmount() (gas: 661472)
[PASS] test_reclaim_fuzz(uint256,uint256,uint256) (runs: 5000, μ: 682527, ~: 681689)
[PASS] test_reclaim_multipleSweepsAndReclaims() (gas: 789768)
[PASS] test_reclaim_revertsWith_AssetNotListed() (gas: 12439)
[PASS] test_reclaim_revertsWith_InvalidAmount_zero() (gas: 93115)
[PASS] test_reclaim_revertsWith_OnlyReinvestmentController(address) (runs: 5000, μ: 93980, ~: 93980)
[PASS] test_reclaim_revertsWith_OnlyReinvestmentController_init() (gas: 40003)
[PASS] test_reclaim_revertsWith_underflow_exceedsSwept() (gas: 98578)
[PASS] test_reclaim_revertsWith_underflow_exceedsSwept_afterSweep() (gas: 461593)
Suite result: ok. 10 passed; 0 failed; 0 skipped; finished in 15.12s (15.10s CPU time)

Ran 12 tests for tests/unit/Hub/Hub.RefreshPremium.t.sol:HubRefreshPremiumTest
[PASS] test_refreshPremium_emitsEvent() (gas: 259376)
[PASS] test_refreshPremium_fuzz_positiveDeltas(uint256,int256,int256) (runs: 5000, μ: 467690, ~: 472069)
[PASS] test_refreshPremium_fuzz_withAccrual(uint256,uint256,uint256,uint256) (runs: 5000, μ: 535420, ~: 542271)
[PASS] test_refreshPremium_maxRiskPremiumThreshold() (gas: 896046)
[PASS] test_refreshPremium_negativeDeltas(uint256) (runs: 5000, μ: 461077, ~: 461095)
[PASS] test_refreshPremium_negativeDeltas_withAccrual(uint256) (runs: 5000, μ: 533767, ~: 533995)
[PASS] test_refreshPremium_pausedSpokesAllowed() (gas: 120453)
[PASS] test_refreshPremium_revertsWith_InvalidPremiumChange_NonZeroRestoredPremiumRay() (gas: 856323)
[PASS] test_refreshPremium_revertsWith_InvalidPremiumChange_RiskPremiumThresholdExceeded_DecreasingPremium() (gas: 874204)
[PASS] test_refreshPremium_revertsWith_SpokeNotActive() (gas: 57758)
[PASS] test_refreshPremium_riskPremiumThreshold() (gas: 921454)
[PASS] test_refreshPremium_spokePremiumUpdateIsContained() (gas: 710313)
Suite result: ok. 12 passed; 0 failed; 0 skipped; finished in 22.47s (22.45s CPU time)

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

[PASS] test_remove_all_with_interest() (gas: 377919)
[PASS] test_remove_fuzz(uint256,uint256) (runs: 5000, μ: 209216, ~: 209034)
[PASS] test_remove_fuzz_all_liquidity_with_interest(uint256,uint256) (runs: 5000, μ: 429852, ~: 430159)
[PASS] test_remove_fuzz_multi_spoke(uint256,uint256) (runs: 5000, μ: 293877, ~: 294021)
[PASS] test_remove_fuzz_multi_spoke_with_interest(uint256,uint256,uint256,uint256) (runs: 5000, μ: 433366, ~: 433926)
[PASS] test_remove_revertsWith_InsufficientLiquidity() (gas: 160467)
[PASS] test_remove_revertsWith_InsufficientLiquidity_exceeding_added_amount() (gas: 148158)
[PASS] test_remove_revertsWith_InsufficientLiquidity_zero_added() (gas: 20745)
[PASS] test_remove_revertsWith_InvalidAddress() (gas: 15718)
[PASS] test_remove_revertsWith_InvalidAmount() (gas: 17819)
[PASS] test_remove_revertsWith_SpokeNotActive() (gas: 59802)
[PASS] test_remove_revertsWith_SpokePaused() (gas: 59908)
[PASS] test_remove_revertsWith_underflow_exceeding_added_amount() (gas: 188116)
[PASS] test_remove_revertsWtih_underflow_one_extra_wei() (gas: 372890)
Suite result: ok. 15 passed; 0 failed; 0 skipped; finished in 32.23s (32.21s CPU time)

Ran 6 tests for tests/unit/Hub/Hub.ReportDeficit.t.sol:HubReportDeficitTest
[PASS] test_reportDeficit_fuzz_revertsWith_SurplusDrawnDeficitReported(uint256) (runs: 5000, μ: 221510, ~: 221238)
[PASS] test_reportDeficit_fuzz_revertsWith_SurplusPremiumRayDeficitReported(uint256) (runs: 5000, μ: 223204, ~: 222932)
[PASS] test_reportDeficit_fuzz_with_premium(uint256,uint256,uint256,uint256) (runs: 5000, μ: 676436, ~: 677378)
[PASS] test_reportDeficit_revertsWith_InvalidAmount() (gas: 24282)
[PASS] test_reportDeficit_revertsWith_SpokeNotActive(address) (runs: 5000, μ: 32428, ~: 32428)
[PASS] test_reportDeficit_with_premium() (gas: 675953)
Logs:
  Bound result 10000000000
  Bound result 31536000
  Bound result 5000000000
  Bound result 0

Suite result: ok. 6 passed; 0 failed; 0 skipped; finished in 18.26s (18.24s CPU time)

Ran 3 tests for tests/unit/Hub/Hub.Rescue.t.sol:HubRescueTest
[PASS] test_cannot_rescue_liquidity_fee_reverts_with_InsufficientTransferred() (gas: 279900)
[PASS] test_rescue_fuzz_with_interest(uint256,uint256) (runs: 5000, μ: 526153, ~: 526142)
[PASS] test_rescue_scenario_fuzz(uint256) (runs: 5000, μ: 462921, ~: 462720)
Suite result: ok. 3 passed; 0 failed; 0 skipped; finished in 19.46s (19.44s CPU time)

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

[PASS] test_restore_full_amount_with_interest_and_premium() (gas: 677110)
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, μ: 368058, ~: 368161)
[PASS] test_restore_fuzz_full_amount_with_interest_and_premium(uint256,uint256,uint256,uint256) (runs: 5000, μ: 667026, ~: 679061)
[PASS] test_restore_fuzz_revertsWith_SurplusDrawnRestored_with_interest(uint256,uint256,uint256) (runs: 5000, μ: 247886, ~: 249163)
[PASS] test_restore_fuzz_revertsWith_SurplusDrawnRestored_with_interest_and_premium(uint256,uint256,uint256,uint256) (runs: 5000, μ: 639384, ~: 639598)
[PASS] test_restore_one_share_delta_increase_revertsWith_InvalidPremiumChange() (gas: 214389)
[PASS] test_restore...*[Comment body truncated]*

@github-actions
Copy link

github-actions bot commented Dec 8, 2025

Forge Build Sizes

🔕 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
AccessManagerEnumerable 12,137 13,534 12,439 35,618
Address 44 94 24,532 49,058
AllowancePositionManager 8,391 8,915 16,185 40,237
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
ConfigPermissionsMap 44 94 24,532 49,058
ConfigPermissionsWrapper 723 751 23,853 48,401
Constants 447 499 24,129 48,653
ECDSA 44 94 24,532 49,058
EIP712Hash 541 593 24,035 48,559
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 21,598 21,832 2,978 27,320
HubConfigurator 9,981 10,254 14,595 38,898
JsonBindings 11,158 11,210 13,418 37,942
KeyValueList 44 94 24,532 49,058
KeyValueListWrapper 802 830 23,774 48,322
LibBit 44 94 24,532 49,058
LiquidationLogic 6,542 6,594 18,034 42,558
LiquidationLogicWrapper 10,943 11,117 13,633 38,035
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
MockNoncesKeyed 601 629 23,975 48,523
MockPriceFeed 642 1,300 23,934 47,852
MockSkimSpoke 923 1,082 23,653 48,070
NativeTokenGateway 6,002 6,419 18,574 42,733
NoncesKeyed 425 453 24,151 48,699
Panic 44 94 24,532 49,058
PercentageMath 44 94 24,532 49,058
PercentageMathWrapper 592 620 23,984 48,532
PositionConfigPositionManager 6,026 6,301 18,550 42,851
PositionManagerBaseWrapper 3,754 4,029 20,822 45,123
PositionStatusMap 44 94 24,532 49,058
PositionStatusMapWrapper 2,389 2,417 22,187 46,735
Premium 44 94 24,532 49,058
ProxyAdmin 977 1,213 23,599 47,939
RescuableWrapper 770 904 23,806 48,248
ReserveFlagsMap 44 94 24,532 49,058
ReserveFlagsMapWrapper 1,075 1,103 23,501 48,049
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
SignatureGateway 9,892 10,403 14,684 38,749
SlotDerivation 44 94 24,532 49,058
SpokeConfigurator 8,659 8,932 15,917 40,220
SpokeInstance 24,523 25,266 53 23,886
StorageSlot 44 94 24,532 49,058
SupplyRepayPositionManager 4,742 5,017 19,834 44,135
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
TreasurySpoke 2,764 3,179 21,812 45,973
UnitPriceFeed 700 1,635 23,876 47,517
UserPositionDebt 44 94 24,532 49,058
UserPositionDebtWrapper 2,677 2,705 21,899 46,447
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,371 1,399 23,205 47,753

@github-actions
Copy link

github-actions bot commented Dec 8, 2025

♻️ Forge Gas Snapshots

Path Value
snapshots/AllowancePositionManager.Operations.json
approveWithdraw 49895
approveWithdrawWithSig 66560
borrowOnBehalfOf 309435
delegateCredit 49864
delegateCreditWithSig 66505
renounceCreditDelegation 28020
renounceWithdrawAllowance 28007
withdrawOnBehalfOf: full 121329
withdrawOnBehalfOf: partial 131461
snapshots/NativeTokenGateway.Operations.json
borrowNative ↑0% (+80) 229,396
repayNative ↑0% (+58) 168,082
supplyAsCollateralNative ↑0% (+80) 160,453
supplyNative ↑0% (+47) 136,523
withdrawNative: full ↑0% (+47) 125,667
withdrawNative: partial ↑0% (+58) 136,883
snapshots/PositionConfigPositionManager.Operations.json
renounceGlobalPermission 27699
renounceUserDynamicConfigPermission 27763
renounceUserRiskPremiumPermission 27720
renounceUsingAsCollateralPermission 27698
setGlobalPermission 49868
setUserDynamicConfigPermission 49845
setUserRiskPremiumPermission 49891
setUsingAsCollateralOnBehalfOf 71916
setUsingAsCollateralPermission 49847
updateUserDynamicConfigOnBehalfOf 49577
updateUserRiskPremiumOnBehalfOf 130652
snapshots/PositionManagerBase.Operations.json
setSelfAsUserPositionManagerWithSig 74809
snapshots/SignatureGateway.Operations.json
setSelfAsUserPositionManagerWithSig ↓1% (-522) 74,880
setUsingAsCollateralWithSig ↑0% (+22) 85,075
supplyWithSig ↑0% (+18) 153,223
updateUserDynamicConfigWithSig ↑0% (+22) 62,791
updateUserRiskPremiumWithSig ↓0% (-66) 61,513
withdrawWithSig ↑0% (+35) 131,731
snapshots/SupplyRepayPositionManager.Operations.json
repayOnBehalfOf 169863
supplyOnBehalfOf 138004
🔕 Unchanged
Path Value
snapshots/Hub.Operations.json
add 88,006
add: with transfer 109,613
draw 105,931
eliminateDeficit: full 59,781
eliminateDeficit: partial 69,429
mintFeeShares 84,007
payFee 72,302
refreshPremium 71,999
remove: full 76,993
remove: partial 81,640
reportDeficit 115,225
restore: full 80,471
restore: full - with transfer 173,377
restore: partial 89,137
restore: partial - with transfer 147,400
transferShares 71,192
snapshots/SignatureGateway.Operations.json
borrowWithSig 215,605
repayWithSig 188,872
snapshots/Spoke.Getters.json
getUserAccountData: supplies: 0, borrows: 0 11,937
getUserAccountData: supplies: 1, borrows: 0 48,600
getUserAccountData: supplies: 2, borrows: 0 80,378
getUserAccountData: supplies: 2, borrows: 1 100,166
getUserAccountData: supplies: 2, borrows: 2 118,596
snapshots/Spoke.Operations.ZeroRiskPremium.json
borrow: first 191,325
borrow: second action, same reserve 171,297
liquidationCall (receiveShares): full 300,103
liquidationCall (receiveShares): partial 299,821
liquidationCall: full 310,468
liquidationCall: partial 310,186
permitReserve + repay (multicall) 166,029
permitReserve + supply (multicall) 146,862
permitReserve + supply + enable collateral (multicall) 160,573
repay: full 126,094
repay: partial 130,983
setUserPositionManagerWithSig: disable 44,846
setUserPositionManagerWithSig: enable 68,875
supply + enable collateral (multicall) 140,624
supply: 0 borrows, collateral disabled 123,679
supply: 0 borrows, collateral enabled 106,601
supply: second action, same reserve 106,579
updateUserDynamicConfig: 1 collateral 73,694
updateUserDynamicConfig: 2 collaterals 88,551
updateUserRiskPremium: 1 borrow 94,804
updateUserRiskPremium: 2 borrows 104,619
usingAsCollateral: 0 borrows, enable 58,915
usingAsCollateral: 1 borrow, disable 105,072
usingAsCollateral: 1 borrow, enable 41,803
usingAsCollateral: 2 borrows, disable 126,055
usingAsCollateral: 2 borrows, enable 41,815
withdraw: 0 borrows, full 128,910
withdraw: 0 borrows, partial 133,473
withdraw: 1 borrow, partial 161,036
withdraw: 2 borrows, partial 174,214
withdraw: non collateral 106,544
snapshots/Spoke.Operations.json
borrow: first 261,721
borrow: second action, same reserve 204,693
liquidationCall (receiveShares): full 333,666
liquidationCall (receiveShares): partial 333,384
liquidationCall: full 344,031
liquidationCall: partial 343,749
permitReserve + repay (multicall) 163,273
permitReserve + supply (multicall) 146,862
permitReserve + supply + enable collateral (multicall) 160,573
repay: full 120,256
repay: partial 139,545
setUserPositionManagerWithSig: disable 44,846
setUserPositionManagerWithSig: enable 68,875
supply + enable collateral (multicall) 140,624
supply: 0 borrows, collateral disabled 123,679
supply: 0 borrows, collateral enabled 106,601
supply: second action, same reserve 106,579
updateUserDynamicConfig: 1 collateral 73,694
updateUserDynamicConfig: 2 collaterals 88,551
updateUserRiskPremium: 1 borrow 151,080
updateUserRiskPremium: 2 borrows 204,276
usingAsCollateral: 0 borrows, enable 58,915
usingAsCollateral: 1 borrow, disable 161,348
usingAsCollateral: 1 borrow, enable 41,803
usingAsCollateral: 2 borrows, disable 233,712
usingAsCollateral: 2 borrows, enable 41,815
withdraw: 0 borrows, full 128,910
withdraw: 0 borrows, partial 133,473
withdraw: 1 borrow, partial 214,810
withdraw: 2 borrows, partial 259,272
withdraw: non collateral 106,544

IERC20 asset = _getReserveUnderlying(reserveId);

uint256 userTotalDebt = SPOKE.getUserTotalDebt(reserveId, onBehalfOf);
uint256 repayAmount = amount > userTotalDebt ? userTotalDebt : amount;
Copy link
Member

Choose a reason for hiding this comment

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

do we care about the attack vector of borrowing more before they max repay kicks in? We d need to disallow max repay here.

Copy link
Contributor

@avniculae avniculae Dec 9, 2025

Choose a reason for hiding this comment

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

or check amount is not more than x% more than userTotalDebt? would it be an overkill?

or maybe take the following inputs (reserveId, amount, maxShares, onBehalfOf). we then revert if shares returned by spoke.repay are > maxShares. would this add too much friction?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think it brings a lot of complexity or would block some users behaviors rather than solving the potential issue.
Imo it's up to user decision to approve+pass a large/larger than needed repayAmount, which would signify they are ready to repay up to that inputed amount.
In here, it's not like we simply override the amount to repay all debt if the inputed amount is higher than the debt of onBehalfOf, so we already have the parameter limiting how much the user is ready to repay at maximum.

Copy link
Member

Choose a reason for hiding this comment

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

I think blocking max_uint is a way to block unintentional max repayments, so using a fixed amount means user knows what is doing, while using max_uint is naive call by a noob user thus it's blocked to protect them

Copy link
Contributor Author

Choose a reason for hiding this comment

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

But then just passing max_uint - 1 would serve the same usecase and skip the blocker, noob user might see it as "inputed the wrong value" and execute the same exact mistake with just - 1.

IERC20 asset = _getReserveUnderlying(reserveId);
asset.safeTransferFrom(msg.sender, address(this), amount);
asset.forceApprove(SPOKE, amount);
return ISpoke(SPOKE).supply(reserveId, amount, onBehalfOf);
Copy link
Contributor

Choose a reason for hiding this comment

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

given that the spoke returns both shares and amounts, I'm wondering whether we should assert (with a require) that amount returned is equal to amount. wdyt?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This function is just an extension of the Spoke method, so I think returning the amount & shares here should be sufficient so integrators can then verify the returned values.

}

/// @inheritdoc ICreditDelegationPositionManager
function approveCreditDelegationWithSig(
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 have something like PositionManagerWithAllowanceBase.sol, which implements the map and the 2 functions for approvals (with and without sig)? (to avoid duplication)

wdyt?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

For the signature part, I'd rather keep each unique typehash & type, rather than a common one used for both. As for the mapping, no real opinion there, the current duplication does not bother me.

Copy link
Contributor

Choose a reason for hiding this comment

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

ofc, still unique typehash, but we can pass typehash to the base

/// @inheritdoc ISignatureGateway
function setSelfAsUserPositionManagerWithSig(
address spoke,
EIP712Types.SetUserPositionManager calldata params,
Copy link
Member

Choose a reason for hiding this comment

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

rm this struct from EIP712Types

Copy link
Contributor Author

Choose a reason for hiding this comment

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

this is still currently used in tests, should we directly remove and change all tests or just move that struct + helper to the test files ?
See other discussion : #1054 (comment)

Copy link
Member

@DhairyaSethi DhairyaSethi Dec 19, 2025

Choose a reason for hiding this comment

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

i think it's fine to keep the struct in src

/// @title SupplyRepayPositionManager
/// @author Aave Labs
/// @notice Position manager to handle supply and repay actions on behalf of users.
contract SupplyRepayPositionManager is ISupplyRepayPositionManager, PositionManagerBase {
Copy link
Member

Choose a reason for hiding this comment

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

wondering if we should find another name for this

Copy link
Contributor Author

Choose a reason for hiding this comment

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

DonationPositionManager ?

constructor(address spoke_) PositionManagerBase(spoke_) {}

/// @inheritdoc ISupplyRepayPositionManager
function supplyOnBehalfOf(
Copy link
Member

Choose a reason for hiding this comment

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

don't we want to have the intents-based version of these actions?


/// @notice Mapping of credit delegations.
mapping(address owner => mapping(address spender => mapping(uint256 reserveId => uint256 amount)))
private _creditDelegations;
Copy link
Member

@miguelmtzinf miguelmtzinf Dec 18, 2025

Choose a reason for hiding this comment

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

i dn't be opposed to use similar terms (e.g. _borrowAllowances) for credit delegation in general... But fine to keep it as it is if "giving borrow allowance" sounds "weird" and industry is used to "delegating credit"

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, kept creditDelegation to reduce the misunderstandings, as it was already accepted by users with v3.

owner: onBehalfOf,
spender: msg.sender,
reserveId: reserveId,
amount: amount
Copy link
Member

Choose a reason for hiding this comment

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

Thinking about max withdraw, which could be a bit confusing / hard to achieve...
It's only possible if the max_uint allowance is given, and will be consume in one go....

Copy link
Contributor Author

Choose a reason for hiding this comment

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

max withdraw can be executed by passing an absurdly high amount, that is not uint256_max, in which case the full allowance wouldn't be fully consumed (since Spoke only checks the passed against max withdrawable, uint256_max is not used as the forced value to make a max withdraw).
And in the case the owner gives uint256_max allowance and the spender also inputs uint256_max, then we both clear the position balance + the given allowance, which makes sense for me there.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

21bce1d for non-decreasing infinite allowance.

Comment on lines 215 to 217
uint256 currentAllowance = _withdrawAllowances[owner][spender][reserveId];
require(currentAllowance >= amount, InsufficientWithdrawAllowance(currentAllowance, amount));
_withdrawAllowances[owner][spender][reserveId] = currentAllowance.uncheckedSub(amount);
Copy link
Member

Choose a reason for hiding this comment

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

should we sentinel values here?
uint.max == infinite allowance, never decreased, like erc20 implementations
uint.max - 1 == one time infinite allowance

Copy link
Contributor Author

Choose a reason for hiding this comment

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

constructor(address spoke_) PositionManagerBase(spoke_) {}

/// @inheritdoc IPositionConfigPositionManager
function setGlobalPermission(address caller, bool permission) external {
Copy link
Member

Choose a reason for hiding this comment

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

idk if I like the "global" term, as it could sound like it's for the entire protocol. Re caller, wondering if clear or better to use smt like delegatee

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm okay with delegatee & delegator terms instead of owner & caller

Copy link
Contributor Author

Choose a reason for hiding this comment

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

should we go with delegator & delegatee then @miguelmtzinf ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants