Pre-release — The API surface may change. Unaudited.

Programmable Calldata Policy Engine

Define type-safe constraints on ABI-encoded data. Enforce them onchain in Solidity, or offchain in TypeScript.

a policy is just canonical byteshover or tap a field
01095ea7b300040102401f0100020000007200490101000007004000000000000000000000000011111111111111111111111111111111111111110000000000000000000000002222222222222222222222222222222222222222002901010001050020000000000000000000000000000000000000000000000000000000e8d4a51000

One spec, two implementations

The policy format is a specification with two independent implementations, a Solidity library and a TypeScript SDK. Reach for whichever your scenario needs: embed the engine in your contracts for dynamic onchain rules, or check payloads in TypeScript before they’re signed. Use one, the other, or both.

Solidity library

Dynamic guardrails in your contracts

// 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();

// reverts on a violation
PolicyEnforcer.enforce(policy, msg.data);

TypeScript SDK

Check payloads before signing

// function approve(address spender, uint256 amount)
const policy = PolicyBuilder
    .create("approve(address,uint256)")
    .add(arg(0).isIn(trustedSpenders))       // spender
    .add(arg(1).lte(1_000_000n * 10n ** 6n)) // amount
    .build();

// throws on a violation
PolicyEnforcer.enforce(policy, calldata);

Both implementations also expose check, which returns a result instead of reverting or throwing.

Express any constraint

Scalar arguments, nested struct fields, array elements, transaction context, even raw ABI blobs. Compose them with AND/OR logic. Pick a capability.

Set membership, ranges, and comparisons on scalar arguments.

// function withdraw(address to, uint256 amount)
bytes memory policy = PolicyBuilder
    .create("withdraw(address,uint256)")
    .add(arg(0).isIn(allowed))          // to
    .add(arg(1).lte(uint256(1_000e18))) // amount
    .build();

Start building

Install the Solidity library or the TypeScript SDK and write your first policy.