# Rule Conditions and Actions

This page describes the conditions that you can set for any single
[rule you create](/user-guide/policies/create-a-policy-rule) while building a policy.

When you create a rule, you
[first set the Action](/user-guide/policies/create-a-policy-rule#create-a-new-policy), that should
be taken if all the conditions of the rule are fulfilled. There are three action
options:

- Allow a transaction.
- Block a transaction.
- Require approval for a transaction.


These are the conditions you can define for the policy rule:

## Initiator

The *Initiator* condition lets admins select which user or group of users will
be part of the rule. A user can appear both as an individual and as part of a
group.

## Origin

The *Origin* condition lets admins select which vaults or group of vaults will
be part of the rule.

## Transaction type

The *Transaction Type* condition lets admins limit the type of transaction for
which the rule will be in effect. It can be one the following:

- Transfer: Sending funds directly to another recipient using the platform
either using the Transfer dialog in the Web console or the API.
- Contract call: Interaction using a smart contract or a DApp
- Allowance: A token approval on EVM chains only
- Message signature: One of three types:
  - EVM Personal message
  - EVM Typed data message
  - Non-EVM message
- Black-box signature: Signing any arbitrary buffer (on black-box vaults only)
- Contract deployment: Deploy a smart contract to the blockchain.
- In-app swap: Swapping using in-app integrated DEX aggregators, encapsulates
the required allowance transaction, as well.


### Conditions and transaction types

Certain conditions apply only to specific types of transactions. When a rule
specifies a condition that is not applicable to a certain transaction type, such
transactions can not be matched by this rule. The table below summarizes which
options are applicable. See also the specifics of setting policy rules for
[message signatures](/user-guide/policies/message-policy).

| Type | Subtype | Origin | Initiator | Recipient | Amount | Periodic amount | Asset | ABI | Cosmos Message | EVM Typed Message |
|  --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| Contract Call |  | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | x |
| Transfer |  | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | x | x | x |
| In-app swap |  | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | x | x | x |
| Allowance |  | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | x | x |
| Message | EVM Typed Data | ✓ | ✓ | ✓ | x | x | x | x | x | ✓ |
|  | EVM Personal Message | ✓ | ✓ | x | x | x | x | x | x | x |
|  | Non-EVM | ✓ | ✓ | x | x | x | x | x | x | x |
| Black box |  | ✓ | ✓ | x | x | x | x | x | x | x |


## Recipient

The *Recipient* condition lets admins set limits on the destination/recipient of
the transaction. The recipient of a transfer is the address that receives the
funds. For allowances, this is the address that receives the token allowance
(that is, the spender). For contract calls, recipient is the destination address
of the contract call.

On certain chains (most
notably Solana and Sui), a transaction can have multiple recipients, where you
define the set of recipients as the set of programs in each of the instructions
of the transaction. For the policy to match the transaction, all of the
recipients should appear in the rule. 

A policy rule can specify the Destination/Recipient as one or more of the
following:

- Address book entry or address group
- Internal vault or vault group
- DApp on a specific chain: You can filter DApps by chain, making it easier to
find the exact match when the same DApp appears on multiple chains:

- Custom address


If a user interacts with a smart contract that transfers funds to a third-party
address using a DApp, Fordefi will match the address of the contract (and its
corresponding DApp) as the recipient of the transaction, rather than the final
destination of the funds.

## Asset

The *Asset* condition lets admins specify the token or tokens that the
transaction is **sending**. For a rule to match a transaction, each of
the **outgoing** (that is, sent) tokens in the transaction must appear in the
list of tokens in the rule. For example, when swapping MATIC for USDC (that is,
send 1 MATIC, get back 1.5 USDC), a rule that specifies MATIC would match the
transaction, whereas a rule that specifies USDC would not.

A transaction that has no outgoing asset outflows does not match any policy rule
that specifies a particular set of assets.

## Amounts

The policy engine supports both transaction-level and periodic amounts.

### Transaction amount

The *Transaction Amount* condition lets admins specify a maximal amount in USD
for the transaction. For transfers, the amount is simply the amount of the
transfer.

Determining the amount of a contract call is more subtle. First, since a
contract call does not directly specify an amount, its value is
simulation-based—derived from the transaction simulation results. Second, a
single contract call can transfer multiple tokens both in and out of the vault.
Fordefi aggregates the USD-value amounts of all the token transfers in the
contract call in each direction: from the vault and into the vault. Token
transfers that do not affect the vault are ignored. The transaction then has two
associated amounts:

- The *outgoing* amount: The total USD value of transfers that reduce the
vault's holdings. Sending assets, or receiving liabilities, count towards this
amount.
- The *net* amount: The sum of the USD-value amounts of all the token transfers
out of the vault, minus the sum of the USD-value amounts of all the token
transfers into the vault.


For example, when a user swaps $100 of USDC for $99.99 USDT, the outgoing amount
is $100, while the net amount is $0.01.

For a more complex example, consider a user borrowing $500 of USDC from Aave. The vault receives $500 of USDC along with a matching debt token, `variableDebtEthUSDC`, priced at −$500. The outgoing amount is $500, because receiving a liability counts as outgoing; the net amount is $0, because the asset and its debt token cancel out.

When setting up a rule, the user can choose whether to use the outgoing or net
amount.

### Periodic amount

The *Periodic Amount* condition limits the total spending volume across
transactions within a specified period of time. It lets you choose the time
period, whether the limit applies cumulatively across all users or per
individual user, and which transactions count toward it.

For example, you can limit the cumulative transaction volume for all users in
your organization to $100,000 per day.

Periodic amounts are based on the "net" (rather than "outgoing") amount of a
transaction.

Edit periodic amount dialog
- Use the `>` or `≤` symbols to define the amount. To indicate a maximum amount,
use `≤`.
- **Scope** — choose what counts toward the limit:
  - **Count matching transactions** (default): only transactions matched by this
rule count toward its limit. Available only with the `≤` operator. Each
transaction counts toward exactly one rule — the rule it matched.
  - **Count all transactions**: every transaction counts toward the limit,
regardless of which rule matched it. This is the previous default behavior.
- Set a time period — counters are aligned to fixed calendar periods in UTC:
  - Hourly
  - Daily — 00:00–23:59 UTC
  - Weekly — Monday 00:00 to Sunday 23:59 UTC
  - Monthly (every 30 days)
- Select one of the user options:
  - **All users**: the limit applies cumulatively across the organization.
  - **Per user**: the limit applies to each user separately.


#### Counters

Fordefi shows the current usage of each periodic amount condition in the rule
view to make troubleshooting easier. Each counter shows the limit, the number of
transactions counted in the current period, the spent amount, and a usage bar. A
**View transactions** link opens the Transactions page filtered to the matching
rule, period, and (for per-user counters) initiator.

Periodic amount counter
- For "All users" rules, a single counter is shown per rule.
- For "Per user" rules, all non-zero counters are shown — one per user with
usage in the current period.


#### Counters and policy changes

When other conditions in a rule change (for example, the recipient list),
counters are retained — Fordefi does not re-evaluate historical transactions
against the updated rule. When the periodic amount condition itself changes
(period, scope, or limit), the counter is reset.

### Handling of various transaction states

- A transaction is counted towards the spending limit quota as soon as it is
created. Until its completion, the amount is computed based on the transaction
simulation. Once a transaction is completed, the amount is computed based on
the actual amount as was executed on the blockchain.
- If a transaction is aborted, the amount of the aborted transaction is credited
back to the quota.
- If a transaction is accelerated, only one instance of the transaction amount
counts towards the quota, even though both the original and accelerated
versions are pending.
- If a transaction is cancelled, the amount of the transaction is credited back
to the quota as soon as the cancellation transaction is confirmed.


### Handling of token allowances

Token allowances count both toward transaction-level and periodic spending
limits. Unlimited allowances are handled specially: they require approval if
they would exceed the periodic limit, but their value is not added to the
running total to prevent a single unlimited allowance from consuming the entire
limit and blocking all further transactions.

For example, with a policy allowing up to $1,000 daily spending without
approval:

- Allowance of $400 → Auto-approved (total: $400)
- Give unlimited token allowance → Requires approval (because it represents
potentially unlimited spending), but doesn't add to the running total
- Allowance $400 → Auto-approved (total: $800)
- Allowance $400 → Requires approval (total would be $1,200, exceeding the
$1,000 limit)


### Handling of missing amounts

In some cases, the amount of a transaction is not available. There are two main
cases when this can happen. The first is when Fordefi does not have a USD price
for a transferred token. (We generally take the prices from CoinGecko, so when a
token is not listed on CoinGecko, we do not have a price. It often happens for
more exotic tokens like LP Tokens.)

The second is when the transaction is a contract call, and we fail to estimate
the amount of the transaction using transaction simulation. This can happen when
the simulation is not supported for a specific chain, when the simulation fails,
or when transaction reverts in simulation.

In both cases, the amount of the transaction is unknown, which makes it unclear
how to evaluate a rule which conditions on the amount of a transaction. In this
case, Fordefi evaluates the policy conservatively as follows:

- If a rule does not have an amount condition, the rule is matched as usual.
- If a rule has a ≤ (*"less than or equal to"*) amount condition, the rule is
not matched. The rationale is that the unknown amount might be above the limit
in the rule.
- If a rule a > (*"greater than"*) amount condition, the rule is matched out of
an abundance of caution.


## ABI

ABI defines how to encode and decode data in contract calls, enabling the
execution of methods within smart contracts. It includes details such as method
name.

- Users can input the ABI in the 4-byte hash format so that Fordefi can check if
the transaction matches the hash.
- Additionally, users can set conditions more granularly, by specifiying the
method's parameters and associated values. Fordefi allows you to create a
policy based on the parameter types in contract calls listed in the table
below: address, integer, Boolean, byte (that includes `bytes32`, fixed-size
byte types `bytes1`–`bytes31`, dynamic `bytes`), arrays, and tuples.
For each, you must specify in which order it occurs in the contract.


Learn more by studying
[Advanced ABI check samples](/user-guide/policies/sample-advanced-abi-check).

The following table lists the parameter types Fordefi supports in ABI
conditions, the operations available for each, and how values should be
formatted.

| Type | Description | Supported operations | Notes |
|  --- | --- | --- | --- |
| Address | `address`: Holds a 20 byte value (size of an Ethereum address). | =, !=, “is origin vault”, “is any vault”, address or group from the address book. |  |
| Integer, Unsigned Integer (uint) | Numeric parameters. `int`, `uint`: Signed and unsigned integers of various sizes. Keywords `uint8` to `uint256` in steps of `8` (unsigned of 8 up to 256 bits) and `int8` to `int256`. `uint` and `int` are aliases for `uint256` and `int256`, respectively. | =, !=, <, >, ≤, ≥ |  |
| Boolean | The possible values are constants `true` and `false`. | = |  |
| `bytes32` | A fixed-size 32-byte value, input as a hex string prefixed with `0x` (exactly 64 hex characters). | =, !=, `is empty`, `contains`, `does NOT contain`, `[i:j] =` | Fixed bytes type is 32 bytes in ABI encoding. |
| `bytes1`–`bytes31` | Fixed-size byte values smaller than 32 bytes, input as a hex string prefixed with `0x`, padded or exactly matching the declared type size. | =, !=, `is empty`, `contains`, `does NOT contain`, `[i:j] =` | `bytes4`: Function selectors are `bytes4` values. This allows policy authors to constrain which inner function is being called, where the outer function is fixed but the inner target varies by a selector argument. |
| `bytes` (dynamic) | A dynamic byte array, input as a hex string prefixed with `0x`. Empty bytes is represented as `0x`. | =, !=, `is empty`, `contains`, `does NOT contain`, `[i:j] =` |  |
| Array (example: `address[]`, `uint256[]`, `uint256[3]`) | Conditions target a specific element within an array-type parameter, scoped by zero-indexed position. The value format follows the underlying element type. | Inherited from element type (example: `=`, `!=` for address; `=`, `!=`, `<`, `>`, `≤`, `≥` for numeric; `=`, `!=` for boolean and bytes elements). | Dynamic arrays use offset+length ABI encoding; the evaluation engine must decode the full array before applying the positional condition. Fixed-size arrays (example: `uint256[3]`) are statically encoded and positional access is straightforward. |
| Tuple (struct) | Conditions target individual fields within a tuple by zero-indexed field position. Multiple field conditions on the same tuple are combined with AND. | Per-field, inherited from field type (`=`, `!=` for address and boolean; `=`, `!=`, `<`, `>`, `≤`, `≥` for numeric; positional element match for array fields). | Tuples are ABI-encoded as a sequence of their component types. The evaluation engine must decode the tuple at the declared top-level parameter position before applying field-level conditions. |


## EVM typed message

See [Set Policy Rules for Message Signatures](/user-guide/policies/message-policy) to learn more.

## Cosmos message

A Cosmos message refers to the specific instruction or action that users want to
execute on the Cosmos blockchain. Messages can represent various types of
actions, such as transferring tokens, voting on proposals, or delegating staking
tokens to validators.

For example, suppose you wish to set a policy that requires different approval
quorums for claiming staking rewards versus un-delegating your staked assets.
This can be done by setting fine-grained policy rules on the `MsgUndelegate`
message-level.

alt