Overview of the cheatcodes made available for the Phylax Credible Layer
Cheatcodes are PhEVM (Phylax EVM) specific instructions implemented in native code instead of EVM bytecode. They can communicate with Internal APIs and support all existing Ethereum cheatcodes up to Dancun, plus new capabilities for:
You may notice the terms “precompiles” and “cheatcodes” used interchangeably in some contexts. We use the term “cheatcodes” as it’s more familiar to Solidity developers who are already using testing frameworks like Foundry/Forge or Hardhat. Both terms refer to native functions that extend the EVM’s capabilities, but “cheatcodes” better reflects their role in the developer experience.
load
Loads a storage slot from an address.
Using forge inspect <ContractName> storage-layout
is an easy way to get the storage layout of a contract.
This can be used to determine the storage slot of a specific variable to use in the cheatcode.
forkPreState
Updates the active fork to the state before the triggering transaction. Useful for:
forkPostState
Updates the active fork to the state after the triggering transaction. Useful for:
getLogs
Retrieves all logs emitted by the latest transaction.
getCallInputs
Gets the call inputs of all the calls made in the current transaction and returns them in an array of CallInputs
structs.
This is a useful precompile to use for intra-transaction assertions such as checking if the price reported by an oracle deviates from an allowed range, which could be a sign of an oracle manipulation.
Internal calls are not actual EVM calls but rather a Solidity language feature. They are not traced by the CallTracer and will not result in CallInputs
or trigger call-based assertions. However, using the this
keyword (e.g., this.functionName()
) creates an external call that will be traced and can trigger assertions.
Example:
getStateChanges
Returns state changes for a contract’s storage slot within the current call stack.
Using forge inspect <ContractName> storage-layout
is an easy way to get the storage layout of a contract.
This can be used to determine the storage slot of a specific variable to use in the cheatcode.
The array returned includes the initial value of the slot as the first element, so the length of the array is either 0 or >= 2.
The following helpers convert state changes to specific types. Each has three variants:
getStateChangesUint
Gets state changes for a storage slot as uint256 values.
Similar helper functions exist for:
getStateChangesAddress
: Convert to address valuesgetStateChangesBool
: Convert to boolean valuesgetStateChangesBytes32
: Get raw bytes32 valuesEach of these functions follows the same pattern with basic, mapping, and mapping-with-offset variants.
Triggers determine when your assertion functions will be executed. You can register
different types of triggers in your assertion’s triggers()
function.
Use triggers to make sure that assertions are only called when they are needed in order to save gas and resources. For example, instead of triggering an assertion on every call to a contract, you can trigger it only on specific function calls that are able to change the state of the specific value you are asserting on.
Call triggers execute your assertion when specific contract calls occur.
Example:
Storage triggers execute your assertion when contract storage changes.
Using forge inspect <ContractName> storage-layout
is an easy way to get the storage layout of a contract.
This can be used to determine the storage slot of a specific variable to use in the cheatcode.
Example:
Executes assertion on ETH balance changes.
Triggers can be combined for comprehensive coverage:
getAssertionAdopter
Get assertion adopter contract address associated with the assertion triggering transaction.
This cheat code allows for not defining an assertion adopter contract in the assertion contract constructor.
The cheat code is only available in the triggers()
function and the assertion functions.
It cannot be used in the constructor since assertion contracts have no state during deployment.