ABI Integration
Import and use external ABIs for type-safe contract interactions.
Matador's type system is extensible through standard Ethereum ABI (Application Binary Interface) files. Importing an ABI allows the compiler to validate function calls, decoding paths, and parameter types at compile time.
Importing ABIs
Use the import keyword to load a JSON ABI file and assign it an alias. This alias becomes a namespace for accessing the contract's functions and events.
import "abis/UniswapV3Router.json" as Uniswap;
import "abis/ERC20.json" as Token;Path Resolution
The compiler supports flexible path resolution strategies to suit different project structures.
Paths starting with ./ or ../ are resolved relative to the location of the .matador policy file.
// Policy is in /policies/swap.matador
// ABI is in /policies/abis/Router.json
import "./abis/Router.json" as Router;Absolute paths are resolved from the root of the filesystem. Use with caution as this reduces portability.
import "/usr/local/project/abis/Router.json" as Router;If no prefix is provided, paths are resolved relative to the compiler's current working directory (usually the project root).
// Run compiler from project root
import "src/abis/Router.json" as Router;Capabilities
Importing an ABI unlocks three powerful capabilities in your policies.
Calldata Inspection
Validate incoming transaction data against specific function signatures. The compiler automatically handles selector matching and decoding.
// Checks if the transaction is a call to 'transfer'
// AND if the recipient matches the parameter
Token.transfer(recipient: parameters.allowedRecipient)State Variable Checks
Read public state variables from external contracts. This compiles to a STATE_VARIABLE_CHECK opcode.
// Ensure the pool has enough liquidity
Pool.liquidity() > 1000000View Functions Only
The referenced function must be marked as view or pure in the ABI. Mutable functions cannot be called during validation.
Type Definitions
Use the ABI alias as a type annotation for parameters. This ensures that the parameter passed at runtime is treated as that specific contract type.
parameters: {
// 'router' must be an address that adheres to the Uniswap ABI
router: Uniswap
}Deep Nested Access
Matador supports accessing deeply nested fields within struct parameters or arrays in calldata.
For example, given a function exactInputSingle that takes a ExactInputSingleParams struct:
struct ExactInputSingleParams {
address tokenIn;
address tokenOut;
uint24 fee;
address recipient;
uint256 amountIn;
uint256 amountOutMinimum;
uint160 sqrtPriceLimitX96;
}You can write a policy that enforces rules on specific fields of that struct:
when: {
all {
// Check the function selector
Uniswap.exactInputSingle,
// Enforce the recipient is the sender (no sweeping to others)
context.args.params.recipient == context.caller,
// Enforce a minimum output amount
context.args.params.amountOutMinimum >= parameters.minOut
}
}Best Practices
Maintain a dedicated ABI directory
Keep all your JSON ABIs in a single abis/ or interfaces/ directory at the root of your project. This makes relative imports consistent across multiple policy files.
- Strip Unused Artifacts: Use "human-readable" ABIs or minimal JSON files containing only the functions you need. Full Foundry/Hardhat artifacts are supported but can be large.
- Version Control: Commit your ABIs to git alongside your policies to ensure reproducible builds.
- Use Aliases: Pick short, descriptive aliases (e.g.,
Aaveinstead ofAavePoolV3Helper) to keep your policy logic readable.