# Workflows

You specify a workflow as an array. Each element of the array represents a validation step. This means it is possible to break down the approval into multiple steps so that, for instance, users who must approve at a later stage are not notified until the first approval step is complete.

## Validation steps

Each validation step represented by an element of the array is a JSON object with three properties, in the form of key-value pairs. This is an example of a simple workflow:


```json
[
    {
        "role": "admin",
        "quorum": 2,
        "type": "RoleQuorum"
    }
]
```

This example includes an array with a single element, so the approval workflow consists of one step only. The `type` specifies that this is a `RoleQuorum` workflow, which means that approval is granted as soon as two signatures (specified in `quorum`) are received from users that have an `admin` role. Of course, the number `2` and the string `admin` can be customized.

Since the submitter is the first approver, only a user with an `admin` role can submit an intent. In a similar way, for the approval process any user with an `admin` role can submit an intent to approve, and, as soon as the quorum is reached, the intent is executed (or moves on to the next step if it is a multi-step approval).

If the quorum is not yet reached the step remains open, and users can go back and change their decision (that is, reject an intent they already approved). Once a step is executed it cannot be changed.

A user can never have more than a single approval taken into account for a complete approval workflow. This includes proposal of an intent, which counts as one approval. This verification is implemented at the public key level, so no duplicate public keys can approve during the whole workflow.

You can write more complex flows with a `type` of `And` and `Or`. The syntax is similar in both cases. The format is as follows:


```json
[
    {
        "left": workflowConditionObj,
        "right": workflowConditionObj,
        "type": "And"
    }
]
```

In this example, `workflowConditionObj` is a placeholder. This step is approved if the condition on the `"left"` and the condition on the `"right"` are met. The left and right conditions are actually objects themselves. A fully expanded example is as follows:


```json
[
    {
        "left": {
            "role": "supervisor",
            "quorum": 2,
            "type": "RoleQuorum"
        },
        "right": {
            "role": "manager",
            "quorum": 4,
            "type": "RoleQuorum"
        },
        "type": "And"
    }
]
```

In this example, the intent is executed when two supervisors and four managers give their approval. If we want only the approvals of one set of roles or the other to apply, we can specify the same expression with `"type" : "Or"`.

Since users can have multiple roles, a user `Foo` that has both supervisor and manager roles can submit their approval. In this case, two constraints are imposed by Ripple Custody:

- Users can never provide two approvals. `Foo` can offer one approval, either as a supervisor or as a manager.
- Ripple Custody uses the quickest path to approve an intent. If two other supervisors already approved, the user `Foo` can approve with manager role.


## Example workflows

This section covers some examples of approval workflows. The examples cover simple and more advanced workflows, and both single-step and multi-step workflows. The complexity (or the number of steps) is relative to the risk associated with the submitted intent.

If the workflow is empty, then, the intent is automatically rejected, i.e. `"workflow": []`.

The first approval comes implicitly from the submitter. If the submitter does not have a role compatible with the first approval step, the intent fails. You therefore need to set up the first step as the approval step for the submitter.

### Example 1

Step 1: Intent submitted by user with role equal to `operator`
Step 2: Approval by 1 user with role `supervisor` **OR** `supervisor-bot`


```json
[
    {
        "role": "operator",
        "quorum": 1,
        "type": "RoleQuorum"
    },
    {
        "left": {
            "role": "supervisor",
            "quorum": 1,
            "type": "RoleQuorum"
        },
        "right": {
            "role": "supervisor-bot",
            "quorum": 1,
            "type": "RoleQuorum"
        },
        "type": "Or"
    }
]
```

### Example 2

Step 1: Intent submitted by user with role equal to `operator`
Step 2: Approval by 1 user with role `compliance` **OR** `compliance-bot`, **AND** by 1 user with role `risk` **OR** `risk-bot`
Step 3: Approval by 1 user with role `CISO`


```json
[
    {
        "role": "operator",
        "quorum": 1,
        "type": "RoleQuorum"
    },
    {
        "left": {
            "left": {
                "role": "compliance",
                "quorum": 1,
                "type": "RoleQuorum"
            },
            "right": {
                "role": "compliance-bot",
                "quorum": 1,
                "type": "RoleQuorum"
            },
            "type": "Or"
        },
        "right": {
            "left": {
                "role": "risk",
                "quorum": 1,
                "type": "RoleQuorum"
            },
            "right": {
                "role": "risk-bot",
                "quorum": 1,
                "type": "RoleQuorum"
            },
            "type": "Or"
        },
        "type": "And"
    },
    {
        "role": "CISO",
        "quorum": 1,
        "type": "RoleQuorum"
    }
]
```