Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

credible-std

Standard library for implementing assertions in the Phylax Credible Layer (PCL). Provides the core contracts and interfaces needed to create, test, and validate assertions for smart contract security monitoring.

Documentation

Full API documentation is available at: https://phylaxsystems.github.io/credible-std

Examples

The Assertions Book examples live in examples/assertions-book. This directory is the canonical source for the code snippets imported by phylaxsystems/phylax-docs.

DirectoryPurpose
examples/assertions-book/assertions/srcAssertion contracts used by the Assertions Book
examples/assertions-book/srcMock protocols and helper contracts imported by assertion examples

Compile the Assertions Book example sources with:

FOUNDRY_PROFILE=assertions-book forge build

Docs automation imports snippets from examples/assertions-book/assertions/src; update examples here before updating the docs pages that reference them.

After example changes merge, run the Import Credible Std Assertion Examples workflow in phylaxsystems/phylax-docs to refresh the rendered snippets.

Installation

Install the latest stable release:

forge install phylaxsystems/credible-std@0.4.0

Or install from master (latest development version):

forge install phylaxsystems/credible-std

Add the remapping to your remappings.txt:

credible-std/=lib/credible-std/src/

Overview

The Phylax Credible Layer (PCL) is a security framework that enables real-time monitoring and validation of smart contract behavior through assertions. credible-std provides the foundational contracts and utilities needed to implement these assertions.

Key Components

ContractDescription
Assertion.solBase contract for creating assertions with trigger registration
Credible.solProvides access to the PhEvm precompile for transaction state inspection
PhEvm.solInterface for the PhEvm precompile (state forking, logs, call inputs)
StateChanges.solType-safe utilities for tracking contract state changes
TriggerRecorder.solInterface for registering assertion triggers
CredibleTest.solBase contract for testing assertions with Forge
CredibleTestWithBacktesting.solExtended test contract with historical transaction backtesting

Features

  • Trigger System: Register triggers for function calls, storage changes, and balance changes
  • State Inspection: Fork to pre/post transaction state, inspect logs, call inputs, and storage
  • Type-Safe State Changes: Built-in converters for uint256, address, bool, and bytes32 state changes
  • Testing Framework: Test assertions locally with Forge before deployment
  • Backtesting: Validate assertions against historical blockchain transactions
  • Internal Call Detection: Automatically detect transactions that call your contract internally (not just direct calls)

Quick Start

1. Create an Assertion

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

import {Assertion} from "credible-std/Assertion.sol";

contract MyAssertion is Assertion {
    // Register when this assertion should run
    function triggers() external view override {
        // Run on any call to the adopter contract
        registerCallTrigger(this.checkInvariant.selector);

        // Or run only on specific function calls
        // registerCallTrigger(this.checkInvariant.selector, ITarget.deposit.selector);
    }

    // Implement your invariant check
    function checkInvariant() external {
        address target = ph.getAssertionAdopter();

        ph.forkPreTx();
        uint256 balanceBefore = target.balance;

        ph.forkPostTx();
        uint256 balanceAfter = target.balance;

        require(balanceAfter >= balanceBefore, "Balance decreased unexpectedly");
    }
}

2. Test Your Assertion

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

import {CredibleTest} from "credible-std/CredibleTest.sol";
import {Test} from "forge-std/Test.sol";
import {MyAssertion} from "./MyAssertion.sol";
import {MyContract} from "./MyContract.sol";

contract TestMyAssertion is CredibleTest, Test {
    MyContract target;

    function setUp() public {
        target = new MyContract();
    }

    function test_assertionPasses() public {
        // Register the assertion
        cl.assertion({
            adopter: address(target),
            createData: type(MyAssertion).creationCode,
            fnSelector: MyAssertion.checkInvariant.selector
        });

        // Execute a transaction - assertion runs automatically
        target.deposit{value: 1 ether}();
    }

    function test_assertionFails() public {
        cl.assertion({
            adopter: address(target),
            createData: type(MyAssertion).creationCode,
            fnSelector: MyAssertion.checkInvariant.selector
        });

        // This should revert because the assertion fails
        vm.expectRevert("Balance decreased unexpectedly");
        target.withdraw(1 ether);
    }
}

Run tests with:

pcl test

PhEvm Cheatcodes

Access these via the ph instance inherited from Credible:

FunctionDescription
forkPreTx()Fork to state before the transaction
forkPostTx()Fork to state after the transaction
forkPreCall(uint256 id)Fork to state before a specific call
forkPostCall(uint256 id)Fork to state after a specific call
load(address, bytes32)Load a storage slot value
getLogs()Get all logs emitted in the transaction
getCallInputs(address, bytes4)Get CALL inputs for target/selector
getStaticCallInputs(address, bytes4)Get STATICCALL inputs
getDelegateCallInputs(address, bytes4)Get DELEGATECALL inputs
getAllCallInputs(address, bytes4)Get all call types
callinputAt(uint256)Get full recorded calldata for one call id
callOutputAt(uint256)Get full recorded return or revert bytes for one call id
getStateChanges(address, bytes32)Get state changes for a slot
getAssertionAdopter()Get the adopter contract address

Trigger Types

Register triggers in your triggers() function:

function triggers() external view override {
    // Trigger on any call to the adopter
    registerCallTrigger(this.myAssertion.selector);

    // Trigger on specific function call
    registerCallTrigger(this.myAssertion.selector, ITarget.transfer.selector);

    // Trigger on any storage change
    registerStorageChangeTrigger(this.myAssertion.selector);

    // Trigger on specific storage slot change
    registerStorageChangeTrigger(this.myAssertion.selector, bytes32(uint256(0)));

    // Trigger on balance change
    registerBalanceChangeTrigger(this.myAssertion.selector);
}

Backtesting

Test your assertions against historical blockchain transactions to validate correctness before deployment. The backtesting framework automatically detects both direct calls AND internal/nested calls to your target contract.

Setup

Add to your foundry.toml:

[profile.backtesting]
src = "src"
test = "test"
ffi = true
gas_limit = 100000000

Block Range Backtesting

Test all transactions in a block range:

import {CredibleTestWithBacktesting} from "credible-std/CredibleTestWithBacktesting.sol";
import {BacktestingTypes} from "credible-std/utils/BacktestingTypes.sol";

contract MyBacktest is CredibleTestWithBacktesting {
    function testHistoricalTransactions() public {
        BacktestingTypes.BacktestingResults memory results = executeBacktest(
            BacktestingTypes.BacktestingConfig({
                targetContract: 0x1234...,           // Contract to monitor
                endBlock: 1000000,                   // End block
                blockRange: 100,                     // Number of blocks to test
                assertionCreationCode: type(MyAssertion).creationCode,
                assertionSelector: MyAssertion.check.selector,
                rpcUrl: "https://eth.llamarpc.com",
                detailedBlocks: false,               // Verbose block output
                forkByTxHash: true                   // Fork by tx hash for accurate state
            })
        );

        // Check no assertions failed
        assertEq(results.assertionFailures, 0, "Assertions failed on historical data");
    }
}

Single Transaction Backtesting

Test a specific transaction by hash:

contract MyBacktest is CredibleTestWithBacktesting {
    function testSpecificTransaction() public {
        bytes32 txHash = 0xabc123...;

        BacktestingTypes.BacktestingResults memory results = executeBacktestForTransaction(
            txHash,
            0x1234...,                              // Target contract
            type(MyAssertion).creationCode,
            MyAssertion.check.selector,
            "https://eth.llamarpc.com"
        );

        assertEq(results.assertionFailures, 0);
    }
}

Running Backtests

# Run with verbose output
pcl test --ffi -vvvv --match-test testHistoricalTransactions

# Or with the backtesting profile
FOUNDRY_PROFILE=backtesting pcl test -vvvv

Internal Call Detection

The backtesting framework automatically detects transactions that call your target contract internally (e.g., through a router or aggregator). It tries multiple trace APIs with automatic fallback:

  1. trace_filter - Fastest, requires Erigon or archive node with trace API
  2. debug_traceBlockByNumber - Slower but widely supported
  3. debug_traceTransaction - Slowest, per-transaction tracing
  4. Direct calls only - Fallback when no trace APIs available

Example output:

=== TRANSACTION DISCOVERY ===
Target: 0x1234...
Blocks: 1000000 to 1000100

[INFO] Detecting both direct calls AND internal/nested calls to target
[INFO] Trying trace APIs with automatic fallback...

[TRACE] Using trace_filter API (fastest method for internal call detection)
[TRACE] trace_filter not supported by this RPC endpoint
[TRACE] Falling back to debug_traceBlockByNumber (slower but widely supported)

=== DISCOVERY COMPLETE ===
[INFO] Detection method: debug_traceBlockByNumber
[INFO] Internal calls: ENABLED

Understanding Results

The backtesting framework provides detailed categorization:

ResultDescription
SuccessTransaction passed assertion validation
SkippedTransaction didn’t trigger the assertion (selector mismatch)
Assertion FailedReal protocol violation detected
Replay FailureTransaction reverted before assertion could run
Unknown ErrorUnexpected failure

When an assertion fails, the framework automatically replays the transaction with full Foundry tracing enabled, showing the complete execution path for debugging.

State Change Helpers

The StateChanges contract provides type-safe helpers for inspecting storage changes:

// Get state changes as specific types
uint256[] memory uintChanges = getStateChangesUint(target, slot);
address[] memory addrChanges = getStateChangesAddress(target, slot);
bool[] memory boolChanges = getStateChangesBool(target, slot);
bytes32[] memory rawChanges = getStateChangesBytes32(target, slot);

// With mapping key support
uint256[] memory balanceChanges = getStateChangesUint(target, balancesSlot, userKey);

// With slot offset for struct fields
uint256[] memory fieldChanges = getStateChangesUint(target, structSlot, key, fieldOffset);

Resources

License

MIT

Contents

Contents

Contents

IERC20MetadataLike

Git Source

Minimal ERC20 metadata surface used by the Aave v3 Horizon example.

Functions

balanceOf

function balanceOf(address account) external view returns (uint256);

decimals

function decimals() external view returns (uint8);

AaveV3Types

Git Source

Structs

UserConfigurationMap

struct UserConfigurationMap {
    uint256 data;
}

ReserveDataLegacy

struct ReserveDataLegacy {
    uint256 configurationData;
    uint128 liquidityIndex;
    uint128 currentLiquidityRate;
    uint128 variableBorrowIndex;
    uint128 currentVariableBorrowRate;
    uint128 currentStableBorrowRate;
    uint40 lastUpdateTimestamp;
    uint16 id;
    address aTokenAddress;
    address stableDebtTokenAddress;
    address variableDebtTokenAddress;
    address interestRateStrategyAddress;
    uint128 accruedToTreasury;
    uint128 unbacked;
    uint128 isolationModeTotalDebt;
}

IAaveV3PoolLike

Git Source

Minimal pool surface matching the local Aave v3 Horizon pool interface.

This example was derived against ~/Documents/code/solidity/aave-v3-horizon/.

Functions

borrow

function borrow(address asset, uint256 amount, uint256 interestRateMode, uint16 referralCode, address onBehalfOf)
    external;

withdraw

function withdraw(address asset, uint256 amount, address to) external returns (uint256);

liquidationCall

function liquidationCall(
    address collateralAsset,
    address debtAsset,
    address user,
    uint256 debtToCover,
    bool receiveAToken
) external;

setUserUseReserveAsCollateral

function setUserUseReserveAsCollateral(address asset, bool useAsCollateral) external;

finalizeTransfer

function finalizeTransfer(
    address asset,
    address from,
    address to,
    uint256 amount,
    uint256 balanceFromBefore,
    uint256 balanceToBefore
) external;

getUserAccountData

function getUserAccountData(address user)
    external
    view
    returns (
        uint256 totalCollateralBase,
        uint256 totalDebtBase,
        uint256 availableBorrowsBase,
        uint256 currentLiquidationThreshold,
        uint256 ltv,
        uint256 healthFactor
    );

getUserConfiguration

function getUserConfiguration(address user) external view returns (AaveV3Types.UserConfigurationMap memory);

getReserveData

function getReserveData(address asset) external view returns (AaveV3Types.ReserveDataLegacy memory);

getReservesList

function getReservesList() external view returns (address[] memory);

ADDRESSES_PROVIDER

function ADDRESSES_PROVIDER() external view returns (address);

IAaveV3AddressesProviderLike

Git Source

Functions

getPriceOracle

function getPriceOracle() external view returns (address);

IAaveV3OracleLike

Git Source

Functions

getAssetPrice

function getAssetPrice(address asset) external view returns (uint256);

AaveV3HorizonProtectionSuite

Git Source

Inherits: LendingProtectionSuiteBase

Title: AaveV3HorizonProtectionSuite

Author: Phylax Systems

Example ILendingProtectionSuite targeting a local Aave v3 Horizon deployment.

This is intentionally aligned with the Aave v3 Horizon pool paths found in ~/Documents/code/solidity/aave-v3-horizon/:

  • borrow(...)
  • withdraw(...)
  • liquidationCall(...)
  • setUserUseReserveAsCollateral(asset, false)
  • finalizeTransfer(...) for aToken transfers that reduce effective collateral.

Constants

HEALTH_FACTOR_METRIC

bytes32 internal constant HEALTH_FACTOR_METRIC = 0x4845414c54485f464143544f5200000000000000000000000000000000000000

WITHDRAW_CLAIM_CHECK

bytes32 internal constant WITHDRAW_CLAIM_CHECK = "WITHDRAW_CLAIM"

LIQUIDATION_DEBT_CHECK

bytes32 internal constant LIQUIDATION_DEBT_CHECK = "LIQUIDATION_DEBT"

LIQUIDATION_COLLATERAL_CHECK

bytes32 internal constant LIQUIDATION_COLLATERAL_CHECK = "LIQUIDATION_COLLATERAL"

HEALTH_FACTOR_THRESHOLD

uint256 internal constant HEALTH_FACTOR_THRESHOLD = 1e18

HEALTH_FACTOR_THRESHOLD_INT

int256 internal constant HEALTH_FACTOR_THRESHOLD_INT = 1e18

POOL

address internal immutable POOL

ADDRESSES_PROVIDER

address internal immutable ADDRESSES_PROVIDER

Functions

constructor

Creates an Aave v3 Horizon suite bound to a specific pool.

The assertion adopter should also be this pool, since the monitored selectors are all pool entrypoints or pool callbacks.

constructor(address pool_) ;

Parameters

NameTypeDescription
pool_addressAave v3 Horizon pool address whose accounting and selectors this suite targets.

getMonitoredSelectors

Returns the Aave v3 Horizon pool selectors relevant to the shared lending invariants.

These map directly to the protocol paths that Aave v3 Horizon guards with the health factor checks or bounded-consumption checks relevant to the shared lending invariants.

function getMonitoredSelectors() external pure override returns (bytes4[] memory selectors);

Returns

NameTypeDescription
selectorsbytes4[]Pool selectors that should trigger the generic lending operation-safety check.

decodeOperation

Decodes an Aave v3 Horizon pool call into the shared lending operation model.

Aave v3 Horizon mixes calldata-owned and caller-owned account semantics:

  • borrow(...) checks the onBehalfOf account.
  • withdraw(...) and setUserUseReserveAsCollateral(...) act on msg.sender.
  • liquidationCall(...) checks the liquidated user, with asset = debtAsset and relatedAsset = collateralAsset.
  • finalizeTransfer(...) checks the from account when collateral leaves. Calls that do not reduce risk headroom are returned as neutral operations and filtered later by shouldCheckPostOperationSolvency(...).
function decodeOperation(TriggeredCall calldata triggered)
    external
    pure
    override
    returns (OperationContext memory operation);

Parameters

NameTypeDescription
triggeredTriggeredCallThe exact Aave v3 Horizon pool frame that caused the assertion to run.

Returns

NameTypeDescription
operationOperationContextProtocol-normalized description of the triggered action.

shouldCheckPostOperationSolvency

Filters decoded Aave v3 Horizon operations down to the ones that must preserve solvency.

This suite only checks paths that either increase debt or reduce effective collateral for a concrete account. Neutral operations are ignored to keep the assertion cheap and avoid false positives from selectors that are monitored broadly.

function shouldCheckPostOperationSolvency(OperationContext calldata operation)
    external
    pure
    override
    returns (bool shouldCheck);

Parameters

NameTypeDescription
operationOperationContextThe decoded operation context.

Returns

NameTypeDescription
shouldCheckboolTrue when the generic assertion should read post-call state.

getConsumptionChecks

Returns the bounded-consumption checks implied by the decoded Aave v3 Horizon operation.

This example exposes two shared resource bounds:

  • withdraws cannot consume more aToken claim than the user had before the call
  • liquidations cannot move more debt from the liquidator into the debt reserve than the user owed before the call, and cannot move more collateral to the liquidator than the user had before the call Other operation kinds return an empty array.
function getConsumptionChecks(
    TriggeredCall calldata triggered,
    OperationContext calldata operation,
    PhEvm.ForkId calldata beforeFork,
    PhEvm.ForkId calldata afterFork
) external view override returns (ConsumptionCheck[] memory checks);

Parameters

NameTypeDescription
triggeredTriggeredCallThe exact Aave v3 Horizon pool frame that caused the assertion to run.
operationOperationContextThe decoded operation context.
beforeForkPhEvm.ForkIdThe pre-call snapshot fork.
afterForkPhEvm.ForkIdThe post-call snapshot fork.

Returns

NameTypeDescription
checksConsumptionCheck[]Operation-specific bounded-consumption checks for the successful call.

getAccountSnapshot

Reads the post-call account snapshot needed by the Aave v3 Horizon solvency invariant.

Hot path override: the invariant itself only needs Aave’s aggregate health factor, so the suite skips per-reserve enumeration here. getAccountBalances(...) remains available for richer debugging or derived assertions.

function getAccountSnapshot(address account, PhEvm.ForkId calldata fork)
    external
    view
    virtual
    override
    returns (AccountSnapshot memory snapshot);

Parameters

NameTypeDescription
accountaddressThe account whose health factor should be checked.
forkPhEvm.ForkIdThe post-call snapshot fork.

Returns

NameTypeDescription
snapshotAccountSnapshotSnapshot containing aggregate state and the derived health-factor decision.

getAccountState

Reads Aave v3 Horizon aggregate account metrics from Pool.getUserAccountData(...).

The returned AccountState uses Aave’s base-currency values for total collateral and total debt, and stores the additional health-factor inputs in metadata.

function getAccountState(address account, PhEvm.ForkId calldata fork)
    external
    view
    override
    returns (AccountState memory state);

Parameters

NameTypeDescription
accountaddressThe account whose aggregate risk data should be queried.
forkPhEvm.ForkIdThe snapshot fork to query.

Returns

NameTypeDescription
stateAccountStateAggregate Aave v3 Horizon account state.

getAccountBalances

Enumerates Aave v3 reserve balances for the account.

This is not needed on the hot path for the example invariant, but it shows how a suite can still expose per-reserve state for debugging, richer assertions, or protocols whose solvency rule depends on per-asset inspection.

function getAccountBalances(address account, PhEvm.ForkId calldata fork)
    external
    view
    override
    returns (AccountBalance[] memory balances);

Parameters

NameTypeDescription
accountaddressThe account whose reserve balances should be queried.
forkPhEvm.ForkIdThe snapshot fork to query.

Returns

NameTypeDescription
balancesAccountBalance[]One entry per non-zero reserve position.

evaluateSolvency

Evaluates Aave v3 Horizon solvency from aggregate account state.

The example intentionally ignores per-reserve balances because Aave v3 Horizon’s own post-action checks reduce to health factor over aggregate pool data. Suites for other protocols may need to inspect the balances argument instead.

function evaluateSolvency(
    AccountState calldata state,
    AccountBalance[] calldata balances,
    PhEvm.ForkId calldata fork
) external pure override returns (SolvencyState memory solvency);

Parameters

NameTypeDescription
stateAccountStateAggregate account state produced by getAccountState(...).
balancesAccountBalance[]The per-reserve balances, unused in this implementation.
forkPhEvm.ForkIdThe snapshot fork, unused because all required information is in state.

Returns

NameTypeDescription
solvencySolvencyStateHealth-factor-based solvency result.

_getAccountState

Internal helper that reads and normalizes Aave v3 Horizon aggregate account data.

This is the canonical aggregate-state implementation used by both getAccountState(...) and the optimized getAccountSnapshot(...) hot path.

function _getAccountState(address account, PhEvm.ForkId memory fork)
    internal
    view
    returns (AccountState memory state);

Parameters

NameTypeDescription
accountaddressThe account whose risk data should be queried.
forkPhEvm.ForkIdThe snapshot fork to query.

Returns

NameTypeDescription
stateAccountStateAggregate state encoded in the common suite format.

_getAccountBalances

Internal helper that expands the account into reserve-level balances and values.

Reads the reserve list, user collateral bitset, reserve token addresses, and oracle prices, then emits one balance entry per reserve with a non-zero collateral or debt balance. The values are normalized to Aave’s base currency.

function _getAccountBalances(address account, PhEvm.ForkId memory fork)
    internal
    view
    returns (AccountBalance[] memory balances);

Parameters

NameTypeDescription
accountaddressThe account whose reserve positions should be queried.
forkPhEvm.ForkIdThe snapshot fork to query.

Returns

NameTypeDescription
balancesAccountBalance[]One entry per non-zero reserve position.

_getWithdrawClaimCheck

Builds the withdraw bounded-consumption check from Aave v3 Horizon call output and pre-state.

Pool.withdraw(...) returns the actual amount withdrawn, which already handles the type(uint256).max full-withdraw path. The available pre-operation claim is the user’s aToken balance before the call.

function _getWithdrawClaimCheck(
    TriggeredCall calldata triggered,
    OperationContext calldata operation,
    PhEvm.ForkId calldata beforeFork
) internal view returns (ConsumptionCheck memory check);

Parameters

NameTypeDescription
triggeredTriggeredCallThe traced withdraw call.
operationOperationContextThe decoded withdraw operation.
beforeForkPhEvm.ForkIdThe pre-call snapshot fork.

Returns

NameTypeDescription
checkConsumptionCheckBound requiring actual withdrawn amount to be no greater than pre-call supply.

_getLiquidationDebtCheck

Builds the liquidation debt-consumption check from actual debt-asset transfers.

Aave v3 Horizon clips liquidation debt to the user’s actual debt or the close-factor cap. The assertion therefore measures the actual debt asset moved from the liquidator to the debt reserve’s aToken during the successful liquidation call.

function _getLiquidationDebtCheck(
    OperationContext calldata operation,
    PhEvm.ForkId calldata beforeFork,
    PhEvm.ForkId calldata afterFork
) internal view returns (ConsumptionCheck memory check);

Parameters

NameTypeDescription
operationOperationContextThe decoded liquidation operation.
beforeForkPhEvm.ForkIdThe pre-call snapshot fork.
afterForkPhEvm.ForkIdThe post-call snapshot fork.

Returns

NameTypeDescription
checkConsumptionCheckBound requiring repaid debt to be no greater than pre-call debt.

_getLiquidationCollateralCheck

Builds the liquidation collateral-consumption check from actual collateral transfers.

This measures what the liquidator actually receives:

  • underlying collateral when receiveAToken == false
  • collateral aTokens when receiveAToken == true The bound is still capped by the user’s pre-call collateral claim.
function _getLiquidationCollateralCheck(
    OperationContext calldata operation,
    PhEvm.ForkId calldata beforeFork,
    PhEvm.ForkId calldata afterFork
) internal view returns (ConsumptionCheck memory check);

Parameters

NameTypeDescription
operationOperationContextThe decoded liquidation operation.
beforeForkPhEvm.ForkIdThe pre-call snapshot fork.
afterForkPhEvm.ForkIdThe post-call snapshot fork.

Returns

NameTypeDescription
checkConsumptionCheckBound requiring seized collateral to be no greater than pre-call collateral.

_evaluateHealthFactor

Converts Aave v3 Horizon aggregate metrics into the common solvency representation.

This is the protocol-specific core of the invariant for Aave v3 Horizon: an account with debt is solvent iff healthFactor >= 1e18.

function _evaluateHealthFactor(AccountState memory state) internal pure returns (SolvencyState memory solvency);

Parameters

NameTypeDescription
stateAccountStateAggregate Aave v3 account state whose metadata contains health-factor inputs.

Returns

NameTypeDescription
solvencySolvencyStateCommon solvency output expressed in terms of health factor.

_buildAccountBalance

Builds a single reserve-level balance entry for the account.

Returns (false, ...) when the account has neither supplied balance nor variable debt in the reserve, allowing the caller to compact the final array. This example intentionally follows the local Horizon borrow surface, which only exposes variable-rate borrowing.

function _buildAccountBalance(
    address asset,
    address account,
    uint256 userConfigData,
    address oracle,
    PhEvm.ForkId memory fork
) internal view returns (bool include, AccountBalance memory balance);

Parameters

NameTypeDescription
assetaddressThe reserve asset being inspected.
accountaddressThe account whose reserve position should be read.
userConfigDatauint256Aave v3 user-configuration bitset used to determine collateral usage.
oracleaddressPrice oracle used to value the reserve balances.
forkPhEvm.ForkIdThe snapshot fork to query.

Returns

NameTypeDescription
includeboolWhether the resulting balance entry should be kept.
balanceAccountBalanceNormalized reserve-level balance information.

_getReserveData

Reads Aave v3 Horizon reserve metadata for a single asset at the requested snapshot fork.

function _getReserveData(address asset, PhEvm.ForkId memory fork)
    internal
    view
    returns (AaveV3Types.ReserveDataLegacy memory reserveData);

Parameters

NameTypeDescription
assetaddressThe reserve asset whose metadata should be queried.
forkPhEvm.ForkIdThe snapshot fork to query.

Returns

NameTypeDescription
reserveDataAaveV3Types.ReserveDataLegacyReserve metadata returned by Pool.getReserveData(...).

_getUserReserveDebt

Reads the user’s total debt for one reserve from Aave v3 Horizon debt-token balances.

The example sums stable and variable debt token balances to make the liquidation bound robust across reserve configurations.

function _getUserReserveDebt(address asset, address account, PhEvm.ForkId memory fork)
    internal
    view
    returns (uint256 debtBalance);

Parameters

NameTypeDescription
assetaddressThe reserve asset whose debt position should be queried.
accountaddressThe user whose debt should be read.
forkPhEvm.ForkIdThe snapshot fork to query.

Returns

NameTypeDescription
debtBalanceuint256Total reserve debt for the user.

_readOptionalBalance

Reads a token balance when the token address may be unset.

Some deployments disable one debt-token flavor and leave the corresponding address at zero. This helper treats that case as a zero balance instead of reverting.

function _readOptionalBalance(address token, address account, PhEvm.ForkId memory fork)
    internal
    view
    returns (uint256 balance);

Parameters

NameTypeDescription
tokenaddressThe token contract to query, or address(0) when absent.
accountaddressThe account whose balance should be read.
forkPhEvm.ForkIdThe snapshot fork to query.

Returns

NameTypeDescription
balanceuint256The token balance, or zero when token == address(0).

_valueInBase

Converts an asset-denominated balance into Aave base currency.

Uses the Aave v3 Horizon oracle price and token decimals from the snapshot fork. This helper is suitable for example code and debugging, but suites with stricter precision requirements may want protocol-exact valuation logic.

function _valueInBase(address oracle, address asset, uint256 balance, PhEvm.ForkId memory fork)
    internal
    view
    returns (uint256);

Parameters

NameTypeDescription
oracleaddressAave v3 price oracle.
assetaddressAsset whose price and decimals should be read.
balanceuint256Raw token amount to convert.
forkPhEvm.ForkIdThe snapshot fork to query.

Returns

NameTypeDescription
<none>uint256value Asset value expressed in Aave base currency units.

_isUsingAsCollateral

Returns whether the reserve is enabled as collateral in Aave v3 Horizon’s user config bitset.

Aave v3 Horizon stores collateral and borrow flags as packed bit pairs keyed by reserve id. This helper reads the collateral bit for the reserve.

function _isUsingAsCollateral(uint256 userConfigData, uint256 reserveId) internal pure returns (bool);

Parameters

NameTypeDescription
userConfigDatauint256Packed Aave v3 user configuration.
reserveIduint256Reserve id from getReserveData(...).

Returns

NameTypeDescription
<none>boolisCollateral True when the reserve currently counts as collateral.

_toInt256

Safely casts a uint256 metric to int256 for SolvencyState.

Solvency metrics use signed integers in the common interface to support protocols with negative liquidity margins. Aave v3 health factor is always non-negative, so values above int256.max are saturated instead of reverting.

function _toInt256(uint256 value) internal pure returns (int256);

Parameters

NameTypeDescription
valueuint256Unsigned metric value to convert.

Returns

NameTypeDescription
<none>int256signedValue Saturated signed representation of value.

Structs

AaveAccountMetrics

Extra aggregate Aave v3 Horizon metrics kept in AccountState.metadata.

The common account shape does not have dedicated fields for these values, but they are useful for debugging and for reconstructing the health-factor-based solvency decision.

struct AaveAccountMetrics {
    uint256 availableBorrowsBase;
    uint256 currentLiquidationThreshold;
    uint256 ltv;
    uint256 healthFactor;
}

AaveV3HorizonOperationSafetyAssertion

Git Source

Inherits: LendingBaseAssertion

Title: AaveV3HorizonOperationSafetyAssertion

Author: Phylax Systems

Example single-entry assertion bundle for Aave v3 Horizon.

Usage: cl.assertion({ adopter: aaveV3HorizonPool, createData: abi.encodePacked(type(AaveV3HorizonOperationSafetyAssertion).creationCode, abi.encode(aaveV3HorizonPool)), fnSelector: AaveV3HorizonOperationSafetyAssertion.assertOperationSafety.selector })

Constants

SUITE

Dedicated Horizon suite deployed by this assertion bundle.

Keeping the suite in a helper contract preserves the one-create-data UX while keeping the assertion runtime below the EIP-170 size limit enforced by CI.

ILendingProtectionSuite internal immutable SUITE

Functions

constructor

Creates an Aave v3 Horizon assertion bundle with an internally deployed suite.

constructor(address pool_) ;

Parameters

NameTypeDescription
pool_addressAave v3 Horizon pool used both as the suite data source and assertion adopter.

_suite

Returns the suite implementation used by the generic lending assertion base.

The assertion keeps protocol-specific logic in a dedicated helper suite contract so the assertion runtime stays within CI’s contract-size limit.

function _suite() internal view override returns (ILendingProtectionSuite);

Returns

NameTypeDescription
<none>ILendingProtectionSuitesuite The internally deployed common lending suite implementation.

AaveV3ProtectionSuite

Git Source

Inherits: AaveV3HorizonProtectionSuite

Title: AaveV3ProtectionSuite

Author: Phylax Systems

Compatibility alias preserving the old generic Aave v3 suite name.

The implementation is Horizon-specific and derived from the local Horizon repository.

Functions

constructor

Creates the compatibility alias.

constructor(address pool_) AaveV3HorizonProtectionSuite(pool_);

Parameters

NameTypeDescription
pool_addressAave v3 Horizon pool used by the underlying suite.

AaveV3OperationSafetyAssertion

Git Source

Inherits: AaveV3HorizonOperationSafetyAssertion

Title: AaveV3OperationSafetyAssertion

Author: Phylax Systems

Compatibility alias preserving the old generic Aave v3 assertion name.

New users should prefer AaveV3HorizonOperationSafetyAssertion to make the Horizon scope explicit.

Functions

constructor

Creates the compatibility alias.

constructor(address pool_) AaveV3HorizonOperationSafetyAssertion(pool_);

Parameters

NameTypeDescription
pool_addressAave v3 Horizon pool used by the underlying assertion bundle.

AaveV3PostOperationSolvencyAssertion

Git Source

Inherits: AaveV3HorizonOperationSafetyAssertion

Title: AaveV3PostOperationSolvencyAssertion

Author: Phylax Systems

Deprecated compatibility alias for the pre-operation-safety contract name.

New users should prefer AaveV3HorizonOperationSafetyAssertion.

Functions

constructor

Creates the deprecated compatibility alias.

constructor(address pool_) AaveV3HorizonOperationSafetyAssertion(pool_);

Parameters

NameTypeDescription
pool_addressAave v3 Horizon pool used by the underlying assertion bundle.

ILendingProtectionSuite

Git Source

Title: ILendingProtectionSuite

Author: Phylax Systems

Step-oriented interface for protocol-specific lending protection suites.

Implementations expose the protocol-specific plumbing needed to assert a shared family of lending-protocol invariants:

  • any successful action that increases debt or reduces effective collateral must leave the affected account solvent under the protocol’s own risk metric
  • successful withdrawals must not consume more claim than the account had before the call
  • successful liquidations must not consume more debt or collateral than existed before the call The bounded-consumption portion should be measured from the successful call’s actual effect, such as traced return data, ERC20 transfer deltas, or protocol-emitted events, rather than from the requested input amount alone. Expected assertion flow:
  1. Read monitored selectors from getMonitoredSelectors().
  2. Resolve the caller-aware TriggeredCall.
  3. Decode the triggered call with decodeOperation(...).
  4. Read operation-specific consumption checks with getConsumptionChecks(...) and require consumed <= availableBefore for each returned check.
  5. Filter to solvency-relevant operations with shouldCheckPostOperationSolvency(...).
  6. Read the account snapshot with getAccountSnapshot(...).
  7. Require snapshot.solvency.isSolvent == true. Different protocols can encode different solvency metrics while preserving the same invariant:
  • Aave-like systems can expose metric = healthFactor, threshold = 1e18, comparison = Gte.
  • Euler-like systems can expose metric = collateralValue - liabilityValue, threshold = 0, comparison = Gt.

Functions

getMonitoredSelectors

Returns the adopter selectors that can participate in the shared lending invariants.

Implementations should return the selectors that the generic assertion must subscribe to on the adopter. These selectors do not all need to be solvency-worsening on every invocation; decodeOperation(...) and shouldCheckPostOperationSolvency(...) can later discard benign or no-op cases. The returned list is typically protocol-entrypoint specific.

function getMonitoredSelectors() external view returns (bytes4[] memory selectors);

Returns

NameTypeDescription
selectorsbytes4[]Selectors that should trigger the generic lending operation-safety assertion.

decodeOperation

Decodes the triggered adopter call into a protocol-normalized operation context.

Caller-aware decoding is necessary because some protocols encode the affected account in msg.sender instead of calldata. Implementations should populate operation.account with the account whose post-operation solvency must be checked and mark whether the call increased debt and/or reduced effective collateral. Unsupported or irrelevant selectors should normally return the zero-value OperationContext rather than revert.

function decodeOperation(TriggeredCall calldata triggered) external view returns (OperationContext memory operation);

Parameters

NameTypeDescription
triggeredTriggeredCallThe exact adopter frame that caused the assertion to run.

Returns

NameTypeDescription
operationOperationContextProtocol-normalized context used by downstream filtering and checks.

shouldCheckPostOperationSolvency

Returns whether the decoded action must preserve post-operation solvency.

This is the last protocol-specific filter before snapshot reads happen. Implementations should return false for actions that are not risk-increasing in the shared sense, such as enabling collateral, zero-amount paths, or protocol no-ops.

function shouldCheckPostOperationSolvency(OperationContext calldata operation)
    external
    view
    returns (bool shouldCheck);

Parameters

NameTypeDescription
operationOperationContextThe decoded operation context returned by decodeOperation(...).

Returns

NameTypeDescription
shouldCheckboolTrue when the assertion should read state and enforce solvency.

getConsumptionChecks

Returns the bounded-consumption checks implied by the decoded operation.

Each returned entry is enforced as consumed <= availableBefore. Implementations should return an empty array when the operation has no shared bounded-consumption invariant. consumed must reflect the actual effect of the successful call, not merely the requested amount. This lets suites support clipped operations such as partial withdraws or capped liquidations without bespoke assertion logic in the base contract. Suitable data sources include traced call output, ERC20 transfer introspection, or decoded logs.

function getConsumptionChecks(
    TriggeredCall calldata triggered,
    OperationContext calldata operation,
    PhEvm.ForkId calldata beforeFork,
    PhEvm.ForkId calldata afterFork
) external view returns (ConsumptionCheck[] memory checks);

Parameters

NameTypeDescription
triggeredTriggeredCallThe exact adopter frame that caused the assertion to run.
operationOperationContextThe decoded operation context returned by decodeOperation(...).
beforeForkPhEvm.ForkIdThe pre-call snapshot fork.
afterForkPhEvm.ForkIdThe post-call snapshot fork.

Returns

NameTypeDescription
checksConsumptionCheck[]Operation-specific bounds to enforce for the successful call.

getAccountSnapshot

Reads the account snapshot used by the post-operation solvency assertion.

Implementations can override this with a protocol-optimized hot path instead of forcing the assertion to always compute per-asset balances. The returned snapshot must describe the post-operation state at fork. The shared suite default in LendingBaseAssertion.sol composes this from getAccountState(...), getAccountBalances(...), and evaluateSolvency(...).

function getAccountSnapshot(address account, PhEvm.ForkId calldata fork)
    external
    view
    returns (AccountSnapshot memory snapshot);

Parameters

NameTypeDescription
accountaddressThe account whose post-operation solvency is being checked.
forkPhEvm.ForkIdThe post-call snapshot fork that should be queried.

Returns

NameTypeDescription
snapshotAccountSnapshotAggregate state, optional per-asset balances, and the final solvency result.

getAccountState

Reads protocol-normalized aggregate account state at a given snapshot fork.

Implementations should return enough aggregate information for downstream solvency logic and debugging. Protocol-specific fields that do not fit the common shape belong in state.metadata.

function getAccountState(address account, PhEvm.ForkId calldata fork)
    external
    view
    returns (AccountState memory state);

Parameters

NameTypeDescription
accountaddressThe account whose risk state should be inspected.
forkPhEvm.ForkIdThe snapshot fork to read from.

Returns

NameTypeDescription
stateAccountStateAggregate account state in protocol-defined accounting units.

getAccountBalances

Reads protocol-normalized per-asset balances for an account at a snapshot fork.

Implementations may return an empty array when balances are not required for the hot-path solvency decision and getAccountSnapshot(...) already exposes an optimized path. When provided, balances should use the same valuation units as AccountState.

function getAccountBalances(address account, PhEvm.ForkId calldata fork)
    external
    view
    returns (AccountBalance[] memory balances);

Parameters

NameTypeDescription
accountaddressThe account whose positions should be inspected.
forkPhEvm.ForkIdThe snapshot fork to read from.

Returns

NameTypeDescription
balancesAccountBalance[]Per-asset collateral and debt entries relevant to the account.

evaluateSolvency

Evaluates the protocol’s solvency rule from the decoded account snapshot.

Implementations should encode the exact rule the protocol uses to decide whether an account is solvent or liquidatable. state and balances are passed separately so simple protocols can decide from aggregate state alone while more complex protocols can inspect per-asset positions.

function evaluateSolvency(
    AccountState calldata state,
    AccountBalance[] calldata balances,
    PhEvm.ForkId calldata fork
) external view returns (SolvencyState memory solvency);

Parameters

NameTypeDescription
stateAccountStateAggregate account state returned by getAccountState(...).
balancesAccountBalance[]Per-asset balances returned by getAccountBalances(...).
forkPhEvm.ForkIdThe snapshot fork used for the solvency evaluation.

Returns

NameTypeDescription
solvencySolvencyStateProtocol-defined solvency decision and supporting metric data.

Structs

TriggeredCall

Resolved information about the exact adopter call that triggered the assertion.

struct TriggeredCall {
    /// @notice Function selector invoked on the adopter.
    bytes4 selector;
    /// @notice Immediate caller of the adopter frame.
    address caller;
    /// @notice Adopter target address that was called.
    address target;
    /// @notice Raw calldata for the adopter frame.
    bytes input;
    /// @notice Call identifier used to construct a PreCall snapshot.
    uint256 callStart;
    /// @notice Call identifier used to construct a PostCall snapshot.
    uint256 callEnd;
}

OperationContext

Protocol-decoded context for a monitored lending call.

struct OperationContext {
    /// @notice The adopter selector that produced this operation context.
    bytes4 selector;
    /// @notice The high-level action kind.
    OperationKind kind;
    /// @notice The immediate caller of the adopter frame.
    address caller;
    /// @notice The primary account whose solvency should be checked after the operation.
    address account;
    /// @notice The primary asset involved in the action, if any.
    address asset;
    /// @notice Optional second asset involved in the action, if any.
    /// @dev This is primarily useful for multi-asset operations such as liquidation, where
    ///      `asset` can represent the debt asset and `relatedAsset` the collateral asset.
    address relatedAsset;
    /// @notice Secondary account involved in the action, if any (receiver, liquidator, etc.).
    address counterparty;
    /// @notice Protocol-decoded requested or declared amount associated with the action, if any.
    /// @dev For clipped operations, this may differ from the actual amount later enforced by
    ///      `getConsumptionChecks(...)`.
    uint256 amount;
    /// @notice True when the action increases the account's debt exposure.
    bool increasesDebt;
    /// @notice True when the action reduces the account's effective collateral.
    bool reducesEffectiveCollateral;
    /// @notice Extension point for protocol-specific metadata.
    bytes metadata;
}

AccountState

Protocol-normalized aggregate state for an account at a snapshot fork.

struct AccountState {
    /// @notice The account whose state was read.
    address account;
    /// @notice Aggregate collateral value using the implementation's protocol-defined accounting units.
    uint256 totalCollateralValue;
    /// @notice Aggregate debt value using the implementation's protocol-defined accounting units.
    uint256 totalDebtValue;
    /// @notice Whether the account currently has any open debt.
    bool hasDebt;
    /// @notice Extension point for protocol-specific aggregate data.
    bytes metadata;
}

AccountBalance

Per-asset balance and value data for an account at a snapshot fork.

struct AccountBalance {
    /// @notice The reserve, market, or asset address represented by this balance entry.
    address asset;
    /// @notice Raw collateral or supplied balance tracked for the account.
    uint256 collateralBalance;
    /// @notice Raw debt balance tracked for the account.
    uint256 debtBalance;
    /// @notice Protocol-normalized collateral value for this asset.
    uint256 collateralValue;
    /// @notice Protocol-normalized debt value for this asset.
    uint256 debtValue;
    /// @notice Whether this asset currently counts as collateral for the account.
    bool countsAsCollateral;
    /// @notice Extension point for protocol-specific per-asset metadata.
    bytes metadata;
}

SolvencyState

Protocol-defined solvency output for an account at a snapshot fork.

struct SolvencyState {
    /// @notice Whether the account is solvent under the protocol's own rules.
    bool isSolvent;
    /// @notice Whether the protocol would consider the account liquidatable at this snapshot.
    bool isLiquidatable;
    /// @notice Identifier for the solvency metric, e.g. "HEALTH_FACTOR" or "LIQUIDITY_EXCESS".
    bytes32 metricName;
    /// @notice Protocol-normalized solvency metric.
    int256 metric;
    /// @notice Threshold that the metric is compared against.
    int256 threshold;
    /// @notice Comparison rule used to interpret `metric` vs `threshold`.
    ComparisonKind comparison;
    /// @notice Extension point for protocol-specific evidence or decoded fields.
    bytes metadata;
}

AccountSnapshot

Full post-operation snapshot for a monitored account.

struct AccountSnapshot {
    /// @notice Aggregate state for the monitored account.
    AccountState state;
    /// @notice Per-asset balances. Implementations may return an empty array on the hot path.
    AccountBalance[] balances;
    /// @notice Protocol-defined solvency decision for the snapshot.
    SolvencyState solvency;
}

ConsumptionCheck

One concrete resource-consumption bound that must hold for a successful operation.

struct ConsumptionCheck {
    /// @notice Identifier for the bound being asserted, e.g. "WITHDRAW_CLAIM".
    bytes32 checkName;
    /// @notice The account whose pre-operation resource balance caps the consumption.
    address account;
    /// @notice The asset whose pre-operation balance or claim is being bounded.
    address asset;
    /// @notice Resource available before the operation in protocol-defined accounting units.
    uint256 availableBefore;
    /// @notice Actual resource consumed by the successful operation in the same units.
    uint256 consumed;
    /// @notice Extension point for protocol-specific evidence or decoded fields.
    bytes metadata;
}

Enums

OperationKind

The lending action being inspected for shared post-operation safety checks.

enum OperationKind {
    Unknown,
    Borrow,
    WithdrawCollateral,
    DisableCollateral,
    TransferCollateral,
    Liquidation
}

ComparisonKind

Comparison rule for the protocol-defined solvency metric.

enum ComparisonKind {
    Unknown,
    Gte,
    Gt
}

LendingProtectionSuiteBase

Git Source

Inherits: ForkUtils, ILendingProtectionSuite

Title: LendingProtectionSuiteBase

Author: Phylax Systems

Shared default implementations for lending protection suites.

Functions

getConsumptionChecks

Default bounded-consumption implementation for suites with no extra resource checks.

Override this when the protocol needs withdraw, liquidation, or other consumption bounds. Returning an empty array keeps solvency-only suites source-compatible with the generic lending assertion.

function getConsumptionChecks(
    TriggeredCall calldata triggered,
    OperationContext calldata operation,
    PhEvm.ForkId calldata beforeFork,
    PhEvm.ForkId calldata afterFork
) external view virtual override returns (ConsumptionCheck[] memory checks);

Parameters

NameTypeDescription
triggeredTriggeredCallThe exact adopter frame that caused the assertion to run.
operationOperationContextThe decoded operation context.
beforeForkPhEvm.ForkIdThe pre-call snapshot fork.
afterForkPhEvm.ForkIdThe post-call snapshot fork.

Returns

NameTypeDescription
checksConsumptionCheck[]Empty by default.

getAccountSnapshot

Composes a full account snapshot from the step-oriented suite functions.

This is the default implementation for step-based suites. Override it only when the protocol exposes a materially cheaper or more direct way to answer the invariant than calling getAccountState(...), getAccountBalances(...), and evaluateSolvency(...) separately.

function getAccountSnapshot(address account, PhEvm.ForkId calldata fork)
    external
    view
    virtual
    override
    returns (AccountSnapshot memory snapshot);

Parameters

NameTypeDescription
accountaddressThe account whose post-operation state should be read.
forkPhEvm.ForkIdThe snapshot fork to query.

Returns

NameTypeDescription
snapshotAccountSnapshotAggregate state, balances, and solvency produced by the suite steps.

_viewFailureMessage

Returns the suite-specific revert string for failed fork-time static calls.

function _viewFailureMessage() internal pure virtual override returns (string memory);

LendingBaseAssertion

Git Source

Inherits: Assertion

Title: LendingBaseAssertion

Author: Phylax Systems

Generic lending operation-safety assertion for lending protocols.

Inherit this together with a concrete ILendingProtectionSuite implementation. The base contract handles one decode pass per triggered call, then enforces both:

  • any bounded-consumption checks returned by the suite
  • post-operation solvency for risk-increasing operations

Functions

_suite

Returns the protocol-specific lending suite that powers this assertion.

Concrete assertions typically inherit both this base contract and a suite contract, then return ILendingProtectionSuite(address(this)). Returning a different contract is also valid if the assertion delegates protocol logic elsewhere.

function _suite() internal view virtual returns (ILendingProtectionSuite);

Returns

NameTypeDescription
<none>ILendingProtectionSuitesuite The suite used to decode operations and evaluate solvency.

triggers

Registers one generic lending operation-safety check for every monitored selector.

This is the only trigger wiring most lending assertions need to implement. The suite decides which selectors matter through getMonitoredSelectors(), and this base maps all of them to assertOperationSafety().

function triggers() external view virtual override;

assertOperationSafety

Enforces the shared lending operation-safety invariants for a successful call.

Assertion authors should usually point Credible at this selector. The method resolves the triggering adopter frame, decodes the protocol operation once, enforces any bounded- consumption checks returned by the suite, and then enforces post-operation solvency when the suite marks the operation as risk-increasing.

function assertOperationSafety() external view;

assertPostOperationSolvency

Backwards-compatible alias for the legacy solvency-only entrypoint name.

Older bundles may still reference this selector directly. It now runs the full generic lending operation-safety pipeline rather than only the solvency portion.

function assertPostOperationSolvency() external view;

_assertOperationSafety

Internal implementation shared by the public lending assertion entrypoints.

Runs all shared lending checks exposed by the suite against the triggered adopter call.

function _assertOperationSafety() internal view;

_assertConsumptionChecks

Enforces the suite-provided bounded-consumption checks for the triggered operation.

Suites may return zero, one, or many bounds depending on the operation kind. Each bound is enforced as consumed <= availableBefore, where both values must already be expressed in the same protocol-defined units.

function _assertConsumptionChecks(
    ILendingProtectionSuite suite,
    ILendingProtectionSuite.TriggeredCall memory triggered,
    ILendingProtectionSuite.OperationContext memory operation,
    PhEvm.ForkId memory beforeFork,
    PhEvm.ForkId memory afterFork
) internal view;

Parameters

NameTypeDescription
suiteILendingProtectionSuiteThe protocol-specific lending suite.
triggeredILendingProtectionSuite.TriggeredCallThe exact adopter frame that caused the assertion to run.
operationILendingProtectionSuite.OperationContextThe decoded lending operation.
beforeForkPhEvm.ForkIdThe pre-call snapshot fork.
afterForkPhEvm.ForkIdThe post-call snapshot fork.

_assertPostOperationSolvency

Enforces post-operation solvency for risk-increasing operations.

Operations that do not increase debt or reduce effective collateral are skipped. This is the original shared lending invariant, now run as one stage of the broader operation-safety pipeline.

function _assertPostOperationSolvency(
    ILendingProtectionSuite suite,
    ILendingProtectionSuite.TriggeredCall memory triggered,
    ILendingProtectionSuite.OperationContext memory operation,
    PhEvm.ForkId memory afterFork
) internal view;

Parameters

NameTypeDescription
suiteILendingProtectionSuiteThe protocol-specific lending suite.
triggeredILendingProtectionSuite.TriggeredCallThe exact adopter frame that caused the assertion to run.
operationILendingProtectionSuite.OperationContextThe decoded lending operation.
afterForkPhEvm.ForkIdThe post-call snapshot fork used for the solvency read.

_resolveTriggeredCall

Resolves the exact adopter frame that caused the current assertion execution.

Credible exposes the selector and call identifiers in ph.context(), but the suite also needs raw calldata and caller information for correct protocol decoding. This helper reconstructs that frame from getAllCallInputs(...) and packages it into ILendingProtectionSuite.TriggeredCall.

function _resolveTriggeredCall() internal view returns (ILendingProtectionSuite.TriggeredCall memory triggered);

Returns

NameTypeDescription
triggeredILendingProtectionSuite.TriggeredCallCaller-aware information about the adopter call being checked.

Errors

LendingTriggeredCallNotFound

error LendingTriggeredCallNotFound(bytes4 selector, uint256 callStart);

LendingOperationAccountMissing

error LendingOperationAccountMissing(bytes4 selector);

LendingConsumptionCheckViolated

error LendingConsumptionCheckViolated(
    address account,
    bytes4 selector,
    ILendingProtectionSuite.OperationKind kind,
    bytes32 checkName,
    address asset,
    uint256 consumed,
    uint256 availableBefore
);

LendingPostOperationSolvencyViolated

error LendingPostOperationSolvencyViolated(
    address account,
    bytes4 selector,
    ILendingProtectionSuite.OperationKind kind,
    bytes32 metricName,
    int256 metric,
    int256 threshold
);

Contents

ERC4626AssetFlowAssertion

Git Source

Inherits: ERC4626BaseAssertion

Title: ERC4626AssetFlowAssertion

Author: Phylax Systems

Asserts that ERC-20 token movement and the vault’s internal asset accounting agree, and that fundamental share-token invariants hold. Invariants covered:

  • Token movement matches accounting: the change in totalAssets across the transaction equals the net ERC-20 flow into/out of the vault. This catches transfer-fee tokens, rebasing tokens, or accounting bugs where totalAssets drifts from reality.
  • Zero address never holds shares: balanceOf(address(0)) == 0 after every share-minting operation.

Uses V2 registerTxEndTrigger for tx-wide checks and registerFnCallTrigger + ph.context() for call-scoped checks.

Functions

_registerAssetFlowTriggers

Register the default trigger set for asset-flow invariants.

function _registerAssetFlowTriggers() internal view;

assertAssetFlowMatchesAccounting

Verifies the change in totalAssets across the tx matches the net ERC-20 flow.

function assertAssetFlowMatchesAccounting() external;

_netAssetFlow

Compute net ERC-20 flow into (+) or out of (-) the vault across the tx.

Override for vaults that deploy assets through adapters or external protocols. The override should include flows to/from all relevant addresses (vault + adapters).

function _netAssetFlow() internal view virtual returns (int256 netFlow);

assertZeroAddressHasNoShares

Verifies the zero address never holds vault shares.

Uses ph.context() to check at PostCall of the triggering call.

function assertZeroAddressHasNoShares() external;

ERC4626BaseAssertion

Git Source

Inherits: Assertion

Title: ERC4626BaseAssertion

Author: Phylax Systems

Base contract for ERC-4626 vault assertions (V2 syntax).

Provides vault-specific state accessors on top of the shared Assertion helpers. Inherit from this (and one or more invariant contracts), then implement triggers(). Example – combine share-price, preview, and outflow invariants:

contract MyVaultAssertion is ERC4626SharePriceAssertion, ERC4626PreviewAssertion, ERC4626CumulativeOutflowAssertion {
constructor(address _vault)
ERC4626BaseAssertion(_vault)
ERC4626SharePriceAssertion(50) // 50 bps tolerance
ERC4626CumulativeOutflowAssertion(1_000, 24 hours) // 10% in 24h
{}
function triggers() external view override {
_registerSharePriceTriggers();
_registerPreviewTriggers();
_registerCumulativeOutflowTriggers();
}
}

Constants

vault

The ERC-4626 vault being monitored (assertion adopter).

address internal immutable vault

asset

The underlying ERC-20 asset of the vault.

address internal immutable asset

Functions

constructor

constructor(address _vault) ;

_totalAssetsAt

function _totalAssetsAt(PhEvm.ForkId memory fork) internal view returns (uint256);

_totalSupplyAt

function _totalSupplyAt(PhEvm.ForkId memory fork) internal view returns (uint256);

_shareBalanceAt

function _shareBalanceAt(address account, PhEvm.ForkId memory fork) internal view returns (uint256);

_assetBalanceAt

Uses the same balanceOf(address) selector — valid for any ERC-20.

function _assetBalanceAt(address account, PhEvm.ForkId memory fork) internal view returns (uint256);

ERC4626CumulativeOutflowAssertion

Git Source

Inherits: ERC4626BaseAssertion

Title: ERC4626CumulativeOutflowAssertion

Author: Phylax Systems

Circuit breaker that triggers when cumulative ERC-20 outflow from the vault exceeds a percentage threshold within a rolling time window. Invariant covered:

  • Cumulative outflow cap: the net outflow of the vault’s underlying asset must not exceed outflowThresholdBps of the TVL snapshot within a rolling outflowWindowDuration.

Uses watchCumulativeOutflow trigger registration — the executor handles all persistent state tracking, TVL snapshots, and threshold enforcement internally. The assertion function fires only when the threshold is breached. Override assertCumulativeOutflow for smart breaker logic (e.g. deposit/repay-only mode). The default implementation unconditionally reverts (hard breaker).

Constants

outflowThresholdBps

Maximum cumulative outflow as basis points of the TVL snapshot. 1000 = 10%.

uint256 public immutable outflowThresholdBps

outflowWindowDuration

Rolling window length in seconds.

uint256 public immutable outflowWindowDuration

Functions

constructor

constructor(uint256 _thresholdBps, uint256 _windowDuration) ;

_registerCumulativeOutflowTriggers

Register the cumulative outflow circuit breaker trigger.

Call this inside your triggers().

function _registerCumulativeOutflowTriggers() internal view;

assertCumulativeOutflow

Called when cumulative outflow exceeds the threshold.

Default is a hard breaker (unconditional revert). Override for smart breaker logic — e.g. allow deposits but block withdrawals using ph.outflowContext() and _matchingCalls().

function assertCumulativeOutflow() external virtual;

ERC4626PreviewAssertion

Git Source

Inherits: ERC4626BaseAssertion

Title: ERC4626PreviewAssertion

Author: Phylax Systems

Asserts that ERC-4626 preview functions are consistent with the actual results of the corresponding state-changing operations, and that rounding favors the vault. Invariants covered:

  • Preview consistency: for the same pre-state, previewDeposit(a) == shares minted by deposit(a) previewMint(s) == assets charged by mint(s) previewWithdraw(a) == shares burned by withdraw(a) previewRedeem(s) == assets returned by redeem(s)
  • Rounding direction (implicit in the inequality checks): previewDeposit rounds DOWN (returns fewer shares -> favors vault) previewMint rounds UP (returns more assets -> favors vault) previewWithdraw rounds UP (returns more shares -> favors vault) previewRedeem rounds DOWN (returns fewer assets -> favors vault)

Uses V2 registerFnCallTrigger + ph.context() for call-scoped triggers, ph.callinputAt() to read call arguments, and ph.callOutputAt() to read the actual return value — replacing the totalSupply/totalAssets delta inference from V1.

Functions

_registerPreviewTriggers

Register the default trigger set for preview-consistency invariants.

Each ERC-4626 operation gets its own assertion function via registerFnCallTrigger.

function _registerPreviewTriggers() internal view;

_maxPreviewDeviation

Maximum acceptable deviation between a preview result and the actual result.

Defaults to 1 (single-unit rounding). Override for vaults with wider rounding (e.g. multi-step rounding, fee chunking, or decimal normalization).

function _maxPreviewDeviation() internal view virtual returns (uint256);

assertDepositPreview

For the triggering deposit(assets, receiver) call, verifies: previewDeposit(assets) <= actualSharesMinted (ERC-4626 spec) actualSharesMinted - previewDeposit(assets) <= maxDeviation

function assertDepositPreview() external;

assertMintPreview

For the triggering mint(shares, receiver) call, verifies: previewMint(shares) >= actualAssetsCharged (ERC-4626 spec) previewMint(shares) - actualAssetsCharged <= maxDeviation

function assertMintPreview() external;

assertWithdrawPreview

For the triggering withdraw(assets, receiver, owner) call, verifies: previewWithdraw(assets) >= actualSharesBurned (ERC-4626 spec) previewWithdraw(assets) - actualSharesBurned <= maxDeviation

function assertWithdrawPreview() external;

assertRedeemPreview

For the triggering redeem(shares, receiver, owner) call, verifies: previewRedeem(shares) <= actualAssetsReturned (ERC-4626 spec) actualAssetsReturned - previewRedeem(shares) <= maxDeviation

function assertRedeemPreview() external;

_stripSelector

Strip the 4-byte selector from raw call input bytes.

function _stripSelector(bytes memory input) internal pure returns (bytes memory args);

ERC4626SharePriceAssertion

Git Source

Inherits: ERC4626BaseAssertion

Title: ERC4626SharePriceAssertion

Author: Phylax Systems

Asserts that the vault’s share price (totalAssets / totalSupply) does not decrease beyond a configurable tolerance, both transaction-wide and per individual user operation. Invariants covered:

  • Non-dilutive entry/exit: absent explicit fee accrual or loss recognition, deposit/mint/withdraw/redeem must not reduce assets-per-share for remaining holders.
  • Rounding favors incumbents: the share price must not move against the vault (i.e., existing holders) during ordinary user operations.

Uses the V2 assetsMatchSharePrice / assetsMatchSharePriceAt precompiles for the primary check, and ratioGe for an explicit cross-multiplication comparison as a second, readable signal. The tolerance is expressed in basis points (1 bps = 0.01%). A tolerance of 0 enforces strict non-decrease; values like 25-50 allow for rounding noise.

Constants

sharePriceToleranceBps

Maximum acceptable share-price decrease in basis points.

uint256 public immutable sharePriceToleranceBps

Functions

constructor

constructor(uint256 _toleranceBps) ;

_registerSharePriceTriggers

Register the default trigger set for share-price invariants.

Uses registerTxEndTrigger for the tx-wide envelope and registerFnCallTrigger for per-call checks. Call this inside your triggers().

function _registerSharePriceTriggers() internal view;

assertSharePriceEnvelope

Verifies the share price did not decrease beyond tolerance across the entire transaction.

Uses assetsMatchSharePrice for a comprehensive all-forks check, then ratioGe for an explicit pre/post comparison as a second signal.

function assertSharePriceEnvelope() external;

assertPerCallSharePrice

Verifies each individual deposit/mint/withdraw/redeem call does not decrease the share price beyond tolerance.

Uses ph.context() to get the triggering call boundaries and assetsMatchSharePriceAt for a targeted pre/post-call comparison.

function assertPerCallSharePrice() external;

IERC4626

Git Source

Title: IERC4626

Minimal ERC-4626 tokenized vault interface for assertion contracts.

Includes the ERC-20 view surface (totalSupply, balanceOf) since ERC-4626 extends ERC-20.

Functions

totalSupply

function totalSupply() external view returns (uint256);

balanceOf

function balanceOf(address account) external view returns (uint256);

asset

function asset() external view returns (address);

totalAssets

function totalAssets() external view returns (uint256);

convertToShares

function convertToShares(uint256 assets) external view returns (uint256);

convertToAssets

function convertToAssets(uint256 shares) external view returns (uint256);

previewDeposit

function previewDeposit(uint256 assets) external view returns (uint256);

previewMint

function previewMint(uint256 shares) external view returns (uint256);

previewWithdraw

function previewWithdraw(uint256 assets) external view returns (uint256);

previewRedeem

function previewRedeem(uint256 shares) external view returns (uint256);

maxDeposit

function maxDeposit(address receiver) external view returns (uint256);

maxMint

function maxMint(address receiver) external view returns (uint256);

maxWithdraw

function maxWithdraw(address owner) external view returns (uint256);

maxRedeem

function maxRedeem(address owner) external view returns (uint256);

deposit

function deposit(uint256 assets, address receiver) external returns (uint256 shares);

mint

function mint(uint256 shares, address receiver) external returns (uint256 assets);

withdraw

function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares);

redeem

function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets);

Contents

Contents

Target

Git Source

State Variables

value

uint256 value = 1

Functions

readStorage

function readStorage() external view returns (uint256);

writeStorage

function writeStorage(uint256 value_) public;

incrementStorage

function incrementStorage() public;

writeStorageAndRevert

function writeStorageAndRevert(uint256 value_) external;

receive

receive() external payable;

fallback

fallback() external;

Events

Log

event Log(uint256 value);

Constants

Git Source

TARGET

Target constant TARGET = Target(payable(0xdCCf1eEB153eF28fdc3CF97d33f60576cF092e9c))

Contents

TestAccessAssertionStorage

Git Source

Inherits: Assertion

State Variables

someAddress

address public someAddress

Functions

accessAssertionStorage

function accessAssertionStorage() external;

triggers

function triggers() external view override;

TriggeringTx

Git Source

Functions

constructor

constructor() payable;

Contents

TestCallInputAt

Git Source

Inherits: Assertion

Functions

constructor

constructor() payable;

callInputAt

function callInputAt() external view;

emptyCalldataReturnsEmptyBytes

function emptyCalldataReturnsEmptyBytes() external view;

triggers

function triggers() external view override;

TriggeringTx

Git Source

Functions

constructor

constructor() payable;

TestCallInputs

Git Source

Inherits: Assertion

Functions

constructor

constructor() payable;

getCallInputs

function getCallInputs() external view;

callInputsWrongTarget

function callInputsWrongTarget() external view;

callNoSelector

function callNoSelector() external view;

triggers

function triggers() external view override;

TriggeringTx

Git Source

Functions

constructor

constructor() payable;

TestCallOutputAt

Git Source

Inherits: Assertion

Functions

constructor

constructor() payable;

callOutputAtReturnsEncodedReturnData

function callOutputAtReturnsEncodedReturnData() external view;

callOutputAtReturnsEmptyBytesForVoidCall

function callOutputAtReturnsEmptyBytesForVoidCall() external view;

callOutputAtReturnsRevertData

function callOutputAtReturnsRevertData() external view;

callOutputAtRejectsRevertedSubtreeCallId

function callOutputAtRejectsRevertedSubtreeCallId() external view;

_successfulNestedWriteId

function _successfulNestedWriteId() internal view returns (uint256 successfulNestedWriteId);

_revertedWriteStorageAndRevertId

function _revertedWriteStorageAndRevertId() internal view returns (uint256);

_revertedSubtreeChildCallId

function _revertedSubtreeChildCallId() internal view returns (uint256);

triggers

function triggers() external view override;

TriggeringTx

Git Source

Functions

constructor

constructor() payable;

CallFrameTrigger

Git Source

Functions

trigger

function trigger() external;

RevertingSubtreeTrigger

Git Source

Functions

trigger

function trigger() external;

TestForking

Git Source

Inherits: Assertion

State Variables

sum

uint256 public sum = 0

someInitValue

uint256 public someInitValue = 1

Functions

forkSwitchStorage

function forkSwitchStorage() external;

forkSwitchNewDeployedContract

function forkSwitchNewDeployedContract() external;

forkSwitchBalance

function forkSwitchBalance() external;

persistTargetContracts

function persistTargetContracts() external;

triggers

function triggers() external view override;

TriggeringTx

Git Source

Functions

constructor

constructor() payable;

TestGetAdopter

Git Source

Inherits: Assertion

Functions

constructor

constructor() payable;

getAdopter

function getAdopter() external view;

triggers

function triggers() external view override;

TriggeringTx

Git Source

Functions

constructor

constructor() payable;

TestLoad

Git Source

Inherits: Assertion

Functions

constructor

constructor() payable;

_loadCount

function _loadCount() internal view returns (uint256);

load

function load() external;

loadRandomAccount

function loadRandomAccount() external view;

triggers

function triggers() external view override;

TriggeringTx

Git Source

Functions

constructor

constructor() payable;

TestLogs

Git Source

Inherits: Assertion

Functions

constructor

constructor() payable;

getLogs

function getLogs() external;

triggers

function triggers() external view override;

TriggeringTx

Git Source

Functions

constructor

constructor() payable;

MappingTarget

Git Source

State Variables

balances

mapping(address => uint256) public balances

Functions

setBalance

function setBalance(address user, uint256 amount) external;

TestChangedMappingKeys

Git Source

Inherits: Assertion

Functions

constructor

constructor() payable;

checkChangedKeys

function checkChangedKeys() external view;

triggers

function triggers() external view override;

TestMappingValueDiff

Git Source

Inherits: Assertion

Functions

constructor

constructor() payable;

checkValueDiff

function checkValueDiff() external view;

triggers

function triggers() external view override;

MappingTriggeringTx

Git Source

Functions

constructor

constructor() payable;

Constants

Git Source

MAPPING_TARGET

MappingTarget constant MAPPING_TARGET = MappingTarget(0xdCCf1eEB153eF28fdc3CF97d33f60576cF092e9c)

TestStateChanges1

Git Source

Inherits: Assertion

Functions

constructor

constructor() payable;

getStateChanges1

function getStateChanges1() external view;

triggers

function triggers() external view override;

TriggeringTx

Git Source

Functions

constructor

constructor() payable;

TestStateChanges2

Git Source

Inherits: Assertion

Functions

constructor

constructor() payable;

getStateChanges2

function getStateChanges2() external view;

triggers

function triggers() external view override;

TriggeringTx

Git Source

Functions

constructor

constructor() payable;

TestStateChangesNone

Git Source

Inherits: Assertion

Functions

constructor

constructor() payable;

getStateChangesNone

function getStateChangesNone() external view;

triggers

function triggers() external view override;

TriggeringTx

Git Source

Functions

constructor

constructor() payable;

Contents

TestAllCallTrigger

Git Source

Inherits: Assertion

Functions

triggered

function triggered() external pure;

triggers

function triggers() external view override;

TriggeringTx

Git Source

Functions

constructor

constructor() payable;

TestAllStorageChangeTrigger

Git Source

Inherits: Assertion

Functions

triggered

function triggered() external;

triggers

function triggers() external view override;

TriggeringTx

Git Source

Functions

constructor

constructor() payable;

TestBalanceTrigger

Git Source

Inherits: Assertion

Functions

triggered

function triggered() external pure;

triggers

function triggers() external view override;

TriggeringTx

Git Source

Functions

constructor

constructor() payable;

TestSomeCallTrigger

Git Source

Inherits: Assertion

Functions

triggered

function triggered() external pure;

triggers

function triggers() external view override;

TriggeringTx

Git Source

Functions

constructor

constructor() payable;

TestStorageSlotChangeTrigger

Git Source

Inherits: Assertion

Functions

triggered

function triggered() external pure;

triggers

function triggers() external view override;

TriggeringTx

Git Source

Functions

constructor

constructor() payable;

Contents

BacktestingTypes

Git Source

Title: BacktestingTypes

Author: Phylax Systems

Type definitions for the backtesting framework

Contains structs for configuration, transaction data, and results used by CredibleTestWithBacktesting

Structs

TransactionData

Transaction data from blockchain

struct TransactionData {
    bytes32 hash;
    address from;
    address to;
    uint256 value;
    bytes data;
    uint256 blockNumber;
    uint256 transactionIndex;
    uint256 gasPrice;
    uint256 gasLimit;
    uint256 maxFeePerGas;
    uint256 maxPriorityFeePerGas;
}

ValidationDetails

Detailed validation result with error information

struct ValidationDetails {
    ValidationResult result;
    string errorMessage;
    bool isProtocolViolation;
}

BacktestingConfig

Configuration for backtesting runs (block range mode)

Internal call detection is automatic - the system tries trace_filter first, then falls back to debug_traceBlockByNumber, debug_traceTransaction, and finally direct-calls-only if no trace methods are supported.

struct BacktestingConfig {
    address targetContract;
    uint256 endBlock;
    uint256 blockRange;
    bytes assertionCreationCode;
    bytes4 assertionSelector;
    string rpcUrl;
    bool detailedBlocks; // Enable detailed block summaries in output
    bool forkByTxHash; // Fork by transaction hash for correct pre-tx state; block forks are unsafe.
}

BacktestingResults

Enhanced backtesting results with detailed categorization

struct BacktestingResults {
    uint256 totalTransactions;
    uint256 processedTransactions; // Transactions that were actually processed
    uint256 successfulValidations;
    uint256 skippedTransactions; // Transactions where assertion wasn't triggered (selector mismatch)
    uint256 assertionFailures; // Real protocol violations
    uint256 replayFailures; // Transactions that reverted during replay before assertion
    uint256 unknownErrors; // Unexpected failures
}

Enums

ValidationResult

Validation result categories for detailed error analysis

enum ValidationResult {
    Success, // Transaction passed all assertions
    Skipped, // Transaction didn't trigger the assertion (function selector mismatch)
    ReplayFailure, // Transaction reverted during replay before assertion could execute
    AssertionFailed, // Assertion logic failed (actual protocol violation)
    UnknownError // Unexpected error during validation
}

BacktestingUtils

Git Source

Title: BacktestingUtils

Author: Phylax Systems

Utility functions for the backtesting framework

Provides parsing, string manipulation, and error decoding utilities used internally by CredibleTestWithBacktesting

Functions

extractDataLine

Extract transaction data from fetcher output

function extractDataLine(string memory output) internal pure returns (string memory);

_isWhitespace

Check if a character is whitespace

function _isWhitespace(bytes1 char) private pure returns (bool);

splitString

Simple pipe-delimited string splitter

function splitString(string memory str, string memory) internal pure returns (string[] memory);

stringToUint

Parse hex or decimal string to uint256

function stringToUint(string memory str) internal pure returns (uint256);

stringToAddress

Parse hex address string to address

function stringToAddress(string memory str) internal pure returns (address);

stringToBytes32

Parse hex string to bytes32

function stringToBytes32(string memory str) internal pure returns (bytes32);

hexStringToBytes

Parse hex string to bytes

function hexStringToBytes(string memory str) internal pure returns (bytes memory);

bytes32ToHex

Convert bytes32 to hex string

function bytes32ToHex(bytes32 data) internal pure returns (string memory);

extractFunctionSelector

Extract function selector from calldata

function extractFunctionSelector(bytes memory data) internal pure returns (string memory);

parseMultipleTransactions

Parse multiple transactions from a single data line

function parseMultipleTransactions(string memory txDataString)
    internal
    pure
    returns (BacktestingTypes.TransactionData[] memory transactions);

_hexCharToUint8

Convert hex character to uint8

function _hexCharToUint8(bytes1 char) private pure returns (uint8);

substring

Helper to get substring for debugging

function substring(string memory str, uint256 start, uint256 len) private pure returns (string memory);

decodeRevertReason

Decode revert reason from error data

function decodeRevertReason(bytes memory data) internal pure returns (string memory);

Parameters

NameTypeDescription
databytesThe error data from a failed call

Returns

NameTypeDescription
<none>stringThe decoded revert reason string

_panicCodeToString

Convert panic code to human-readable string

function _panicCodeToString(uint256 code) private pure returns (string memory);

bytesToHex

Convert bytes to hex string

function bytesToHex(bytes memory data) internal pure returns (bytes memory);

Parameters

NameTypeDescription
databytesThe bytes to convert

Returns

NameTypeDescription
<none>bytesThe hex string representation

getErrorTypeString

Get human-readable error type string from validation result

function getErrorTypeString(BacktestingTypes.ValidationResult result) internal pure returns (string memory);

Parameters

NameTypeDescription
resultBacktestingTypes.ValidationResultThe validation result enum

Returns

NameTypeDescription
<none>stringThe human-readable string representation

startsWith

Check if a string starts with a prefix

function startsWith(string memory str, string memory prefix) internal pure returns (bool);

Parameters

NameTypeDescription
strstringThe string to check
prefixstringThe prefix to look for

Returns

NameTypeDescription
<none>boolTrue if str starts with prefix

getDefaultScriptSearchPaths

Get the standard search paths for transaction_fetcher.sh

function getDefaultScriptSearchPaths() internal pure returns (string[] memory);

Returns

NameTypeDescription
<none>string[]Array of paths to check, in order of preference

IERC20BalanceReaderLike

Git Source

Minimal token balance surface used by fork-read helpers.

Functions

balanceOf

function balanceOf(address account) external view returns (uint256);

ForkUtils

Git Source

Inherits: Credible

Title: ForkUtils

Author: Phylax Systems

Shared fork-aware read and ERC20-delta helpers for assertions and protection suites.

Constants

FORK_VIEW_GAS

Gas forwarded to snapshot-time protocol view calls made through ph.staticcallAt.

uint64 internal constant FORK_VIEW_GAS = 500_000

Functions

_viewFailureMessage

Revert string used when a fork-time static call fails.

Override this when a more specific failure message is useful for a derived contract.

function _viewFailureMessage() internal pure virtual returns (string memory);

_viewAt

Executes a static call against target at a specific snapshot fork.

function _viewAt(address target, bytes memory data, PhEvm.ForkId memory fork)
    internal
    view
    returns (bytes memory resultData);

Parameters

NameTypeDescription
targetaddressThe protocol contract to query.
databytesABI-encoded calldata for the target view.
forkPhEvm.ForkIdThe snapshot fork the read should execute against.

Returns

NameTypeDescription
resultDatabytesRaw return bytes from the static call.

_readUintAt

Convenience wrapper that decodes a snapshot-time static call as uint256.

function _readUintAt(address target, bytes memory data, PhEvm.ForkId memory fork)
    internal
    view
    returns (uint256 value);

_readUint8At

Convenience wrapper that decodes a snapshot-time static call as uint8.

function _readUint8At(address target, bytes memory data, PhEvm.ForkId memory fork)
    internal
    view
    returns (uint8 value);

_readAddressAt

Convenience wrapper that decodes a snapshot-time static call as address.

function _readAddressAt(address target, bytes memory data, PhEvm.ForkId memory fork)
    internal
    view
    returns (address value);

_readBoolAt

Convenience wrapper that decodes a snapshot-time static call as bool.

function _readBoolAt(address target, bytes memory data, PhEvm.ForkId memory fork)
    internal
    view
    returns (bool value);

_readBalanceAt

Convenience wrapper that reads an ERC20-style balanceOf(account) at a snapshot fork.

function _readBalanceAt(address token, address account, PhEvm.ForkId memory fork)
    internal
    view
    returns (uint256 balance);

_reducedErc20BalanceDeltasAt

Returns reduced ERC20 transfer deltas for a token within the selected fork scope.

function _reducedErc20BalanceDeltasAt(address token, PhEvm.ForkId memory fork)
    internal
    view
    returns (PhEvm.Erc20TransferData[] memory deltas);

_transferredValueAt

Returns the total amount of token transferred from from to to in the fork scope.

function _transferredValueAt(address token, address from, address to, PhEvm.ForkId memory fork)
    internal
    view
    returns (uint256 value);

_consumedBetween

Computes the non-negative decrease between two snapshot values.

function _consumedBetween(uint256 beforeValue, uint256 afterValue) internal pure returns (uint256 consumed);

IERC20LogUtils

Git Source

Title: IERC20LogUtils

Author: Phylax Systems

Helpers for querying and decoding standard ERC20 logs returned by PhEvm.

Constants

TRANSFER_EVENT_SIGNATURE

Standard ERC20 Transfer event signature.

bytes32 internal constant TRANSFER_EVENT_SIGNATURE = keccak256("Transfer(address,address,uint256)")

APPROVAL_EVENT_SIGNATURE

Standard ERC20 Approval event signature.

bytes32 internal constant APPROVAL_EVENT_SIGNATURE = keccak256("Approval(address,address,uint256)")

Functions

transferQuery

Builds a PhEvm query for ERC20 Transfer logs emitted by token.

Pass address(0) to match Transfer logs from any emitter.

function transferQuery(address token) internal pure returns (PhEvm.LogQuery memory query);

approvalQuery

Builds a PhEvm query for ERC20 Approval logs emitted by token.

Pass address(0) to match Approval logs from any emitter.

function approvalQuery(address token) internal pure returns (PhEvm.LogQuery memory query);

isTransfer

Returns true when log has the canonical ERC20 Transfer event shape.

function isTransfer(PhEvm.Log memory log) internal pure returns (bool);

isApproval

Returns true when log has the canonical ERC20 Approval event shape.

function isApproval(PhEvm.Log memory log) internal pure returns (bool);

decodeTransfer

Decodes a canonical ERC20 Transfer log.

function decodeTransfer(PhEvm.Log memory log) internal pure returns (PhEvm.Erc20TransferData memory transfer);

decodeApproval

Decodes a canonical ERC20 Approval log.

function decodeApproval(PhEvm.Log memory log) internal pure returns (ApprovalData memory approval);

decodeTransfers

Decodes all logs as ERC20 Transfer events.

Reverts if any log is not a canonical Transfer event.

function decodeTransfers(PhEvm.Log[] memory logs)
    internal
    pure
    returns (PhEvm.Erc20TransferData[] memory transfers);

decodeApprovals

Decodes all logs as ERC20 Approval events.

Reverts if any log is not a canonical Approval event.

function decodeApprovals(PhEvm.Log[] memory logs) internal pure returns (ApprovalData[] memory approvals);

_topicAddress

function _topicAddress(bytes32 topic) private pure returns (address);

Structs

ApprovalData

Decoded ERC20 Approval event data.

struct ApprovalData {
    /// @notice The token contract that emitted the Approval event.
    address token_addr;
    /// @notice The token owner indexed in topic1.
    address owner;
    /// @notice The approved spender indexed in topic2.
    address spender;
    /// @notice The approved amount decoded from log data.
    uint256 value;
}

LogUtils

Git Source

Title: LogUtils

Author: Phylax Systems

Pure utility library for matching, filtering, and decoding EVM logs returned by getLogs() or getLogsQuery(). All functions operate on in-memory PhEvm.Log structs and do not call any precompiles.

Implemented with internal functions so they inline at the call site and avoid external call overhead.

Functions

sig

Returns topic[0] of the log, or bytes32(0) if no topics.

function sig(PhEvm.Log memory log) internal pure returns (bytes32);

isSig

True if log.topics[0] == eventSig.

function isSig(PhEvm.Log memory log, bytes32 eventSig) internal pure returns (bool);

isFrom

True if log.emitter == emitter.

function isFrom(PhEvm.Log memory log, address emitter) internal pure returns (bool);

isEvent

True if log matches both emitter and eventSig.

function isEvent(PhEvm.Log memory log, address emitter, bytes32 eventSig) internal pure returns (bool);

indexedTopic

Returns topics[indexedIdx + 1] as raw bytes32. Reverts if out of bounds.

The +1 skips topic[0] (the event signature).

function indexedTopic(PhEvm.Log memory log, uint256 indexedIdx) internal pure returns (bytes32);

indexedAddress

Decodes indexed param as address.

function indexedAddress(PhEvm.Log memory log, uint256 indexedIdx) internal pure returns (address);

indexedUint

Decodes indexed param as uint256.

function indexedUint(PhEvm.Log memory log, uint256 indexedIdx) internal pure returns (uint256);

indexedBool

Decodes indexed param as bool.

function indexedBool(PhEvm.Log memory log, uint256 indexedIdx) internal pure returns (bool);

topic

Encodes address as topic-compatible bytes32 (left-pads 20 bytes to 32).

function topic(address value) internal pure returns (bytes32);

topic

Encodes uint256 as topic-compatible bytes32.

function topic(uint256 value) internal pure returns (bytes32);

first

Returns the first log matching (emitter, eventSig).

function first(PhEvm.Log[] memory logs, address emitter, bytes32 eventSig)
    internal
    pure
    returns (bool found, PhEvm.Log memory log);

Returns

NameTypeDescription
foundboolTrue if a matching log was found.
logPhEvm.LogThe first matching log, or an empty log if none found.

count

Counts logs matching (emitter, eventSig).

function count(PhEvm.Log[] memory logs, address emitter, bytes32 eventSig) internal pure returns (uint256 n);

Assertion

Git Source

Inherits: ForkUtils, StateChanges

Title: Assertion

Author: Phylax Systems

Base contract for creating Credible Layer assertions

Inherit from this contract to create custom assertions. Assertions can inspect transaction state via the inherited ph precompile and register triggers to specify when the assertion should be executed. Example:

contract MyAssertion is Assertion {
function triggers() external view override {
registerCallTrigger(this.checkInvariant.selector, ITarget.deposit.selector);
}
function checkInvariant() external {
ph.forkPostTx();
Check invariants...
}
}

Constants

triggerRecorder

The trigger recorder precompile for registering assertion triggers

Address is derived from a deterministic hash for consistency

TriggerRecorder constant triggerRecorder = TriggerRecorder(address(uint160(uint256(keccak256("TriggerRecorder")))))

specRecorder

The spec recorder precompile for registering the assertion spec

Address is derived from keccak256(“SpecRecorder”)

SpecRecorder constant specRecorder = SpecRecorder(address(uint160(uint256(keccak256("SpecRecorder")))))

Functions

triggers

Used to record fn selectors and their triggers.

function triggers() external view virtual;

registerCallTrigger

Registers a call trigger for the AA without specifying an AA function selector. This will trigger the assertion function on any call to the AA.

function registerCallTrigger(bytes4 fnSelector) internal view;

Parameters

NameTypeDescription
fnSelectorbytes4The function selector of the assertion function.

registerCallTrigger

Registers a call trigger for calls to the AA with a specific AA function selector.

function registerCallTrigger(bytes4 fnSelector, bytes4 triggerSelector) internal view;

Parameters

NameTypeDescription
fnSelectorbytes4The function selector of the assertion function.
triggerSelectorbytes4The function selector upon which the assertion will be triggered.

registerStorageChangeTrigger

Registers storage change trigger for any slot

function registerStorageChangeTrigger(bytes4 fnSelector) internal view;

Parameters

NameTypeDescription
fnSelectorbytes4The function selector of the assertion function.

registerStorageChangeTrigger

Registers storage change trigger for a specific slot

function registerStorageChangeTrigger(bytes4 fnSelector, bytes32 slot) internal view;

Parameters

NameTypeDescription
fnSelectorbytes4The function selector of the assertion function.
slotbytes32The storage slot to trigger on.

registerBalanceChangeTrigger

Registers balance change trigger for the AA

function registerBalanceChangeTrigger(bytes4 fnSelector) internal view;

Parameters

NameTypeDescription
fnSelectorbytes4The function selector of the assertion function.

registerFnCallTrigger

Registers an onFnCall trigger. The assertion fires once per matching call, with TriggerContext available via ph.context().

function registerFnCallTrigger(bytes4 fnSelector, bytes4 triggerSelector) internal view;

Parameters

NameTypeDescription
fnSelectorbytes4The assertion function to invoke.
triggerSelectorbytes4The 4-byte selector on the adopter to watch for.

registerTxEndTrigger

Registers a trigger that fires once after the entire transaction completes.

function registerTxEndTrigger(bytes4 fnSelector) internal view;

Parameters

NameTypeDescription
fnSelectorbytes4The assertion function to invoke.

registerErc20ChangeTrigger

Registers a trigger that fires when a token’s balances change.

function registerErc20ChangeTrigger(bytes4 fnSelector, address token) internal view;

Parameters

NameTypeDescription
fnSelectorbytes4The assertion function to invoke.
tokenaddressThe ERC20 token address to watch.

watchCumulativeOutflow

Registers a circuit breaker trigger that fires when cumulative ERC20 outflow from the assertion adopter exceeds a percentage threshold within a rolling time window.

function watchCumulativeOutflow(address token, uint256 thresholdBps, uint256 windowDuration, bytes4 fnSelector)
    internal
    view;

Parameters

NameTypeDescription
tokenaddressThe ERC20 token address to monitor.
thresholdBpsuint256Maximum cumulative outflow as basis points of the TVL snapshot taken at window start. 1000 = 10%.
windowDurationuint256Rolling window length in seconds.
fnSelectorbytes4The assertion function to invoke when the threshold is breached.

watchCumulativeInflow

Registers a circuit breaker trigger that fires when cumulative ERC20 inflow into the assertion adopter exceeds a percentage threshold within a rolling time window.

function watchCumulativeInflow(address token, uint256 thresholdBps, uint256 windowDuration, bytes4 fnSelector)
    internal
    view;

Parameters

NameTypeDescription
tokenaddressThe ERC20 token address to monitor.
thresholdBpsuint256Maximum cumulative inflow as basis points of the TVL snapshot taken at window start. 1000 = 10%.
windowDurationuint256Rolling window length in seconds.
fnSelectorbytes4The assertion function to invoke when the threshold is breached.

_successOnlyFilter

Returns a CallFilter that only matches successful calls at any depth.

function _successOnlyFilter() internal pure returns (PhEvm.CallFilter memory filter);

_matchingCalls

Returns successful calls matching target and selector, up to limit.

function _matchingCalls(address target, bytes4 selector, uint256 limit)
    internal
    view
    returns (PhEvm.TriggerCall[] memory);

_preTx

function _preTx() internal pure returns (PhEvm.ForkId memory);

_postTx

function _postTx() internal pure returns (PhEvm.ForkId memory);

_preCall

function _preCall(uint256 callId) internal pure returns (PhEvm.ForkId memory);

_postCall

function _postCall(uint256 callId) internal pure returns (PhEvm.ForkId memory);

registerAssertionSpec

Registers the desired assertion spec. Must be called within the constructor. The assertion spec defines what subset of precompiles are available. Can only be called once. For an assertion to be valid, it needs a defined spec.

function registerAssertionSpec(AssertionSpec spec) internal view;

Parameters

NameTypeDescription
specAssertionSpecThe desired AssertionSpec.

console

Git Source

Title: console

Author: Phylax Systems

Logging library for Credible Layer assertions

Provides console logging functionality within assertion execution context. Logs are captured by the Credible Layer runtime for debugging purposes.

Constants

CONSOLE_ADDRESS

The console precompile address

Derived from a deterministic hash to ensure consistency with the runtime

address constant CONSOLE_ADDRESS = address(uint160(uint256(keccak256("Kim Jong Un Sucks"))))

Functions

log

Log a string message

Messages are captured by the Credible Layer runtime

function log(string memory message) internal view;

Parameters

NameTypeDescription
messagestringThe message to log

Credible

Git Source

Title: Credible

Author: Phylax Systems

Base contract providing access to the PhEvm precompile interface

All assertion contracts should inherit from this contract (via Assertion) to access the PhEvm precompile for reading transaction state, logs, and call inputs.

Constants

ph

The PhEvm precompile instance for accessing transaction state

The address is derived from a deterministic hash to ensure consistency

PhEvm constant ph = PhEvm(address(uint160(uint256(keccak256("Kim Jong Un Sucks")))))

VmEx

Git Source

Inherits: Vm

Title: VmEx

Extended Vm interface with assertion testing capabilities

Extends the standard Forge Vm interface with Credible Layer specific cheatcodes

Functions

assertion

Register an assertion for testing

function assertion(address adopter, bytes calldata createData, bytes4 fnSelector) external;

Parameters

NameTypeDescription
adopteraddressThe address of the contract that adopts the assertion
createDatabytesThe creation bytecode of the assertion contract
fnSelectorbytes4The function selector of the assertion function to test

CredibleTest

Git Source

Title: CredibleTest

Author: Phylax Systems

Base contract for testing Credible Layer assertions with Forge

Inherit from this contract (or CredibleTestWithBacktesting) to test assertions locally

Constants

cl

The extended Vm cheatcode interface for assertion testing

Provides access to assertion-specific cheatcodes

VmEx public constant cl = VmEx(address(uint160(uint256(keccak256("hevm cheat code")))))

CredibleTestWithBacktesting

Git Source

Inherits: CredibleTest, Test

Title: CredibleTestWithBacktesting

Author: Phylax Systems

Extended CredibleTest with historical transaction backtesting capabilities

Inherit from this contract to test assertions against historical blockchain transactions. Supports two modes:

  • Block range mode: Test all transactions in a block range via executeBacktest(config)
  • Single transaction mode: Test a specific transaction via executeBacktestForTransaction(txHash, ...) Example:
contract MyBacktest is CredibleTestWithBacktesting {
function testHistorical() public {
executeBacktest(BacktestingTypes.BacktestingConfig({
targetContract: 0x...,
endBlock: 1000000,
blockRange: 100,
assertionCreationCode: type(MyAssertion).creationCode,
assertionSelector: MyAssertion.check.selector,
rpcUrl: "https://eth.llamarpc.com",
detailedBlocks: false,
forkByTxHash: true
}));
}
}

State Variables

_cachedScriptPath

Cached script path to avoid repeated filesystem lookups

string private _cachedScriptPath

Functions

executeBacktestForTransaction

Execute backtesting for a single transaction by hash (overload for single tx mode)

function executeBacktestForTransaction(
    bytes32 txHash,
    address targetContract,
    bytes memory assertionCreationCode,
    bytes4 assertionSelector,
    string memory rpcUrl
) public returns (BacktestingTypes.BacktestingResults memory results);

Parameters

NameTypeDescription
txHashbytes32The transaction hash to backtest
targetContractaddressThe target contract address
assertionCreationCodebytesThe assertion contract creation code
assertionSelectorbytes4The assertion function selector
rpcUrlstringThe RPC URL to use

Returns

NameTypeDescription
resultsBacktestingTypes.BacktestingResultsThe backtesting results

executeBacktest

Execute backtesting with config struct (block range mode)

function executeBacktest(BacktestingTypes.BacktestingConfig memory config)
    public
    returns (BacktestingTypes.BacktestingResults memory results);

_getScriptSearchPaths

Get the standard search paths for transaction_fetcher.sh

Override this in your test contract to add custom search paths

function _getScriptSearchPaths() internal view virtual returns (string[] memory);

Returns

NameTypeDescription
<none>string[]Array of paths to check, in order of preference

_findScriptPath

Find the transaction_fetcher.sh script path

Checks environment variable first, then searches common locations, and finally uses find to auto-detect the script location. Override _getScriptSearchPaths() to customize search locations

function _findScriptPath() internal virtual returns (string memory);

Returns

NameTypeDescription
<none>stringThe path to transaction_fetcher.sh

_autoDetectScriptPath

Auto-detect the script path using find command

Searches the project directory for transaction_fetcher.sh

function _autoDetectScriptPath() internal virtual returns (string memory);

Returns

NameTypeDescription
<none>stringThe detected path, or empty string if not found

_fetchTransactions

Fetch transactions using FFI

Automatically detects internal calls using trace APIs with fallback: trace_filter -> debug_traceBlockByNumber -> debug_traceTransaction -> direct calls only

function _fetchTransactions(address targetContract, uint256 startBlock, uint256 endBlock, string memory rpcUrl)
    private
    returns (BacktestingTypes.TransactionData[] memory transactions);

_executeBacktestForSingleTransaction

Execute backtesting for a single transaction specified by hash

function _executeBacktestForSingleTransaction(
    bytes32 txHash,
    address targetContract,
    bytes memory assertionCreationCode,
    bytes4 assertionSelector,
    string memory rpcUrl
) private returns (BacktestingTypes.BacktestingResults memory results);

_fetchTransactionByHash

Fetch a single transaction by hash using FFI

function _fetchTransactionByHash(bytes32 txHash, string memory rpcUrl)
    private
    returns (BacktestingTypes.TransactionData memory txData);

_parseTransactionFromTsv

Parse transaction data from tab-separated output

function _parseTransactionFromTsv(string memory tsvLine)
    private
    pure
    returns (BacktestingTypes.TransactionData memory txData);

_validateTransaction

Validate a single transaction with detailed error categorization

function _validateTransaction(
    address targetContract,
    bytes memory assertionCreationCode,
    bytes4 assertionSelector,
    string memory rpcUrl,
    BacktestingTypes.TransactionData memory txData,
    bool forkByTxHash
) private returns (BacktestingTypes.ValidationDetails memory validation);

_replayTransactionForTrace

Replay a failed transaction to show the full execution trace

Forks to state before the tx and makes a raw call so Foundry prints the full trace

function _replayTransactionForTrace(
    address, // targetContract - unused, kept for interface compatibility
    bytes memory, // assertionCreationCode - unused
    bytes4, // assertionSelector - unused
    string memory rpcUrl,
    BacktestingTypes.TransactionData memory txData
) private;

_categorizeAndLogError

Categorize and log error details

function _categorizeAndLogError(BacktestingTypes.ValidationDetails memory validation) private pure;

_printDetailedResults

Print detailed results with error categorization

function _printDetailedResults(
    uint256 startBlock,
    uint256 endBlock,
    BacktestingTypes.BacktestingResults memory results
) private pure;

PhEvm

Git Source

Title: PhEvm

Author: Phylax Systems

Precompile interface for accessing transaction state within assertions

This interface provides access to the Credible Layer’s execution environment, allowing assertions to inspect transaction state, logs, call inputs, and storage changes. The precompile is available at a deterministic address during assertion execution.

Functions

forkPreTx

Fork to the state before the assertion-triggering transaction

DEPRECATED: Use staticcallAt / loadStateAt with ForkId instead.

function forkPreTx() external;

forkPostTx

Fork to the state after the assertion-triggering transaction

DEPRECATED: Use staticcallAt / loadStateAt with ForkId instead.

function forkPostTx() external;

forkPreCall

Fork to the state before a specific call execution

DEPRECATED: Use staticcallAt / loadStateAt with ForkId instead.

function forkPreCall(uint256 id) external;

forkPostCall

Fork to the state after a specific call execution

DEPRECATED: Use staticcallAt / loadStateAt with ForkId instead.

function forkPostCall(uint256 id) external;

load

Load a storage slot value from any address

DEPRECATED: Use loadStateAt with ForkId instead.

function load(address target, bytes32 slot) external view returns (bytes32 data);

loadStateAt

Read a storage slot from the current assertion adopter at a snapshot.

function loadStateAt(bytes32 slot, ForkId calldata fork) external view returns (bytes32 value);

Parameters

NameTypeDescription
slotbytes32The storage slot to read.
forkForkIdThe snapshot fork to read from.

Returns

NameTypeDescription
valuebytes32The raw 32-byte value at the slot.

loadStateAt

Read a storage slot from any account at a snapshot.

function loadStateAt(address target, bytes32 slot, ForkId calldata fork) external view returns (bytes32 value);

Parameters

NameTypeDescription
targetaddressThe address to read storage from.
slotbytes32The storage slot to read.
forkForkIdThe snapshot fork to read from.

Returns

NameTypeDescription
valuebytes32The raw 32-byte value at the slot.

staticcallAt

Execute a static call against a snapshot fork.

function staticcallAt(address target, bytes calldata data, uint64 gas_limit, ForkId calldata fork)
    external
    view
    returns (StaticCallResult memory result);

Parameters

NameTypeDescription
targetaddressThe contract to call.
databytesThe ABI-encoded function call.
gas_limituint64The gas budget forwarded to the nested static call.
forkForkIdThe snapshot fork to execute against.

Returns

NameTypeDescription
resultStaticCallResultSuccess flag and return or revert bytes from the nested call.

getLogsQuery

Get logs matching a query from a snapshot fork

function getLogsQuery(LogQuery calldata query, ForkId calldata fork) external view returns (Log[] memory logs);

Parameters

NameTypeDescription
queryLogQueryThe emitter and signature filters to apply
forkForkIdThe snapshot fork to read logs from

Returns

NameTypeDescription
logsLog[]Array of logs matching the query inside the selected snapshot window

getErc20Transfers

Returns all ERC20 transfers for a single token in the specified fork.

function getErc20Transfers(address token, ForkId calldata fork)
    external
    view
    returns (Erc20TransferData[] memory transfers);

Parameters

NameTypeDescription
tokenaddressThe ERC20 token address.
forkForkIdThe fork to query.

Returns

NameTypeDescription
transfersErc20TransferData[]Array of decoded transfer records.

getErc20TransfersForTokens

Returns all ERC20 transfers for multiple tokens in the specified fork.

function getErc20TransfersForTokens(address[] calldata tokens, ForkId calldata fork)
    external
    view
    returns (Erc20TransferData[] memory transfers);

Parameters

NameTypeDescription
tokensaddress[]Array of ERC20 token addresses.
forkForkIdThe fork to query.

Returns

NameTypeDescription
transfersErc20TransferData[]Combined array of decoded transfer records across all tokens.

changedErc20BalanceDeltas

Returns all transfers involving the given token for the specified fork.

Semantic alias of getErc20Transfers for balance-delta workflows.

function changedErc20BalanceDeltas(address token, ForkId calldata fork)
    external
    view
    returns (Erc20TransferData[] memory deltas);

Parameters

NameTypeDescription
tokenaddressThe ERC20 token address.
forkForkIdThe fork to query.

reduceErc20BalanceDeltas

Reduces transfers into net balance deltas per unique (from, to) pair.

function reduceErc20BalanceDeltas(address token, ForkId calldata fork)
    external
    view
    returns (Erc20TransferData[] memory deltas);

Parameters

NameTypeDescription
tokenaddressThe ERC20 token address.
forkForkIdThe fork to query.

Returns

NameTypeDescription
deltasErc20TransferData[]Aggregated transfer records in first-seen pair order.

getLogs

Get all logs emitted during the transaction

Returns logs in emission order

function getLogs() external returns (Log[] memory logs);

Returns

NameTypeDescription
logsLog[]Array of Log structs containing all emitted events

getAllCallInputs

Get all call inputs for a target and selector (all call types)

Includes CALL, STATICCALL, DELEGATECALL, and CALLCODE

function getAllCallInputs(address target, bytes4 selector) external view returns (CallInputs[] memory calls);

Parameters

NameTypeDescription
targetaddressThe target contract address
selectorbytes4The function selector to filter by

Returns

NameTypeDescription
callsCallInputs[]Array of CallInputs matching the criteria

getCallInputs

Get call inputs for regular CALL opcode only

function getCallInputs(address target, bytes4 selector) external view returns (CallInputs[] memory calls);

Parameters

NameTypeDescription
targetaddressThe target contract address
selectorbytes4The function selector to filter by

Returns

NameTypeDescription
callsCallInputs[]Array of CallInputs from CALL opcodes

getStaticCallInputs

Get call inputs for STATICCALL opcode only

function getStaticCallInputs(address target, bytes4 selector) external view returns (CallInputs[] memory calls);

Parameters

NameTypeDescription
targetaddressThe target contract address
selectorbytes4The function selector to filter by

Returns

NameTypeDescription
callsCallInputs[]Array of CallInputs from STATICCALL opcodes

getDelegateCallInputs

Get call inputs for DELEGATECALL opcode only

function getDelegateCallInputs(address target, bytes4 selector) external view returns (CallInputs[] memory calls);

Parameters

NameTypeDescription
targetaddressThe target/proxy contract address
selectorbytes4The function selector to filter by

Returns

NameTypeDescription
callsCallInputs[]Array of CallInputs from DELEGATECALL opcodes

getCallCodeInputs

Get call inputs for CALLCODE opcode only

function getCallCodeInputs(address target, bytes4 selector) external view returns (CallInputs[] memory calls);

Parameters

NameTypeDescription
targetaddressThe target contract address
selectorbytes4The function selector to filter by

Returns

NameTypeDescription
callsCallInputs[]Array of CallInputs from CALLCODE opcodes

callOutputAt

Returns the raw return or revert bytes for a traced call.

function callOutputAt(uint256 callId) external view returns (bytes memory output);

Parameters

NameTypeDescription
callIduint256The call identifier from CallInputs.id.

Returns

NameTypeDescription
outputbytesThe raw ABI-encoded return bytes or revert bytes.

callinputAt

Returns the calldata of a specific call.

function callinputAt(uint256 callId) external view returns (bytes memory input);

Parameters

NameTypeDescription
callIduint256The call ID to read input from.

Returns

NameTypeDescription
inputbytesThe raw calldata bytes (selector + ABI-encoded arguments).

getStateChanges

Get all state changes for a specific storage slot

Returns the sequence of values the slot held during transaction execution

function getStateChanges(address contractAddress, bytes32 slot)
    external
    view
    returns (bytes32[] memory stateChanges);

Parameters

NameTypeDescription
contractAddressaddressThe contract whose storage to inspect
slotbytes32The storage slot to get changes for

Returns

NameTypeDescription
stateChangesbytes32[]Array of values the slot held (in order of changes)

forbidChangeForSlot

Checks that a single storage slot on the assertion adopter was not modified.

function forbidChangeForSlot(bytes32 slot) external returns (bool ok);

Parameters

NameTypeDescription
slotbytes32The slot to protect.

Returns

NameTypeDescription
okboolTrue when the slot was not written during the transaction.

forbidChangeForSlots

Checks that none of the given storage slots on the assertion adopter were modified.

function forbidChangeForSlots(bytes32[] calldata slots) external returns (bool ok);

Parameters

NameTypeDescription
slotsbytes32[]The slots to protect.

Returns

NameTypeDescription
okboolTrue when none of the slots were written during the transaction.

getAssertionAdopter

Get the assertion adopter address for the current transaction

The adopter is the contract that registered the assertion

function getAssertionAdopter() external view returns (address);

Returns

NameTypeDescription
<none>addressThe address of the assertion adopter contract

getTxObject

Get the original transaction object that triggered the assertion

Returns the transaction envelope data for the assertion-triggering tx

function getTxObject() external view returns (TxObject memory txObject);

Returns

NameTypeDescription
txObjectTxObjectThe transaction data struct

context

Returns the context for the current onFnCall trigger invocation.

Only valid inside an assertion function triggered by registerFnCallTrigger. Reverts if called outside of an onFnCall-triggered assertion.

function context() external view returns (TriggerContext memory);

matchingCalls

Returns calls matching the given target, selector, and filter criteria.

function matchingCalls(address target, bytes4 selector, CallFilter calldata filter, uint256 limit)
    external
    view
    returns (TriggerCall[] memory calls);

Parameters

NameTypeDescription
targetaddressThe target contract address.
selectorbytes4The function selector to filter by.
filterCallFilterFiltering criteria (call type, depth, success).
limituint256Maximum number of results to return.

Returns

NameTypeDescription
callsTriggerCall[]Array of matching call records.

getLogsForCall

Returns logs emitted during a specific call frame.

function getLogsForCall(LogQuery calldata query, uint256 callId) external view returns (Log[] memory logs);

Parameters

NameTypeDescription
queryLogQueryThe emitter and signature filters to apply.
callIduint256The call ID to scope the log query to.

Returns

NameTypeDescription
logsLog[]Array of logs emitted during the call.

store

Write a bytes32 value to persistent assertion storage.

function store(bytes32 key, bytes32 value) external;

Parameters

NameTypeDescription
keybytes32The storage key.
valuebytes32The value to store.

load

Read a bytes32 value from persistent assertion storage.

function load(bytes32 key) external view returns (bytes32 value);

Parameters

NameTypeDescription
keybytes32The storage key.

Returns

NameTypeDescription
valuebytes32The stored value.

exists

Check if a key exists in persistent assertion storage.

function exists(bytes32 key) external view returns (bool doesExist);

Parameters

NameTypeDescription
keybytes32The storage key.

Returns

NameTypeDescription
doesExistboolTrue if the key has been written to.

values_left

Returns remaining storage slots available to this assertion.

function values_left() external view returns (uint256 remaining);

changedMappingKeys

Returns canonical Solidity key encodings h(key) for keys whose mapping entry at baseSlot was written during the tx.

Best-effort heuristic: traces KECCAK256 -> SSTORE provenance in the execution trace. Custom inline assembly or precomputed hashed slots can bypass the visible keccak chain and produce false negatives.

function changedMappingKeys(address target, bytes32 baseSlot) external view returns (bytes[] memory keys);

Parameters

NameTypeDescription
targetaddressThe contract whose storage was modified.
baseSlotbytes32The Solidity mapping’s base storage slot.

Returns

NameTypeDescription
keysbytes[]Array of encoded keys (each is the h(key) preimage).

mappingValueDiff

Returns the pre/post values for a specific mapping entry.

Computes slot = keccak256(key ++ baseSlot) + fieldOffset, then reads pre from the PreTx fork and post from the PostTx fork.

function mappingValueDiff(address target, bytes32 baseSlot, bytes calldata key, uint256 fieldOffset)
    external
    view
    returns (bytes32 pre, bytes32 post, bool changed);

Parameters

NameTypeDescription
targetaddressThe contract address.
baseSlotbytes32The mapping’s base slot.
keybytesThe canonical encoding h(key) of the mapping key.
fieldOffsetuint256Struct field offset (0 for the first slot of the value).

Returns

NameTypeDescription
prebytes32The PreTx value.
postbytes32The PostTx value.
changedboolTrue if pre != post.

assetsMatchSharePrice

Checks ERC4626 share price consistency across all fork points.

function assetsMatchSharePrice(address vault, uint256 toleranceBps) external returns (bool);

Parameters

NameTypeDescription
vaultaddressThe ERC4626 vault address.
toleranceBpsuint256Maximum allowed deviation in basis points.

Returns

NameTypeDescription
<none>boolTrue if share price stays within tolerance at all forks.

assetsMatchSharePriceAt

Checks ERC4626 share price consistency between two specific forks.

function assetsMatchSharePriceAt(address vault, uint256 toleranceBps, ForkId calldata fork0, ForkId calldata fork1)
    external
    returns (bool);

Parameters

NameTypeDescription
vaultaddressThe ERC4626 vault address.
toleranceBpsuint256Maximum allowed deviation in basis points.
fork0ForkIdThe baseline fork.
fork1ForkIdThe comparison fork.

Returns

NameTypeDescription
<none>boolTrue if share price stays within tolerance.

conserveBalance

Checks that an account’s ERC20 balance is unchanged between two forks.

function conserveBalance(ForkId calldata fork0, ForkId calldata fork1, address token, address account)
    external
    returns (bool);

Parameters

NameTypeDescription
fork0ForkIdThe baseline fork.
fork1ForkIdThe comparison fork.
tokenaddressThe ERC20 token address.
accountaddressThe account whose balance should remain unchanged.

Returns

NameTypeDescription
<none>boolTrue if balanceOf(account) is identical at both forks.

outflowContext

Returns context about the outflow that triggered this assertion.

Only valid inside an assertion function triggered by watchCumulativeOutflow. Returns a zeroed struct if called from a non-outflow trigger context.

function outflowContext() external view returns (OutflowContext memory ctx);

Returns

NameTypeDescription
ctxOutflowContextThe outflow context for the current trigger invocation.

inflowContext

Returns context about the inflow that triggered this assertion.

Only valid inside an assertion function triggered by watchCumulativeInflow. Returns a zeroed struct if called from a non-inflow trigger context.

function inflowContext() external view returns (InflowContext memory ctx);

Returns

NameTypeDescription
ctxInflowContextThe inflow context for the current trigger invocation.

oracleSanity

Checks oracle price consistency across all fork points.

function oracleSanity(address target, bytes calldata data, uint256 bpsDeviation) external returns (bool);

Parameters

NameTypeDescription
targetaddressThe oracle contract address.
databytesThe ABI-encoded oracle query.
bpsDeviationuint256Maximum allowed deviation in basis points.

Returns

NameTypeDescription
<none>boolTrue if oracle price stays within tolerance.

oracleSanityAt

Checks oracle price consistency between two specific forks.

function oracleSanityAt(
    address target,
    bytes calldata data,
    uint256 bpsDeviation,
    ForkId calldata initialFork,
    ForkId calldata currentFork
) external returns (bool);

Parameters

NameTypeDescription
targetaddressThe oracle contract address.
databytesThe ABI-encoded oracle query.
bpsDeviationuint256Maximum allowed deviation in basis points.
initialForkForkIdThe baseline fork.
currentForkForkIdThe comparison fork.

Returns

NameTypeDescription
<none>boolTrue if oracle price stays within tolerance.

mulDivDown

Computes (x * y) / denominator, rounded down. Uses 512-bit intermediates.

function mulDivDown(uint256 x, uint256 y, uint256 denominator) external pure returns (uint256 result);

mulDivUp

Computes (x * y) / denominator, rounded up. Uses 512-bit intermediates.

function mulDivUp(uint256 x, uint256 y, uint256 denominator) external pure returns (uint256 result);

normalizeDecimals

Scales an amount from one decimal base to another.

function normalizeDecimals(uint256 amount, uint8 fromDecimals, uint8 toDecimals)
    external
    pure
    returns (uint256 result);

ratioGe

Compares two ratios with tolerance: num1/den1 >= num2/den2 * (1 - toleranceBps/10000).

Uses cross-multiplication with wide intermediates to avoid division and overflow.

function ratioGe(uint256 num1, uint256 den1, uint256 num2, uint256 den2, uint256 toleranceBps)
    external
    pure
    returns (bool);

Structs

Log

Represents an Ethereum log emitted during transaction execution

Used by getLogs() to return transaction logs for inspection

struct Log {
    /// @notice The topics of the log, including the event signature if any
    bytes32[] topics;
    /// @notice The raw ABI-encoded data of the log
    bytes data;
    /// @notice The address of the contract that emitted the log
    address emitter;
}

LogQuery

Query used to filter transaction logs by emitter and/or signature

struct LogQuery {
    /// @notice address(0) matches any emitter
    address emitter;
    /// @notice bytes32(0) matches any topic0 signature
    bytes32 signature;
}

CallInputs

Represents the inputs to a call made during transaction execution

Used by getCallInputs() and related functions to inspect call details

struct CallInputs {
    /// @notice The calldata of the call
    bytes input;
    /// @notice The gas limit of the call
    uint64 gas_limit;
    /// @notice The address of the bytecode being executed (code address)
    address bytecode_address;
    /// @notice The target address whose storage may be modified
    address target_address;
    /// @notice The address that initiated this call
    address caller;
    /// @notice The ETH value sent with the call
    uint256 value;
    /// @notice Unique identifier for this call, used with forkPreCall/forkPostCall
    uint256 id;
}

TxObject

Contains data about the original assertion-triggering transaction

Provides access to transaction envelope data for inspection in assertions

struct TxObject {
    /// @notice The address that initiated the transaction (tx.origin equivalent)
    address from;
    /// @notice The transaction recipient, or address(0) for contract creation
    address to;
    /// @notice The ETH value sent with the transaction
    uint256 value;
    /// @notice The chain ID, or 0 if not present
    uint64 chain_id;
    /// @notice The gas limit for the transaction
    uint64 gas_limit;
    /// @notice The gas price or max_fee_per_gas for EIP-1559 transactions
    uint128 gas_price;
    /// @notice The transaction calldata
    bytes input;
}

StaticCallResult

Result of a nested static call executed against a snapshot.

struct StaticCallResult {
    /// @notice Whether the nested call completed successfully
    bool ok;
    /// @notice Raw return data or revert data from the nested call
    bytes data;
}

Erc20TransferData

Decoded ERC20 Transfer event data from a snapshot fork.

struct Erc20TransferData {
    /// @notice The token contract that emitted the Transfer event
    address token_addr;
    /// @notice The sender indexed in topic1
    address from;
    /// @notice The receiver indexed in topic2
    address to;
    /// @notice The transferred amount decoded from log data
    uint256 value;
}

ForkId

Identifies a read-only transaction snapshot.

forkType: 0 = PreTx, 1 = PostTx, 2 = PreCall, 3 = PostCall callIndex is used only for call-scoped snapshots.

struct ForkId {
    uint8 forkType;
    uint256 callIndex;
}

TriggerContext

Context for an onFnCall-triggered assertion invocation.

Only valid inside an assertion function triggered by registerFnCallTrigger.

struct TriggerContext {
    /// @notice The function selector that was called on the adopter
    bytes4 selector;
    /// @notice Call index for constructing PreCall ForkId
    uint256 callStart;
    /// @notice Call index for constructing PostCall ForkId
    uint256 callEnd;
}

CallFilter

Filter criteria for matchingCalls queries.

struct CallFilter {
    /// @notice Call type: 0 = any, 1 = CALL, 2 = STATICCALL, 3 = DELEGATECALL, 4 = CALLCODE
    uint8 callType;
    /// @notice Minimum call depth to include
    uint32 minDepth;
    /// @notice Maximum call depth to include
    uint32 maxDepth;
    /// @notice If true, only return top-level calls (depth == 1)
    bool topLevelOnly;
    /// @notice If true, only return calls that succeeded
    bool successOnly;
}

TriggerCall

Detailed record of a call in the transaction trace.

struct TriggerCall {
    uint256 callId;
    uint256 parentCallId;
    address caller;
    address target;
    address codeAddress;
    bytes4 selector;
    uint32 depth;
    uint8 callType;
    bool success;
    uint256 value;
    bytes input;
}

OutflowContext

Context about the outflow that triggered an assertion via watchCumulativeOutflow.

Only valid inside an assertion function triggered by watchCumulativeOutflow. Returns a zeroed struct if called from a non-outflow trigger context.

struct OutflowContext {
    /// @notice The ERC20 token that breached the threshold
    address token;
    /// @notice Net outflow within the window (token units)
    uint256 cumulativeOutflow;
    /// @notice Total absolute outflow within the window (token units, ignoring deposits)
    uint256 absoluteOutflow;
    /// @notice Current outflow as basis points of TVL snapshot
    uint256 currentBps;
    /// @notice Adopter's token balance at window start
    uint256 tvlSnapshot;
    /// @notice Timestamp when the current window began
    uint256 windowStart;
    /// @notice Timestamp when the current window expires
    uint256 windowEnd;
}

InflowContext

Context about the inflow that triggered an assertion via watchCumulativeInflow.

Only valid inside an assertion function triggered by watchCumulativeInflow. Returns a zeroed struct if called from a non-inflow trigger context.

struct InflowContext {
    /// @notice The ERC20 token that breached the threshold
    address token;
    /// @notice Net inflow within the window (token units)
    uint256 cumulativeInflow;
    /// @notice Total absolute inflow within the window (token units, ignoring withdrawals)
    uint256 absoluteInflow;
    /// @notice Current inflow as basis points of TVL snapshot
    uint256 currentBps;
    /// @notice Adopter's token balance at window start
    uint256 tvlSnapshot;
    /// @notice Timestamp when the current window began
    uint256 windowStart;
    /// @notice Timestamp when the current window expires
    uint256 windowEnd;
}

AssertionSpec

Git Source

The assertion spec defines what subset of precompiles are available. All new specs derive and expose all precompiles from the old definitions, unless specified otherwise.

enum AssertionSpec {
/// @notice Standard set of PhEvm precompiles available at launch.
Legacy,
/// @notice Contains tx object precompiles.
Reshiram,
/// @notice Unrestricted access to all available precompiles. May be untested and dangerous.
Experimental
}

SpecRecorder

Git Source

Title: SpecRecorder

Author: Phylax Systems

Precompile interface for registering the desired assertion spec

Used within the constructor of assertion contracts to specify which subset of PhEvm precompiles should be available during assertion execution. You can only call registerAssertionSpec once per assertion.

Functions

registerAssertionSpec

Called within the constructor to set the desired assertion spec. The assertion spec defines what subset of precompiles are available. You can only call this function once. For an assertion to be valid, it needs to have a defined spec.

function registerAssertionSpec(AssertionSpec spec) external view;

Parameters

NameTypeDescription
specAssertionSpecThe desired AssertionSpec.

StateChanges

Git Source

Inherits: Credible

Title: StateChanges

Helper contract for converting state changes from bytes32 arrays to typed arrays

Inherits from Credible to access the PhEvm interface

Functions

getStateChangesUint

Converts state changes for a slot to uint256 array

function getStateChangesUint(address contractAddress, bytes32 slot) internal view returns (uint256[] memory);

Parameters

NameTypeDescription
contractAddressaddressThe address of the contract to get state changes from
slotbytes32The storage slot to get state changes for

Returns

NameTypeDescription
<none>uint256[]Array of state changes as uint256 values

getStateChangesAddress

Converts state changes for a slot to address array

function getStateChangesAddress(address contractAddress, bytes32 slot) internal view returns (address[] memory);

Parameters

NameTypeDescription
contractAddressaddressThe address of the contract to get state changes from
slotbytes32The storage slot to get state changes for

Returns

NameTypeDescription
<none>address[]Array of state changes as address values

getStateChangesBool

Converts state changes for a slot to boolean array

function getStateChangesBool(address contractAddress, bytes32 slot) internal view returns (bool[] memory);

Parameters

NameTypeDescription
contractAddressaddressThe address of the contract to get state changes from
slotbytes32The storage slot to get state changes for

Returns

NameTypeDescription
<none>bool[]Array of state changes as boolean values

getStateChangesBytes32

Gets raw state changes as bytes32 array

function getStateChangesBytes32(address contractAddress, bytes32 slot) internal view returns (bytes32[] memory);

Parameters

NameTypeDescription
contractAddressaddressThe address of the contract to get state changes from
slotbytes32The storage slot to get state changes for

Returns

NameTypeDescription
<none>bytes32[]Array of state changes as bytes32 values

getSlotMapping

Calculates the storage slot for a mapping with a given key and offset

function getSlotMapping(bytes32 slot, uint256 key, uint256 offset) private pure returns (bytes32);

Parameters

NameTypeDescription
slotbytes32The base storage slot of the mapping
keyuint256The key in the mapping
offsetuint256Additional offset to add to the calculated slot

Returns

NameTypeDescription
<none>bytes32The storage slot for the mapping entry

getStateChangesUint

Gets uint256 state changes for a mapping entry

function getStateChangesUint(address contractAddress, bytes32 slot, uint256 key)
    internal
    view
    returns (uint256[] memory);

Parameters

NameTypeDescription
contractAddressaddressThe contract address
slotbytes32The mapping’s slot
keyuint256The mapping key

Returns

NameTypeDescription
<none>uint256[]Array of state changes as uint256 values

getStateChangesAddress

Gets address state changes for a mapping entry

function getStateChangesAddress(address contractAddress, bytes32 slot, uint256 key)
    internal
    view
    returns (address[] memory);

Parameters

NameTypeDescription
contractAddressaddressThe contract address
slotbytes32The mapping’s slot
keyuint256The mapping key

Returns

NameTypeDescription
<none>address[]Array of state changes as address values

getStateChangesBool

Gets boolean state changes for a mapping entry

function getStateChangesBool(address contractAddress, bytes32 slot, uint256 key)
    internal
    view
    returns (bool[] memory);

Parameters

NameTypeDescription
contractAddressaddressThe contract address
slotbytes32The mapping’s slot
keyuint256The mapping key

Returns

NameTypeDescription
<none>bool[]Array of state changes as boolean values

getStateChangesBytes32

Gets bytes32 state changes for a mapping entry

function getStateChangesBytes32(address contractAddress, bytes32 slot, uint256 key)
    internal
    view
    returns (bytes32[] memory);

Parameters

NameTypeDescription
contractAddressaddressThe contract address
slotbytes32The mapping’s slot
keyuint256The mapping key

Returns

NameTypeDescription
<none>bytes32[]Array of state changes as bytes32 values

getStateChangesUint

Gets uint256 state changes for a mapping entry with offset

function getStateChangesUint(address contractAddress, bytes32 slot, uint256 key, uint256 slotOffset)
    internal
    view
    returns (uint256[] memory);

Parameters

NameTypeDescription
contractAddressaddressThe contract address
slotbytes32The mapping’s slot
keyuint256The mapping key
slotOffsetuint256Additional offset to add to the slot

Returns

NameTypeDescription
<none>uint256[]Array of state changes as uint256 values

getStateChangesAddress

Gets address state changes for a mapping entry with offset

function getStateChangesAddress(address contractAddress, bytes32 slot, uint256 key, uint256 slotOffset)
    internal
    view
    returns (address[] memory);

Parameters

NameTypeDescription
contractAddressaddressThe contract address
slotbytes32The mapping’s slot
keyuint256The mapping key
slotOffsetuint256Additional offset to add to the slot

Returns

NameTypeDescription
<none>address[]Array of state changes as address values

getStateChangesBool

Gets boolean state changes for a mapping entry with offset

function getStateChangesBool(address contractAddress, bytes32 slot, uint256 key, uint256 slotOffset)
    internal
    view
    returns (bool[] memory);

Parameters

NameTypeDescription
contractAddressaddressThe contract address
slotbytes32The mapping’s slot
keyuint256The mapping key
slotOffsetuint256Additional offset to add to the slot

Returns

NameTypeDescription
<none>bool[]Array of state changes as boolean values

getStateChangesBytes32

Gets bytes32 state changes for a mapping entry with offset

function getStateChangesBytes32(address contractAddress, bytes32 slot, uint256 key, uint256 slotOffset)
    internal
    view
    returns (bytes32[] memory);

Parameters

NameTypeDescription
contractAddressaddressThe contract address
slotbytes32The mapping’s slot
keyuint256The mapping key
slotOffsetuint256Additional offset to add to the slot

Returns

NameTypeDescription
<none>bytes32[]Array of state changes as bytes32 values

TriggerRecorder

Git Source

Title: TriggerRecorder

Author: Phylax Systems

Precompile interface for registering assertion triggers

Used within the triggers() function of assertion contracts to specify when assertions should be executed. Supports call triggers, storage change triggers, and balance change triggers.

Functions

registerStorageChangeTrigger

Registers storage change trigger for all slots

function registerStorageChangeTrigger(bytes4 fnSelector) external view;

Parameters

NameTypeDescription
fnSelectorbytes4The function selector of the assertion function.

registerStorageChangeTrigger

Registers storage change trigger for a slot

function registerStorageChangeTrigger(bytes4 fnSelector, bytes32 slot) external view;

Parameters

NameTypeDescription
fnSelectorbytes4The function selector of the assertion function.
slotbytes32The storage slot to trigger on.

registerBalanceChangeTrigger

Registers balance change trigger for the AA

function registerBalanceChangeTrigger(bytes4 fnSelector) external view;

Parameters

NameTypeDescription
fnSelectorbytes4The function selector of the assertion function.

registerCallTrigger

Registers a call trigger for calls to the AA.

function registerCallTrigger(bytes4 fnSelector, bytes4 triggerSelector) external view;

Parameters

NameTypeDescription
fnSelectorbytes4The function selector of the assertion function.
triggerSelectorbytes4The function selector of the trigger function.

registerCallTrigger

Records a call trigger for the specified assertion function. A call trigger signifies that the assertion function should be called if the assertion adopter is called.

function registerCallTrigger(bytes4 fnSelector) external view;

Parameters

NameTypeDescription
fnSelectorbytes4The function selector of the assertion function.

registerFnCallTrigger

Registers a trigger that fires when the adopter receives a call matching triggerSelector. The assertion fires once per matching call, with TriggerContext available via ph.context().

function registerFnCallTrigger(bytes4 fnSelector, bytes4 triggerSelector) external view;

Parameters

NameTypeDescription
fnSelectorbytes4The assertion function to invoke.
triggerSelectorbytes4The 4-byte selector on the adopter to watch for.

registerTxEndTrigger

Registers a trigger that fires once after the entire transaction completes.

function registerTxEndTrigger(bytes4 fnSelector) external view;

Parameters

NameTypeDescription
fnSelectorbytes4The assertion function to invoke.

registerErc20ChangeTrigger

Registers a trigger that fires when a token’s balances change.

function registerErc20ChangeTrigger(bytes4 fnSelector, address token) external view;

Parameters

NameTypeDescription
fnSelectorbytes4The assertion function to invoke.
tokenaddressThe ERC20 token address to watch.

watchCumulativeOutflow

Registers a circuit breaker trigger that fires when cumulative ERC20 outflow from the assertion adopter exceeds a percentage threshold within a rolling time window.

The executor handles all persistent state tracking, TVL snapshots, and threshold enforcement internally.

function watchCumulativeOutflow(address token, uint256 thresholdBps, uint256 windowDuration, bytes4 fnSelector)
    external
    view;

Parameters

NameTypeDescription
tokenaddressThe ERC20 token address to monitor.
thresholdBpsuint256Maximum cumulative outflow as basis points of the TVL snapshot taken at window start. 1000 = 10%.
windowDurationuint256Rolling window length in seconds. Balance deltas are stored in 10-second buckets; old buckets that fall outside the window are dropped as the window slides forward.
fnSelectorbytes4The assertion function to invoke when the threshold is breached.

watchCumulativeInflow

Registers a circuit breaker trigger that fires when cumulative ERC20 inflow into the assertion adopter exceeds a percentage threshold within a rolling time window.

The executor handles all persistent state tracking, TVL snapshots, and threshold enforcement internally.

function watchCumulativeInflow(address token, uint256 thresholdBps, uint256 windowDuration, bytes4 fnSelector)
    external
    view;

Parameters

NameTypeDescription
tokenaddressThe ERC20 token address to monitor.
thresholdBpsuint256Maximum cumulative inflow as basis points of the TVL snapshot taken at window start. 1000 = 10%.
windowDurationuint256Rolling window length in seconds. Balance deltas are stored in 10-second buckets; old buckets that fall outside the window are dropped as the window slides forward.
fnSelectorbytes4The assertion function to invoke when the threshold is breached.