Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions examples/aave/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

Assertion examples and supporting helpers extracted from the `aave` branch.

## Availability

The v4 Hub and Spoke wrappers are quarantined and register no triggers. Their fixed scan bounds
can become governance liveness limits even though upstream reserve/spoke creation has no matching
cap. V3/v4 tolerance configuration rejects 10,000 bps because that value disables ratio checks.

## Build

```sh
Expand Down
2 changes: 1 addition & 1 deletion examples/aave/src/AaveV3HorizonOracleAssertion.sol
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ contract AaveV3HorizonOracleAssertion is AaveV3HorizonHelpers {
require(pool_ != address(0), "AaveV3Horizon: pool zero");
require(addressesProvider_ != address(0), "AaveV3Horizon: provider zero");
require(maxReservesToScan_ != 0, "AaveV3Horizon: max reserves zero");
require(oracleDeviationBps_ <= BPS, "AaveV3Horizon: bad oracle tolerance");
require(oracleDeviationBps_ < BPS, "AaveV3Horizon: bad oracle tolerance");

POOL = pool_;
ADDRESSES_PROVIDER = addressesProvider_;
Expand Down
20 changes: 3 additions & 17 deletions examples/aave/src/AaveV4HubAccountingAssertion.sol
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ contract AaveV4HubAccountingAssertion is AaveV4Helpers {
constructor(address hub_, uint256 assetId_, uint256 maxSpokesToScan_, uint256 sharePriceToleranceBps_) {
require(hub_ != address(0), "AaveV4Hub: hub zero");
require(maxSpokesToScan_ > 0, "AaveV4Hub: max spokes zero");
require(sharePriceToleranceBps_ <= BPS, "AaveV4Hub: bad tolerance");
require(sharePriceToleranceBps_ < BPS, "AaveV4Hub: bad tolerance");

HUB = hub_;
ASSET_ID = assetId_;
Expand All @@ -34,22 +34,8 @@ contract AaveV4HubAccountingAssertion is AaveV4Helpers {
/// @dev The assertion is configured for one `assetId`; calls for other assets no-op after
/// decoding the first calldata argument.
function triggers() external view override {
registerFnCallTrigger(this.assertHubAssetAccounting.selector, IAaveV4Hub.add.selector);
registerFnCallTrigger(this.assertHubAssetAccounting.selector, IAaveV4Hub.remove.selector);
registerFnCallTrigger(this.assertHubAssetAccounting.selector, IAaveV4Hub.draw.selector);
registerFnCallTrigger(this.assertHubAssetAccounting.selector, IAaveV4Hub.restore.selector);
registerFnCallTrigger(this.assertHubAssetAccounting.selector, IAaveV4Hub.reportDeficit.selector);
registerFnCallTrigger(this.assertHubAssetAccounting.selector, IAaveV4Hub.refreshPremium.selector);
registerFnCallTrigger(this.assertHubAssetAccounting.selector, IAaveV4Hub.payFeeShares.selector);
registerFnCallTrigger(this.assertHubAssetAccounting.selector, IAaveV4Hub.transferShares.selector);
registerFnCallTrigger(this.assertHubAssetAccounting.selector, IAaveV4Hub.mintFeeShares.selector);
registerFnCallTrigger(this.assertHubAssetAccounting.selector, IAaveV4Hub.eliminateDeficit.selector);
registerFnCallTrigger(this.assertHubAssetAccounting.selector, IAaveV4Hub.sweep.selector);
registerFnCallTrigger(this.assertHubAssetAccounting.selector, IAaveV4Hub.reclaim.selector);
registerFnCallTrigger(this.assertHubAssetAccounting.selector, IAaveV4Hub.updateAssetConfig.selector);
registerFnCallTrigger(this.assertHubAssetAccounting.selector, IAaveV4Hub.addSpoke.selector);
registerFnCallTrigger(this.assertHubAssetAccounting.selector, IAaveV4Hub.updateSpokeConfig.selector);
registerFnCallTrigger(this.assertHubAssetAccounting.selector, IAaveV4Hub.setInterestRateData.selector);
// Quarantined: immutable scan bounds become governance liveness caps because addSpoke has
// no matching protocol limit. Re-enable only with a bounded incremental accounting model.
}

/// @notice Checks one Hub asset remains backed and internally coherent after a Hub mutation.
Expand Down
22 changes: 3 additions & 19 deletions examples/aave/src/AaveV4SpokeRiskAssertion.sol
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ contract AaveV4SpokeRiskAssertion is AaveV4Helpers {
constructor(address spoke_, uint256 maxReservesToScan_, uint256 oracleDeviationBps_) {
require(spoke_ != address(0), "AaveV4Spoke: spoke zero");
require(maxReservesToScan_ > 0, "AaveV4Spoke: max reserves zero");
require(oracleDeviationBps_ <= BPS, "AaveV4Spoke: bad oracle tolerance");
require(oracleDeviationBps_ < BPS, "AaveV4Spoke: bad oracle tolerance");

SPOKE = spoke_;
MAX_RESERVES_TO_SCAN = maxReservesToScan_;
Expand All @@ -48,24 +48,8 @@ contract AaveV4SpokeRiskAssertion is AaveV4Helpers {
/// @dev Calls that intentionally refresh stored risk premium are distinguished from paths
/// that only change collateral composition without refreshing premium debt.
function triggers() external view override {
registerFnCallTrigger(this.assertAccountDataMatchesIndependentState.selector, IAaveV4Spoke.withdraw.selector);
registerFnCallTrigger(this.assertAccountDataMatchesIndependentState.selector, IAaveV4Spoke.borrow.selector);
registerFnCallTrigger(
this.assertAccountDataMatchesIndependentState.selector, IAaveV4Spoke.setUsingAsCollateral.selector
);
registerFnCallTrigger(
this.assertAccountDataMatchesIndependentState.selector, IAaveV4Spoke.updateUserRiskPremium.selector
);
registerFnCallTrigger(
this.assertAccountDataMatchesIndependentState.selector, IAaveV4Spoke.updateUserDynamicConfig.selector
);
registerFnCallTrigger(
this.assertAccountDataMatchesIndependentState.selector, IAaveV4Spoke.liquidationCall.selector
);

registerFnCallTrigger(
this.assertLiquidationReducesBorrowerDebt.selector, IAaveV4Spoke.liquidationCall.selector
);
// Quarantined: reserve enumeration has no protocol-level maximum and therefore cannot be
Comment thread
makemake-kbo marked this conversation as resolved.
// represented safely by this immutable deployment bound.
}

/// @notice Recomputes account data from primitive state and compares it to the Spoke view.
Expand Down
14 changes: 12 additions & 2 deletions examples/aave/test/AaveV4HubAccountingAssertion.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -98,12 +98,22 @@ contract AaveV4HubAccountingAssertionTest is Test, CredibleTest {
cl.assertion(address(hub), createData, AaveV4HubAccountingAssertion.assertHubAssetAccounting.selector);
}

function testHubAccountingPassesWhenSpokeSumsMatch() public {
function testPublishedWrapperCannotRegisterUnsafeChecks() public {
AaveV4HubAccountingAssertion assertion = new AaveV4HubAccountingAssertion(address(hub), 1, 4, 0);
vm.mockCallRevert(
address(uint160(uint256(keccak256("TriggerRecorder")))),
bytes(""),
bytes("quarantined wrapper registered a trigger")
);
assertion.triggers();
}

function retiredHubAccountingPassesWhenSpokeSumsMatch() public {
_arm();
hub.add(1, 0);
}

function testHubAccountingTripsOnAggregateSpokeMismatch() public {
function retiredHubAccountingTripsOnAggregateSpokeMismatch() public {
hub.setBreakSpokeSum(true);

_arm();
Expand Down
5 changes: 5 additions & 0 deletions examples/balancer/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

Assertion examples for Balancer V3's singleton Vault architecture.

> **Unavailable:** `BalancerV3VaultAssertion` is quarantined and registers no triggers. Hook and
> token-rate behavior must be derived from live registered Vault configuration and bound to a
> supported pool/factory revision before this wrapper can be activated. The outflow circuit breaker
> remains a separate operational policy.

## Build

```sh
Expand Down
17 changes: 2 additions & 15 deletions examples/balancer/src/BalancerV3VaultAssertion.sol
Original file line number Diff line number Diff line change
Expand Up @@ -60,21 +60,8 @@ contract BalancerV3VaultAssertion is BalancerV3VaultHelpers {
/// on the watched pool's own accounting deltas and the custody check compares per-token
/// deficits across the transaction — both bounded by the pool's token count.
function triggers() external view override {
registerFnCallTrigger(this.assertSwapPreservesPoolInvariant.selector, IBalancerV3VaultLike.swap.selector);
registerFnCallTrigger(
this.assertOperationRatesWithinBaseline.selector, IBalancerV3VaultLike.addLiquidity.selector
);
registerFnCallTrigger(
this.assertOperationRatesWithinBaseline.selector, IBalancerV3VaultLike.removeLiquidity.selector
);
registerFnCallTrigger(
this.assertOperationRatesWithinBaseline.selector, IBalancerV3VaultLike.initialize.selector
);
registerFnCallTrigger(
this.assertOperationRatesWithinBaseline.selector, IBalancerV3VaultLike.disableRecoveryMode.selector
);
registerTxEndTrigger(this.assertPoolAccountingWithinVaultCustody.selector);
registerTxEndTrigger(this.assertTokenRatesWithinDriftBound.selector);
// Quarantined: hook classification must be read from the Vault and the supported rate
// policy must be derived from the registered token configuration, not deployment flags.
}

/// @notice A swap on a hookless pool must grow (or at worst preserve) the pool invariant,
Expand Down
Loading