Skip to main content
Every signing request passes through the policy engine before the Bitnob Secure Enclave signs it. The engine compares the request against the rules in your organization’s enforced policy and returns one decision. This page explains how it reaches that decision, so you can predict what a rule set will do before you write it.

The objects

A policy is a named, ordered list of rules. Your organization has at most one policy in enforced status at a time. Any others are drafts or archived versions. A rule has three parts:
  • Conditions: a list of comparisons against the request, such as amount_usd greater_than 10000. Every condition in a rule must match for the rule to match.
  • An action: what happens when the rule matches. One of allow, block, require_approval, delay, or alert.
  • An order: the rule’s position in the list. Lower numbers run first.
A condition has a field, an operator, and a value. The value goes in value, values, or min and max, depending on the operator. See Condition values.

First match wins

The engine walks the rules in order, from first to last. For each rule it checks the conditions in turn, and stops at the first condition that fails. The first rule whose conditions all match is the terminal rule: its action becomes the decision, and the rules after it are not evaluated. Three consequences follow, and most policy bugs come from one of them:
  • Order is meaning. A broad allow placed above a narrow block makes the block unreachable. Put the most specific and most restrictive rules first.
  • Conditions within a rule are AND. To express “chain is Tron or chain is Ethereum”, use one condition with the in operator, not two conditions.
  • Rules are OR. To express “block if A, and separately block if B”, write two rules.
Validate stored draft policy catches the first problem for you: it warns about rules that are shadowed by an earlier rule, for example with the code shadowed_by_different_action.

What the engine can see

A condition can compare any request attribute the engine evaluates. These include: Rule reference describes each field. Saving a rule with a field the engine doesn’t know returns 400 invalid_condition_field.
Prefer amount_usd for spending thresholds. A single USD rule covers every asset, and you don’t need a separate rule per token with its own decimals.

When no rule matches

If no rule matches, the request is allowed. A dry-run returns "result": "approved" and a trace in which every rule has matched: false. The same result comes back, with the reason “No active policy and no quorum”, when your organization has nothing enforced. So a policy that only lists what to block or hold allows everything else. If you want a default-deny posture, write the allow rules first and finish with a block rule that catches what’s left.
If the engine can’t work out a request’s USD value, conditions on amount_usd don’t match, and the trace reports a resolution error such as “rate provider unavailable”. A block rule that relies only on amount_usd then lets the request through. For your most important limits, add a matching rule on amount for the assets you hold.
Don’t rely on an implicit default for anything security-relevant. End your rule list with an explicit decision for the cases you care about, and confirm the behavior by dry-running a request that matches none of your other rules. See Test rules with dry-run evaluation.

Actions and the transaction status they produce

A held transaction is persisted and its funds are locked. It does not need to be resubmitted: it executes on its own once it is approved or its time lock expires. Handle held and rejected transactions covers the integration side.

Categories

Every policy has a category: access, whitelist, limits, approvals, velocity, compliance, or quorum. If you leave it out, it defaults to access. The category describes what the policy is for and controls how it is evaluated. quorum is reserved for the policy that governs administrative changes, described in Policy lifecycle and quorum. Rule reference lists the categories.

Policies and KYT screening

Policies decide whether a transfer may be signed. KYT risk profiles screen the counterparties a transfer touches, and can hold or block by risk category and exposure. They are configured separately, and a transfer must pass both.