Policies

A policy engine is a software component that manages and enforces rules. It operates by evaluating input data against predefined policies to ascertain the appropriate Permit or Forbid decision. In the Armory Stack, policies are a cornerstone component used to govern aspects of the organization's entities such as user or group account access, spending limits over time, the usage of smart-contract functions, and more.

The Armory Policy Engine's flexibility and scalability make it an invaluable tool for organizations seeking to secure usage of digital assets and/or automate decision-making processes with fine-grained control.

What's a policy?

In essence, a policy consists of an action and criteria. For a policy to evaluate the defined action, all criteria must evaluate to true.

{
  when: [
    // Criteria
  ],
  then: "permit" // or "forbid"
}

Writing a policy

This section provides instructions on creating a policy to permit a user, Bob, to transfer up to 10 MATIC from an account on Polygon every 5 hours.

Check out the Policies > Recipies section for more examples.

The goal is to assist you in building a mental model of how policies function in the Armory Stack. Note that each section below builds upon the previous one.

Let's start by permitting Transaction signature requests

{
  when: [
    {
      criterion: "checkAction",
      args: ["signTransaction"]
    }
  ],
  then: "permit"
}

Check if the user is Bob

User IDs are unique ids defined in your Entity Data. For instance, let's assume Bob's ID is bob-id.

{
  when: [
    // ...
    {
      criterion: "checkPrincipalId",
      args: ['bob-id']
    }
  ],
  then: "permit"
}

Check if the account is the correct one

Let's assume the account address is 0x962Ba468Be802d8c92F0462A368e40813f0b4104.

{
  when: [
    // ...
    {
      criterion: "checkAccountAddress",
      args: ['0x962Ba468Be802d8c92F0462A368e40813f0b4104']
    }
  ],
  then: "permit"
}

Check if the action is a MATIC transfer

Here, we'll check the action's intent type and the token by combining two criteria.

{
  when: [
    // ...
    {
      criterion: "checkIntentType",
      args: ["transferNative"]
    },
    {
      criterion: "checkIntentToken",
      args: ['eip155:137/slip44:966']
    }
  ],
  then: "permit"
}
  • When the action is signTransaction, Armory takes the opaque transaction request (from, to, value, and data) and reverse-engineers it into a more granular data structure, which we refer to as "intent".

  • The Armory widely utilizes the CAIP-19 standard to represent chain-agnostic asset IDs. As a result, MATIC is identified as eip155:137/slip44:966.

Check user's spending limits in the last 5 hours

{
  when: [
    // ...
    {
      criterion: "checkSpendingLimit",
      args: {
        limit: '10000000000000000000',
        timeWindow: {
          type: "rolling",
          value: 5 * 60 * 60
        },
        filters: {
          tokens: ['eip155:137/slip44:966'],
          users: ['bob-id']
        }
      }
    }
  ],
  then: "permit"
}

Putting all together

If Bob attempts to Sign a Transaction using the account 0x96..04 where the transaction is a MATIC transfer and he has transferred < 10 MATIC in the last 5 hours, then Permit.

{
  when: [
    {
      criterion: "checkAction",
      args: ["signTransaction"]
    },
    {
      criterion: "checkPrincipalId",
      args: ["bob-id"]
    },
    {
      criterion: "checkAccountAddress",
      args: ["0x962Ba468Be802d8c92F0462A368e40813f0b4104"]
    },
    {
      criterion: "checkIntentType",
      args: ["transferNative"]
    },
    {
      criterion: "checkIntentToken",
      args: ["eip155:137/slip44:966"]
    },
    {
      criterion: "checkSpendingLimit",
      args: {
        limit: "10000000000000000000",
        timeWindow: {
          type: "rolling",
          value: 5 * 60 * 60
        },
        filters: {
          tokens: ["eip155:137/slip44:966"],
          users: ["bob-id"]
        }
      }
    }
  ],
  then: "permit"
}

Last updated