# Overview

A transaction restriction is a rule that says: "If a transaction matches these criteria, then these approvers must sign off." Each restriction has:

- **Filters** - the conditions that decide whether a restriction applies (asset, amount, source account, destination, initiator group, etc.)
- **Action** - who must approve when the filters match, or whether to block the transaction

Transaction restrictions cover anything that signs or broadcasts a transaction: transfers, contract calls, contract deploys, raw signing, staking, sponsored transactions, and allocations.

# Evaluation Semantics

Transaction restrictions are **additive**. When a transaction arrives:

1. Every transaction restriction is checked against the transaction.
2. For each restriction whose filters **match**, its approval requirements are added.
3. The transaction is allowed when **all** the accumulated approval requirements are satisfied.
4. If **no** restriction matches, the transaction is allowed without approvals.

This means the policy engine is **allow-by-default**: to block something, you must write a restriction that matches it and sets Action to Block.

## Filter Values

Filters in the UI use these patterns:

- **Any** - matches everything for that field
- **Only: A, B, C** - matches only the listed values
- **All except: A, B, C** - matches everything except the listed values

Amount filters use a numeric threshold with a currency. `0 USD` is treated as "any amount" (the filter is effectively disabled).

### Initiator group filter

On **Block** restrictions, the form includes **When initiated by**. This scopes the rule to initiator **groups** (the same groups used for approvers, assigned under Settings → Groups).

- **All users** - the restriction applies to every initiator (when the other filters match).
- **All users, except group(s)** - the restriction applies to every initiator **except** members of the listed groups. Those groups are **exempt** from this restriction.

The initiator group filter uses **All except** semantics only. There is no **Only: group Y** mode. To limit an account to one group, write a Block rule on that source account with **All users, except** that group.

When an exempt initiator starts a transaction, they must still **confirm** it first so Policy Nodes can verify group membership before honoring the exemption.

## Action

The Action column in the UI says what happens when the filters match:

- **N of group** - requires N **distinct** approvals from members of that group (e.g. `2 of owner`). Each approver can sign only once per operation.
- **N of multiple groups** (e.g. `1 of owner, treasury` when both groups are selected on one rule) - requires N approvals **in total** from the **combined** membership of all selected groups. Approvals may come from any listed group. A user who belongs to more than one selected group still counts as **one** approver; **one** signature from that user satisfies the whole requirement. This is **not** "one approval from each group."
- **Block** - denies the transaction; no approver set can satisfy it

When you need **separate** requirements from different groups on the same transaction (for example `2 of owner` **and** `1 of compliance`), add **separate** transaction restrictions whose filters both match.

**Example:** one rule selects groups `owner` and `treasury` with **No. Required** = 1.

| Situation | Satisfied by |
| --- | --- |
| UserX is in `owner` only and approves | Yes (1 of 1 from the combined pool) |
| UserY is in `treasury` only and approves | Yes |
| UserZ is in **both**`owner` and `treasury` and approves once | Yes (membership in both groups does not require two signatures) |
| UserZ is in both groups but **No. Required** = 2 | No (one user cannot supply two distinct approvals) |

## Confirmation and approval

When a transaction requires approvals and has an **initiator**, the initiator must **confirm** it first. Confirmation is the initiator's signed attestation to the intent shown in the Approver App. After confirmation, the wallet collects any remaining **approvals** from the configured approver groups.

The initiator acts as **confirmer** during that first step. Whether confirmation also counts as an approval depends on group membership:

- If the initiator **belongs to** any group that contributes to a matched approval requirement, their confirmation counts as **one approval** toward that requirement.
- If the initiator **does not belong** to any contributing group, confirmation does **not** reduce the approval count. The full number of approvals is still required.

**Example:** a restriction requires `2 of owner`.

| Initiator | After initiator confirms | Still required |
| --- | --- | --- |
| UserA (member of `owner`) | 1 owner approval recorded | 1 more approval from `owner` |
| UserB (not in `owner`) | Confirmation only (does not count toward `owner`) | 2 approvals from `owner` |

Confirmation is skipped when no approvals are required, or when the operation has no initiator (for example some API-initiated flows).

# UI Columns

Each row in the Transaction tab is one restriction. When you add or edit a restriction, the form groups **When initiated by** (Block rules only), **Action** (Block or Approvals), **Group(s)** and **No. Required**, **Source** (and source accounts when narrowed), **Amount (USD)**, and an **Advanced** section for **Destination**, **Symbol**, and **Function** (for example Mint, Burn, Clawback).

| Column | What it filters on |
| --- | --- |
| **When initiated by** | Initiator group (Block rules only; **All users** or **All users, except group(s)**) |
| **Symbol** | Asset symbol (e.g. `ETH`, `USDC`, `BTC`) |
| **Amount Greater Than Or Equal To** | Total transaction amount above a threshold (rates converted via the pricing service) |
| **Source** | Source vault account |
| **Destination** | Internal account or external on-chain address |
| **Function** | Function performed (e.g. `transfer`, `mint`, `burn`, `clawback`, `freeze`, `deploy`) |
| **Action** | Approval requirement or Block when the filters match |

# Scenarios

All restrictions are added independently; their effects accumulate.

## Scenario 1: Two-of-N owner approval for any transaction

The simplest baseline: every transaction needs two approvals from the `owner` group.

| When initiated by | Symbol | Amount Greater Than Or Equal To | Source | Destination | Function | Action |
| --- | --- | --- | --- | --- | --- | --- |
| All users | Any symbol | 0 USD | Any account | Any | Any | 2 of owner |

Result: any transfer, contract call, deploy, raw sign, etc. requires 2 owner approvals. If the initiator is in `owner`, they confirm first and that confirmation counts as one of the two; otherwise the initiator confirms and two separate owner approvals are still required.

## Scenario 2: Higher bar for large transfers

Keep the baseline rule, **and** require an additional compliance approval whenever the transaction value is at or above 100,000 USD.

| When initiated by | Symbol | Amount Greater Than Or Equal To | Source | Destination | Function | Action |
| --- | --- | --- | --- | --- | --- | --- |
| All users | Any symbol | 0 USD | Any account | Any | Any | 2 of owner |
| All users | Any symbol | 100,000 USD | Any account | Any | Any | 1 of compliance |

Result:

- A 50,000 USD transfer matches only the baseline rule and needs 2 owner approvals.
- A 250,000 USD transfer matches both rules and needs 2 owner approvals **plus** 1 compliance approval.

## Scenario 3: Allowlist for external destinations

Block transfers to anywhere except a known set of audited counterparty addresses. Internal transfers between vault accounts are unaffected.

| When initiated by | Symbol | Amount Greater Than Or Equal To | Source | Destination | Function | Action |
| --- | --- | --- | --- | --- | --- | --- |
| All users | Any symbol | 0 USD | Any account | All except: 0xCounterpartyA, 0xCounterpartyB, bc1qcounterpartyc | Any | Block |

Result:

- A transfer to one of the listed counterparties does not match this rule, so only the baseline rule applies.
- A transfer to any other external address matches this rule and is denied.

## Scenario 4: Restricted minting authority

Mint operations on tokens should only be initiated from the `conversionWallet` source account, and only with elevated approvals depending on size.

| When initiated by | Symbol | Amount Greater Than Or Equal To | Source | Destination | Function | Action |
| --- | --- | --- | --- | --- | --- | --- |
| All users | Any symbol | 0 USD | All except: conversionWallet | Any | Only: Mint | Block |
| All users | Any symbol | 0 USD | Only: conversionWallet | Any | Only: Mint | 1 of operationsMint |
| All users | Any symbol | 1,000,000 USD | Only: conversionWallet | Any | Only: Mint | 2 of operationsMint |

Result:

- Any Mint attempted from a source other than `conversionWallet` is blocked.
- A Mint from `conversionWallet` under 1,000,000 USD requires 1 approval from `operationsMint`.
- A Mint from `conversionWallet` at or above 1,000,000 USD matches both Mint rules and requires 2 approvals from `operationsMint` (the higher requirement absorbs the lower).

## Scenario 5: Restrict a source account to one initiator group

Limit which users may initiate transactions **from** a sensitive vault account. Only members of group `treasuryOps` may operate from `treasuryAccount`; everyone else is denied when sending from that account.

| When initiated by | Symbol | Amount Greater Than Or Equal To | Source | Destination | Function | Action |
| --- | --- | --- | --- | --- | --- | --- |
| All users except: treasuryOps | Any symbol | 0 USD | Only: treasuryAccount | Any | Any | Block |

Result:

- A user in `treasuryOps` initiates from `treasuryAccount`. This restriction does not apply to them (they are exempt). The transaction proceeds if no other restriction blocks it or adds approvers.
- A user who is **not** in `treasuryOps` initiates from `treasuryAccount`. The restriction matches and **Block** denies the transaction.
- A transfer from any other source account does not match the **Source** filter, so this rule is ignored.
