Programmable Calldata Validation Engine
Define type-safe constraints on ABI-encoded data.Update validation rules without redeploying contracts.
Get StartedBuild policies with a fluent Solidity API
// function approve(address spender, uint256 amount)
bytes memory policy = PolicyBuilder
.create("approve(address,uint256)")
.add(arg(0).isIn(trustedSpenders)) // spender
.add(arg(1).lte(uint256(1_000_000e6))) // amount
.build();// struct SwapParams { address tokenIn; address tokenOut; uint256 amount; }
// function swap(SwapParams params)
bytes memory policy = PolicyBuilder
.create("swap((address,address,uint256))")
.add(arg(0, 0).notIn(sanctioned)) // params.tokenIn
.add(arg(0, 1).notIn(sanctioned)) // params.tokenOut
.add(arg(0, 2).gt(uint256(0))) // params.amount
.build();// struct Transaction { address to; uint256 value; }
// function multiSend(Transaction[] calls)
bytes memory policy = PolicyBuilder
.create("multiSend((address,uint256)[])")
.add(arg(0).lengthBetween(1, 50)) // calls.length
.add(arg(0, Path.ALL, 0).notIn(sanctioned)) // calls[*].to
.add(arg(0, Path.ALL, 1).lte(uint256(1e18))) // calls[*].value
.build();// function transfer(address to, uint256 amount)
bytes memory policy = PolicyBuilder
.create("transfer(address,uint256)")
.add(msgSender().isIn(operators)) // caller
.add(arg(0).notIn(sanctioned)) // to
.add(arg(1).lte(uint256(100e18))) // amount
.build();// function supply(address asset, uint256 amount)
bytes memory policy = PolicyBuilder
.create("supply(address,uint256)")
.add(msgSender().eq(OPERATOR)) // caller
.or()
.add(arg(0).isIn(allowedAssets)) // asset
.build();