Built-in Functions

Complete reference for all available built-in functions in policies

Only the following built-in functions are enabled in policies. Functions not listed here are disabled for security reasons. See Restrictions for details on disabled functions.

String Functions

Functions for manipulating and inspecting string values. Essential for working with addresses, method names, and other text fields.

contains

Check if a string contains a substring. Returns true if found, false otherwise.

Example

# Block any method containing "sign"
deny if {
    contains(input.rpc_method, "sign")
}

startswith

Check if a string starts with a prefix. Useful for matching method categories or address patterns.

Example

# Block debug methods
deny if {
    startswith(input.rpc_method, "debug_")
}
 
# Block addresses starting with many zeros
deny if {
    startswith(input.to_address, "0x00000000")
}

endswith

Check if a string ends with a suffix.

Example

# Block addresses ending with specific pattern
deny if {
    endswith(lower(input.to_address), "dead")
}

lower

Convert a string to lowercase. Essential for case-insensitive address comparison since addresses can have mixed case.

Example

# Case-insensitive address check
blocked_addresses := {
    "0x000000000000000000000000000000000000dead"
}
 
deny if {
    lower(input.to_address) in blocked_addresses
}

upper

Convert a string to uppercase.

Example

# Normalize method names that might have inconsistent casing
deny if {
    upper(input.rpc_method) == "ETH_SENDTRANSACTION"
    input.usd_value > 10000
}

concat

Join an array of strings with a delimiter.

Example

# Join values for logging or comparison
message := concat(", ", ["chain:", input.chain, "method:", input.rpc_method])

split

Split a string into an array using a delimiter.

Example

# Parse a method name
parts := split(input.rpc_method, "_")
 
deny if {
    parts[0] == "debug"
}

replace

Replace all occurrences of a substring with another string.

Example

# Normalize address format
normalized := replace(input.to_address, "0X", "0x")

substring

Extract a portion of a string by start position and length.

Example

# Get method prefix (first 4 characters after "eth_")
deny if {
    startswith(input.rpc_method, "eth_")
    method_action := substring(input.rpc_method, 4, 4)
    method_action == "send"
}

sprintf

Format a string with placeholders. Useful for creating dynamic values.

PlaceholderType
%sString
%dInteger
%fFloat
%vAny value

Example

# Create formatted message
threshold := 10000
message := sprintf("Value %d exceeds limit of %d", [input.usd_value, threshold])

trim

Remove specified characters from both ends of a string.

Example

# Remove specific characters from both ends
cleaned := trim(input.rpc_method, "_")

trim_space

Remove whitespace from both ends of a string.

Example

# Clean up input with extra spaces
clean_method := trim_space(input.rpc_method)

trim_prefix

Remove a prefix from a string if present.

Example

# Remove common prefix to get the action name
method_name := trim_prefix(input.rpc_method, "eth_")
 
deny if {
    method_name == "sendTransaction"
}

trim_suffix

Remove a suffix from a string if present.

Example

# Remove suffix for comparison
base_method := trim_suffix(input.rpc_method, "_v2")

indexof

Find the index of the first occurrence of a substring. Returns -1 if not found.

Example

# Check if underscore exists
deny if {
    indexof(input.rpc_method, "_") == -1
}

Regex Functions

Functions for pattern matching using regular expressions. More powerful than string functions for complex patterns.

regex.match

Check if a string matches a regular expression pattern. Returns true or false.

Example

# Block methods starting with debug_, admin_, or personal_
deny if {
    regex.match("^(debug_|admin_|personal_)", input.rpc_method)
}
 
# Block addresses with many leading zeros
deny if {
    regex.match("^0x0{10,}", input.to_address)
}

regex.replace

Replace all matches of a pattern with a replacement string.

Example

# Remove all non-alphanumeric characters
cleaned := regex.replace(input.rpc_method, "[^a-zA-Z0-9]", "")

regex.split

Split a string by a regex pattern.

Example

# Split by multiple delimiters
parts := regex.split("[_.]", input.rpc_method)

regex.find_n

Find up to n matches of a pattern in a string.

Example

# Find all hex sequences
hex_matches := regex.find_n("0x[a-fA-F0-9]+", input.raw_params[0].data, 10)
 
deny if {
    count(hex_matches) > 5
}

Time Functions

Functions for working with time. All time values are in nanoseconds since Unix epoch.

time.now_ns

Get the current time in nanoseconds. Use this as the basis for time-based policies.

Example

# Block high-value transactions during volatile market hours
deny if {
    current := time.now_ns()
    [hour, _, _] := time.clock(current)
    hour >= 14  # After 2 PM UTC (US market open)
    hour < 21   # Before 9 PM UTC (US market close)
    input.usd_value > 50000
}

time.clock

Extract hour, minute, and second from a timestamp. Returns [hour, minute, second].

Example

# Block outside business hours (9 AM - 5 PM UTC)
deny if {
    [hour, _, _] := time.clock(time.now_ns())
    hour < 9
}
 
deny if {
    [hour, _, _] := time.clock(time.now_ns())
    hour >= 17
}

time.weekday

Get the day of the week from a timestamp. Returns 0 (Sunday) through 6 (Saturday).

Example

# Block on weekends
deny if {
    day := time.weekday(time.now_ns())
    day == 0  # Sunday
}
 
deny if {
    day := time.weekday(time.now_ns())
    day == 6  # Saturday
}

time.date

Extract year, month, and day from a timestamp. Returns [year, month, day].

Example

# Block on specific dates
deny if {
    [year, month, day] := time.date(time.now_ns())
    month == 12
    day == 25  # Christmas
}

time.parse_rfc3339_ns

Parse an RFC3339 formatted timestamp string into nanoseconds.

Example

# Compare against a specific date
cutoff := time.parse_rfc3339_ns("2024-12-31T23:59:59Z")
 
deny if {
    time.now_ns() > cutoff
}

time.add_date

Add years, months, and days to a timestamp.

Example

# Block transactions if we're within 7 days of year end
deny if {
    year_end := time.parse_rfc3339_ns("2024-12-31T23:59:59Z")
    week_before := time.add_date(year_end, 0, 0, -7)
    time.now_ns() > week_before
    input.usd_value > 10000
}

time.diff

Calculate the difference between two timestamps. Returns [years, months, days, hours, minutes, seconds].

Example

# Check if more than 1 hour has passed
start := time.parse_rfc3339_ns("2024-01-01T00:00:00Z")
[_, _, _, hours, _, _] := time.diff(time.now_ns(), start)
 
deny if {
    hours > 1
}

Aggregate Functions

Functions for working with collections of values.

count

Count the number of elements in an array, set, or object.

Example

# Limit number of contracts in a request
deny if {
    count(input.contract_addresses) > 5
}
 
# Ensure at least one address
deny if {
    count(input.contract_addresses) == 0
}

sum

Calculate the sum of numbers in an array.

Example

# Block if total gas across params exceeds limit
deny if {
    gas_values := [to_number(p.gas) | some p in input.raw_params; p.gas != null]
    sum(gas_values) > 5000000
}

max

Find the maximum value in an array.

Example

# Check against maximum in a set of thresholds
thresholds := [1000, 5000, 10000]
 
deny if {
    input.usd_value > max(thresholds)
}

min

Find the minimum value in an array.

Example

# Ensure value meets minimum threshold
thresholds := [100, 500, 1000]
 
deny if {
    input.usd_value < min(thresholds)
}

sort

Sort an array in ascending order.

Example

# Check if smallest contract address looks suspicious (many leading zeros)
deny if {
    count(input.contract_addresses) > 0
    sorted_addrs := sort(input.contract_addresses)
    startswith(sorted_addrs[0], "0x00000000")
}

product

Calculate the product of numbers in an array.

Example

# Calculate combined risk score from multiple factors
deny if {
    risk_factors := [2, 3]  # High-value = 2x, Unknown sender = 3x
    combined_risk := product(risk_factors)
    combined_risk > 5
}

Type Functions

Functions for checking and working with data types. Useful for handling nullable fields safely.

is_null

Check if a value is null. Essential for handling optional input fields.

Example

# Safely check nullable field
deny if {
    not is_null(input.usd_value)
    input.usd_value > 10000
}

is_number

Check if a value is a number.

Example

# Validate before numeric comparison
deny if {
    is_number(input.usd_value)
    input.usd_value > 10000
}

is_string

Check if a value is a string.

Example

# Validate input type
deny if {
    is_string(input.to_address)
    startswith(input.to_address, "0x0000")
}

is_array

Check if a value is an array.

Example

# Check before iterating
deny if {
    is_array(input.contract_addresses)
    count(input.contract_addresses) > 10
}

is_boolean

Check if a value is a boolean (true or false).

Example

# Verify a flag is actually a boolean before using it
deny if {
    is_boolean(input.raw_params[0].enabled)
    input.raw_params[0].enabled == false
}

is_set

Check if a value is a set.

Example

# Validate collection type
deny if {
    is_set(input.raw_params[0].addresses)
    count(input.raw_params[0].addresses) > 100
}

is_object

Check if a value is an object (key-value map).

Example

# Ensure params is an object before accessing fields
deny if {
    is_object(input.raw_params[0])
    object.get(input.raw_params[0], "dangerous", false) == true
}

type_name

Get the type name of a value as a string.

Example

# Block if usd_value is not a number (unexpected type)
deny if {
    input.usd_value != null
    type_name(input.usd_value) != "number"
}

Number Functions

Functions for numeric operations.

abs

Get the absolute value of a number.

Example

# Check magnitude regardless of sign
deny if {
    abs(input.usd_value) > 10000
}

round

Round a number to the nearest integer.

Example

# Round for comparison
deny if {
    round(input.usd_value) > 10000
}

ceil

Round a number up to the next integer.

Example

# Round up for conservative limit checking
deny if {
    ceil(input.usd_value) > 10000
}

floor

Round a number down to the previous integer.

Example

# Block transactions over $10,000 (ignoring cents)
deny if {
    floor(input.usd_value) >= 10000
}

to_number

Convert a string to a number. Useful for hex string values.

Example

# Convert hex gas values
deny if {
    input.gas_limit != null
    to_number(input.gas_limit) > 1000000
}

numbers.range

Generate an array of numbers from start to end (inclusive).

Example

# Allow transactions only during business hours (9 AM - 5 PM)
deny if {
    [hour, _, _] := time.clock(time.now_ns())
    business_hours := numbers.range(9, 17)
    not hour in business_hours
}

Object Functions

Functions for working with objects (key-value maps).

object.get

Safely get a value from an object with a default if the key doesn't exist.

Example

# Safely access nested data
deny if {
    params := input.raw_params[0]
    data := object.get(params, "data", "0x")
    startswith(data, "0xa9059cbb")  # ERC-20 transfer
}

object.keys

Get all keys from an object as an array.

Example

# Check which fields are present
params := input.raw_params[0]
keys := object.keys(params)
 
deny if {
    "data" in keys
    "value" in keys
}

object.remove

Create a new object with specified keys removed.

Example

# Block if params contain unexpected fields after removing known safe ones
deny if {
    safe_fields := ["to", "from", "value", "gas", "data"]
    remaining := object.remove(input.raw_params[0], safe_fields)
    count(object.keys(remaining)) > 0
}

object.union

Merge two objects. Values from the second object override the first.

Example

# Apply safe defaults and check resulting gas limit
deny if {
    defaults := {"gas": "0x5208"}
    params := object.union(defaults, input.raw_params[0])
    to_number(params.gas) > 1000000
}

Array Functions

Functions for array manipulation.

array.concat

Concatenate two arrays into one.

Example

# Combine address lists
all_addresses := array.concat(
    input.contract_addresses,
    [input.to_address]
)

array.slice

Extract a portion of an array by start and end index.

Example

# Only check first 5 contract addresses for blocked list
deny if {
    first_five := array.slice(input.contract_addresses, 0, 5)
    some addr in first_five
    addr in {"0xbanned1...", "0xbanned2..."}
}

array.reverse

Reverse the order of elements in an array.

Example

# Check last contract address (most recent) for suspicious patterns
deny if {
    count(input.contract_addresses) > 0
    reversed := array.reverse(input.contract_addresses)
    startswith(reversed[0], "0x00000000")
}

Set Functions

Functions for set operations.

intersection

Get elements that exist in both sets.

Example

# Check for any blocked address
blocked := {"0xdead...", "0xbad..."}
request_addrs := {lower(input.to_address)}
 
deny if {
    count(intersection(blocked, request_addrs)) > 0
}

union

Combine two sets into one with all unique elements.

Example

# Combine multiple blocklists
blocked_countries := union(
    {"KP", "IR", "CU"},
    {"SY", "RU"}
)
 
deny if {
    input.source_country in blocked_countries
}

Encoding Functions

Functions for encoding and decoding data.

base64.encode

Encode a string to Base64 format.

Example

# Check if method matches an encoded pattern
deny if {
    encoded_method := base64.encode(input.rpc_method)
    encoded_method == "ZXRoX3NlbmRUcmFuc2FjdGlvbg=="  # eth_sendTransaction
}

base64.decode

Decode a Base64 string back to plain text.

Example

# Decode base64 data from request
decoded := base64.decode("aGVsbG8=")  # "hello"
 
deny if {
    contains(decoded, "dangerous")
}

base64url.encode

Encode a string to URL-safe Base64 format. Uses - and _ instead of + and /.

Example

# Create URL-safe identifier from address for comparison
deny if {
    encoded_addr := base64url.encode(input.to_address)
    encoded_addr in {"MHhkZWFk...", "MHhiYWQ..."}
}

base64url.decode

Decode a URL-safe Base64 string back to plain text.

Example

# Decode and check URL-safe encoded data in params
deny if {
    encoded_data := object.get(input.raw_params[0], "encoded", "")
    decoded := base64url.decode(encoded_data)
    contains(decoded, "malicious")
}

hex.encode

Encode a string to hexadecimal format.

Example

# Encode method name to hex for pattern matching
deny if {
    method_hex := hex.encode(input.rpc_method)
    startswith(method_hex, "657468")  # "eth" in hex
}

hex.decode

Decode a hexadecimal string back to plain text.

Example

# Decode hex-encoded data field and check contents
deny if {
    data := object.get(input.raw_params[0], "data", "")
    startswith(data, "0x")
    decoded := hex.decode(substring(data, 2, 8))
    contains(decoded, "admin")
}
Built-in Functions | 256 Blocks