Skip to main content
Note: see the language section for more details.

Allow ABI-specific contract call parameters

For contract interactions, use Smart Contract Interfaces (ABI upload) rather than raw calldata slicing. ABI-based policies use named arguments (eth.tx.contract_call_args['arg_name']) instead of byte offsets — they’re more readable, less error-prone, and won’t silently break if the contract encoding changes. Raw eth.tx.data[...] slicing is a fallback for contracts where no ABI is available. Restrict a transfer call to a maximum amount and a specific recipient:
{
  "policyName": "Limit WETH transfers",
  "effect": "EFFECT_ALLOW",
  "condition": "eth.tx.contract_call_args['wad'] < 1000000000000000000 && eth.tx.contract_call_args['dst'] == '0x08d2b0a37F869FF76BACB5Bab3278E26ab7067B7'"
}
Restrict by function name or selector (also requires an ABI upload):
{
  "policyName": "Allow only transfer calls to a contract",
  "effect": "EFFECT_ALLOW",
  "condition": "eth.tx.to == '<CONTRACT_ADDRESS>' && eth.tx.function_name == 'transfer'"
}
See Smart Contract Interfaces for the full upload walkthrough and Solana IDL support.

Allow ERC-20 transfers for a specific token smart contract (raw calldata fallback)

Use this pattern only when an ABI is unavailable. The selector 0xa9059cbb is the 4-byte keccak256 hash of transfer(address,uint256).
{
  "policyName": "Enable ERC-20 transfers for <CONTRACT_ADDRESS>",
  "effect": "EFFECT_ALLOW",
  "condition": "eth.tx.to == '<CONTRACT_ADDRESS>' && eth.tx.data[0..10] == '0xa9059cbb'"
}

Allow anyone to sign transactions for testnet (Sepolia)

{
  "policyName": "Allow signing ethereum sepolia transactions",
  "effect": "EFFECT_ALLOW",
  "condition": "eth.tx.chain_id == 11155111"
}

Allow ETH transactions with a specific nonce range

{
  "policyName": "Allow signing Ethereum transactions with an early nonce",
  "effect": "EFFECT_ALLOW",
  "condition": "eth.tx.nonce <= 3"
}

Allow signing of EIP-712 payloads for Hyperliquid ApproveAgent operations

{
  "policyName": "Allow signing of EIP-712 Payloads for Hyperliquid `ApproveAgent` operations",
  "effect": "EFFECT_ALLOW",
  "condition": "eth.eip_712.domain.name == 'HyperliquidSignTransaction' && eth.eip_712.primary_type == 'HyperliquidTransaction:ApproveAgent' && activity.type == 'ACTIVITY_TYPE_SIGN_RAW_PAYLOAD_V2'"
}

Inspect nested fields in EIP-712 message payloads

The eth.eip_712.message map supports nested field access using bracket notation and array iteration operators, allowing policies to inspect and enforce conditions across typed data contents, beyond just the domain and primary type. Syntax:
  • Nested struct fields: eth.eip_712.message['outerField']['innerField']
  • Array element fields: eth.eip_712.message['arrayField'][0]['innerField']
  • Array iteration: eth.eip_712.message['arrayField'].all(item, <condition>)
  • Array length: eth.eip_712.message['arrayField'].count()
Example: Restrict Hyperliquid orders to a specific asset Hyperliquid’s HyperliquidTransaction:Order message contains an orders array of Order structs. Each Order uses short field names: a (asset index), b (isBuy), p (price), s (size), r (reduceOnly).
{
  "primaryType": "HyperliquidTransaction:Order",
  "domain": { "name": "HyperliquidSignTransaction", ... },
  "message": {
    "orders": [
      { "a": 3, "b": true, "p": "1800.0", "s": "0.1", "r": false, ... }
    ],
    "grouping": "normalTpsl"
  }
}
To allow only orders for a specific asset (e.g. ETH = asset index 3):
{
  "policyName": "Allow Hyperliquid orders for ETH only",
  "effect": "EFFECT_ALLOW",
  "condition": "eth.eip_712.domain.name == 'HyperliquidSignTransaction' && eth.eip_712.primary_type == 'HyperliquidTransaction:Order' && eth.eip_712.message['orders'][0]['a'] == 3 && activity.type == 'ACTIVITY_TYPE_SIGN_RAW_PAYLOAD_V2'"
}
Array elements can be accessed by index ([0], [1], etc.). The condition message['orders'][0]['a'] == '3' only checks the first order — any additional orders in the array are not evaluated. Checking multiple positions explicitly (message[‘orders’][0][‘a’] == 3 && message[‘orders’][1][‘a’] == 3) works, but is fragile — adding a third order bypasses the check entirely. Use .all() to enforce a condition across every element regardless of array size.

Iterating over array fields

Enforce batch size with .count():
{
  "policyName": "Limit Hyperliquid batch to 5 orders",
  "effect": "EFFECT_ALLOW",
  "condition": "eth.eip_712.domain.name == 'HyperliquidSignTransaction' && eth.eip_712.primary_type == 'HyperliquidTransaction:Order' && eth.eip_712.message['orders'].count() <= 5 && activity.type == 'ACTIVITY_TYPE_SIGN_RAW_PAYLOAD_V2'"
}
Whitelist a specific asset across all orders with .all():
{
  "policyName": "Allow Hyperliquid orders for asset 3 only",
  "effect": "EFFECT_ALLOW",
  "condition": "eth.eip_712.domain.name == 'HyperliquidSignTransaction' && eth.eip_712.primary_type == 'HyperliquidTransaction:Order' && eth.eip_712.message['orders'].all(order, order['a'] == 3) && activity.type == 'ACTIVITY_TYPE_SIGN_RAW_PAYLOAD_V2'"
}
Whitelist multiple assets with .all():
{
  "policyName": "Allow Hyperliquid orders for ETH or BTC only",
  "effect": "EFFECT_ALLOW",
  "condition": "eth.eip_712.domain.name == 'HyperliquidSignTransaction' && eth.eip_712.primary_type == 'HyperliquidTransaction:Order' && eth.eip_712.message['orders'].all(order, order['a'] in [3, 5]) && activity.type == 'ACTIVITY_TYPE_SIGN_RAW_PAYLOAD_V2'"
}
in works for integer fields (e.g. order['a'] in [3, 5]). For string fields, use || instead.
Combine size limit and asset whitelist:
{
  "policyName": "Allow Hyperliquid orders for ETH only, max 5 per batch",
  "effect": "EFFECT_ALLOW",
  "condition": "eth.eip_712.domain.name == 'HyperliquidSignTransaction' && eth.eip_712.primary_type == 'HyperliquidTransaction:Order' && eth.eip_712.message['orders'].count() <= 5 && eth.eip_712.message['orders'].all(order, order['a'] == 3) && activity.type == 'ACTIVITY_TYPE_SIGN_RAW_PAYLOAD_V2'"
}
Require at least one reduce-only order with .any():
{
  "policyName": "Require at least one reduce-only order in the batch",
  "effect": "EFFECT_ALLOW",
  "condition": "eth.eip_712.domain.name == 'HyperliquidSignTransaction' && eth.eip_712.primary_type == 'HyperliquidTransaction:Order' && eth.eip_712.message['orders'].any(order, order['r'] == true) && activity.type == 'ACTIVITY_TYPE_SIGN_RAW_PAYLOAD_V2'"
}

Deny signing of NO_OP keccak256 payloads

{
  "policyName": "Deny NO_OP hash signing",
  "effect": "EFFECT_DENY",
  "condition": "activity.type == 'ACTIVITY_TYPE_SIGN_RAW_PAYLOAD_V2' && activity.params.hash_function == 'HASH_FUNCTION_NO_OP' && activity.params.encoding != 'PAYLOAD_ENCODING_EIP712'"
}

Allow signing of EIP-712 payloads for EIP-3009 transfers

{
  "policyName": "Allow signing of EIP-712 payloads for EIP-3009 Transfers for USD Coin",
  "effect": "EFFECT_ALLOW",
  "condition": "eth.eip_712.domain.name == 'USD Coin' && eth.eip_712.primary_type == 'TransferWithAuthorization' && activity.type == 'ACTIVITY_TYPE_SIGN_RAW_PAYLOAD_V2'"
}

Allow signing of EIP-712 payloads for EIP-2612 permits for USD Coin

{
  "policyName": "Allow signing of EIP-712 payloads for EIP-2612 Permits for USD Coin",
  "effect": "EFFECT_ALLOW",
  "condition": "eth.eip_712.domain.name == 'USD Coin' && eth.eip_712.primary_type == 'Permit' && activity.type == 'ACTIVITY_TYPE_SIGN_RAW_PAYLOAD_V2'"
}

Allow signing of EIP-7702 authorizations

{
  "policyName": "Allow signing of EIP-7702 Authorizations",
  "effect": "EFFECT_ALLOW",
  "condition": "eth.eip_7702_authorization.address == '<ADDRESS>' && eth.eip_7702_authorization.chain_id == '<CHAIN_ID>' && eth.eip_7702_authorization.nonce == '<NONCE>' && activity.type == 'ACTIVITY_TYPE_SIGN_RAW_PAYLOAD_V2'"
}