PhEvm
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
| Name | Type | Description |
|---|---|---|
slot | bytes32 | The storage slot to read. |
fork | ForkId | The snapshot fork to read from. |
Returns
| Name | Type | Description |
|---|---|---|
value | bytes32 | The 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
| Name | Type | Description |
|---|---|---|
target | address | The address to read storage from. |
slot | bytes32 | The storage slot to read. |
fork | ForkId | The snapshot fork to read from. |
Returns
| Name | Type | Description |
|---|---|---|
value | bytes32 | The 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
| Name | Type | Description |
|---|---|---|
target | address | The contract to call. |
data | bytes | The ABI-encoded function call. |
gas_limit | uint64 | The gas budget forwarded to the nested static call. |
fork | ForkId | The snapshot fork to execute against. |
Returns
| Name | Type | Description |
|---|---|---|
result | StaticCallResult | Success 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
| Name | Type | Description |
|---|---|---|
query | LogQuery | The emitter and signature filters to apply |
fork | ForkId | The snapshot fork to read logs from |
Returns
| Name | Type | Description |
|---|---|---|
logs | Log[] | 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
| Name | Type | Description |
|---|---|---|
token | address | The ERC20 token address. |
fork | ForkId | The fork to query. |
Returns
| Name | Type | Description |
|---|---|---|
transfers | Erc20TransferData[] | 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
| Name | Type | Description |
|---|---|---|
tokens | address[] | Array of ERC20 token addresses. |
fork | ForkId | The fork to query. |
Returns
| Name | Type | Description |
|---|---|---|
transfers | Erc20TransferData[] | 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
| Name | Type | Description |
|---|---|---|
token | address | The ERC20 token address. |
fork | ForkId | The 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
| Name | Type | Description |
|---|---|---|
token | address | The ERC20 token address. |
fork | ForkId | The fork to query. |
Returns
| Name | Type | Description |
|---|---|---|
deltas | Erc20TransferData[] | 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
| Name | Type | Description |
|---|---|---|
logs | Log[] | 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
| Name | Type | Description |
|---|---|---|
target | address | The target contract address |
selector | bytes4 | The function selector to filter by |
Returns
| Name | Type | Description |
|---|---|---|
calls | CallInputs[] | 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
| Name | Type | Description |
|---|---|---|
target | address | The target contract address |
selector | bytes4 | The function selector to filter by |
Returns
| Name | Type | Description |
|---|---|---|
calls | CallInputs[] | 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
| Name | Type | Description |
|---|---|---|
target | address | The target contract address |
selector | bytes4 | The function selector to filter by |
Returns
| Name | Type | Description |
|---|---|---|
calls | CallInputs[] | 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
| Name | Type | Description |
|---|---|---|
target | address | The target/proxy contract address |
selector | bytes4 | The function selector to filter by |
Returns
| Name | Type | Description |
|---|---|---|
calls | CallInputs[] | 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
| Name | Type | Description |
|---|---|---|
target | address | The target contract address |
selector | bytes4 | The function selector to filter by |
Returns
| Name | Type | Description |
|---|---|---|
calls | CallInputs[] | 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
| Name | Type | Description |
|---|---|---|
callId | uint256 | The call identifier from CallInputs.id. |
Returns
| Name | Type | Description |
|---|---|---|
output | bytes | The 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
| Name | Type | Description |
|---|---|---|
callId | uint256 | The call ID to read input from. |
Returns
| Name | Type | Description |
|---|---|---|
input | bytes | The 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
| Name | Type | Description |
|---|---|---|
contractAddress | address | The contract whose storage to inspect |
slot | bytes32 | The storage slot to get changes for |
Returns
| Name | Type | Description |
|---|---|---|
stateChanges | bytes32[] | 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
| Name | Type | Description |
|---|---|---|
slot | bytes32 | The slot to protect. |
Returns
| Name | Type | Description |
|---|---|---|
ok | bool | True 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
| Name | Type | Description |
|---|---|---|
slots | bytes32[] | The slots to protect. |
Returns
| Name | Type | Description |
|---|---|---|
ok | bool | True 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
| Name | Type | Description |
|---|---|---|
<none> | address | The 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
| Name | Type | Description |
|---|---|---|
txObject | TxObject | The 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
| Name | Type | Description |
|---|---|---|
target | address | The target contract address. |
selector | bytes4 | The function selector to filter by. |
filter | CallFilter | Filtering criteria (call type, depth, success). |
limit | uint256 | Maximum number of results to return. |
Returns
| Name | Type | Description |
|---|---|---|
calls | TriggerCall[] | 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
| Name | Type | Description |
|---|---|---|
query | LogQuery | The emitter and signature filters to apply. |
callId | uint256 | The call ID to scope the log query to. |
Returns
| Name | Type | Description |
|---|---|---|
logs | Log[] | Array of logs emitted during the call. |
store
Write a bytes32 value to persistent assertion storage.
function store(bytes32 key, bytes32 value) external;
Parameters
| Name | Type | Description |
|---|---|---|
key | bytes32 | The storage key. |
value | bytes32 | The value to store. |
load
Read a bytes32 value from persistent assertion storage.
function load(bytes32 key) external view returns (bytes32 value);
Parameters
| Name | Type | Description |
|---|---|---|
key | bytes32 | The storage key. |
Returns
| Name | Type | Description |
|---|---|---|
value | bytes32 | The stored value. |
exists
Check if a key exists in persistent assertion storage.
function exists(bytes32 key) external view returns (bool doesExist);
Parameters
| Name | Type | Description |
|---|---|---|
key | bytes32 | The storage key. |
Returns
| Name | Type | Description |
|---|---|---|
doesExist | bool | True 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
| Name | Type | Description |
|---|---|---|
target | address | The contract whose storage was modified. |
baseSlot | bytes32 | The Solidity mapping’s base storage slot. |
Returns
| Name | Type | Description |
|---|---|---|
keys | bytes[] | 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
| Name | Type | Description |
|---|---|---|
target | address | The contract address. |
baseSlot | bytes32 | The mapping’s base slot. |
key | bytes | The canonical encoding h(key) of the mapping key. |
fieldOffset | uint256 | Struct field offset (0 for the first slot of the value). |
Returns
| Name | Type | Description |
|---|---|---|
pre | bytes32 | The PreTx value. |
post | bytes32 | The PostTx value. |
changed | bool | True if pre != post. |
assetsMatchSharePrice
Checks ERC4626 share price consistency across all fork points.
function assetsMatchSharePrice(address vault, uint256 toleranceBps) external returns (bool);
Parameters
| Name | Type | Description |
|---|---|---|
vault | address | The ERC4626 vault address. |
toleranceBps | uint256 | Maximum allowed deviation in basis points. |
Returns
| Name | Type | Description |
|---|---|---|
<none> | bool | True 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
| Name | Type | Description |
|---|---|---|
vault | address | The ERC4626 vault address. |
toleranceBps | uint256 | Maximum allowed deviation in basis points. |
fork0 | ForkId | The baseline fork. |
fork1 | ForkId | The comparison fork. |
Returns
| Name | Type | Description |
|---|---|---|
<none> | bool | True 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
| Name | Type | Description |
|---|---|---|
fork0 | ForkId | The baseline fork. |
fork1 | ForkId | The comparison fork. |
token | address | The ERC20 token address. |
account | address | The account whose balance should remain unchanged. |
Returns
| Name | Type | Description |
|---|---|---|
<none> | bool | True 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
| Name | Type | Description |
|---|---|---|
ctx | OutflowContext | The 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
| Name | Type | Description |
|---|---|---|
ctx | InflowContext | The 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
| Name | Type | Description |
|---|---|---|
target | address | The oracle contract address. |
data | bytes | The ABI-encoded oracle query. |
bpsDeviation | uint256 | Maximum allowed deviation in basis points. |
Returns
| Name | Type | Description |
|---|---|---|
<none> | bool | True 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
| Name | Type | Description |
|---|---|---|
target | address | The oracle contract address. |
data | bytes | The ABI-encoded oracle query. |
bpsDeviation | uint256 | Maximum allowed deviation in basis points. |
initialFork | ForkId | The baseline fork. |
currentFork | ForkId | The comparison fork. |
Returns
| Name | Type | Description |
|---|---|---|
<none> | bool | True 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;
}