# Permission Rules

Cocoon's `PermissionRegistry` contract enforces **argument-level permissions** — constraints on the values of method arguments, not just whether a role can call a method. This page documents the rule format, the default role matrix, and how to manage rules.

{% hint style="info" %}
Argument-level permissions are a key Cocoon differentiator. Most permissioning systems enforce function-level access ("Trader can call `transfer`"). Cocoon's `PermissionRegistry` enforces argument-level constraints ("Trader can call `transfer`, but only with `amount ≤ $1,000,000`").
{% endhint %}

## Rule Format

A permission rule is a tuple of:

```
(role, method, argument, constraint_type, constraint_value)
```

| Field              | Type             | Description                                                                                                 |
| ------------------ | ---------------- | ----------------------------------------------------------------------------------------------------------- |
| `role`             | string           | The user role this rule applies to: `Trader`, `SeniorTrader`, `Compliance`, `Auditor`, `Regulator`, `Admin` |
| `method`           | string           | The JSON-RPC method name (e.g. `token_transfer`)                                                            |
| `argument`         | string           | The argument name to constrain (e.g. `amount`)                                                              |
| `constraint_type`  | string           | One of: `max_value`, `min_value`, `exact_value`, `blocked`, `allowed`                                       |
| `constraint_value` | string (numeric) | The constraint threshold, encoded as a decimal string                                                       |

### Constraint Types

| Type          | Meaning                                   | Example                                   |
| ------------- | ----------------------------------------- | ----------------------------------------- |
| `max_value`   | Argument must be ≤ this value             | Trader transfer ≤ $1M                     |
| `min_value`   | Argument must be ≥ this value             | Minimum subscription amount               |
| `exact_value` | Argument must equal this value            | Token address must be a specific contract |
| `blocked`     | This role may not call this method at all | Auditor cannot call `token_transfer`      |
| `allowed`     | No constraint; this role may call freely  | Admin is allowed all methods              |

### Encoding Amounts

Amounts in permission rules are stored in the token's smallest unit (18 decimals for most ERC-20 tokens). Human-readable values:

| Human-readable | Encoded value                                   |
| -------------- | ----------------------------------------------- |
| $1,000         | `1000000000000000000000` (1,000 × 10^18)        |
| $1,000,000     | `1000000000000000000000000` (1,000,000 × 10^18) |
| $5,000,000     | `5000000000000000000000000` (5,000,000 × 10^18) |

The admin dashboard's permission editor handles this encoding automatically — enter amounts in human-readable form and the dashboard converts them.

## Default Role Matrix

The following rules are deployed by default in `contracts/deploy.sh`. They reflect the intended demo permission structure for the MVP.

| Role         | Method                          | Argument     | Constraint             |
| ------------ | ------------------------------- | ------------ | ---------------------- |
| Trader       | `token_transfer`                | `amount`     | ≤ $1,000,000           |
| Trader       | `token_batchTransfer`           | `amounts[*]` | Each ≤ $1,000,000      |
| SeniorTrader | `token_transfer`                | `amount`     | ≤ $5,000,000           |
| SeniorTrader | `token_batchTransfer`           | `amounts[*]` | Each ≤ $5,000,000      |
| Compliance   | `token_freeze`                  | —            | allowed                |
| Compliance   | `token_unfreeze`                | —            | allowed                |
| Compliance   | All write methods except freeze | —            | blocked                |
| Auditor      | All write methods               | —            | blocked                |
| Regulator    | All write methods               | —            | blocked                |
| Admin        | All methods                     | —            | allowed (unrestricted) |

## Managing Rules

### Via the Admin Dashboard

1. Navigate to **<http://localhost:3000/permissions>**
2. The rule table shows all active rules
3. Click **Add Rule** to create a new constraint
4. Click any rule row to edit the constraint value
5. Toggle the **Active** switch to disable a rule without deleting it

### Via the PermissionRegistry Contract

Rules are stored on-chain in the `PermissionRegistry` contract. The contract address is in `deployments.json`.

```solidity
// Add a new rule
permissionRegistry.setRule(
    "SeniorTrader",           // role
    "token_transfer",          // method
    "amount",                  // argument
    RuleType.MAX_VALUE,        // constraint type
    5_000_000 * 10**18        // $5M in wei
);

// Remove a rule
permissionRegistry.removeRule("SeniorTrader", "token_transfer", "amount");

// Check if a call is permitted
bool permitted = permissionRegistry.isPermitted(
    "Trader",
    "token_transfer",
    "amount",
    2_000_000 * 10**18  // $2M — will return false for Trader
);
```

### Via the Backend Proxy API

```bash
# List all active rules
GET http://localhost:8546/api/permissions

# Add a rule
POST http://localhost:8546/api/permissions
Content-Type: application/json

{
  "role": "SeniorTrader",
  "method": "token_transfer",
  "argument": "amount",
  "constraint_type": "max_value",
  "constraint_value": "5000000000000000000000000"
}

# Delete a rule
DELETE http://localhost:8546/api/permissions/{rule_id}
```

## Permission Enforcement

When a request arrives at the backend proxy:

1. The caller's role is read from the validated session token.
2. The proxy queries the `PermissionRegistry` for rules matching `(role, method, argument)`.
3. For each matching rule, the corresponding argument value from the request is compared against the constraint.
4. If any rule is violated, the proxy returns JSON-RPC error `-32001 TransferNotAllowed` with a message describing the violated rule.
5. The blocked request is logged to the audit database with `status: blocked`.

### Error Response Format

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32001,
    "message": "Permission rule violated: Trader role allows token_transfer.amount ≤ 1000000000000000000000000. Requested: 2000000000000000000000000."
  }
}
```

The `message` field is human-readable and includes the violated rule in plain language, making it suitable for direct display in investor-facing UIs.

## Adding a Custom Rule

**Scenario:** Your compliance team requires that no single investor can redeem more than $500,000 worth of MMF tokens in a single transaction.

1. In the admin dashboard, navigate to **Permissions → Add Rule**.
2. Set:
   * Role: `Trader`
   * Method: `token_redeem`
   * Argument: `shares`
   * Constraint: Max Value = $500,000 (the dashboard converts to `500000000000000000000000`)
3. Click Save. The rule is written to the `PermissionRegistry` contract and takes effect immediately.

Alternatively, via the contract:

```solidity
permissionRegistry.setRule("Trader", "token_redeem", "shares", RuleType.MAX_VALUE, 500_000 * 10**18);
```

## Security Notes

* Rules are stored on-chain and cannot be silently modified — any change is a contract transaction and is auditable.
* The backend proxy enforces rules before forwarding to the chain. This is a defense-in-depth measure; the chain itself does not enforce argument-level rules.
* To enforce rules at the chain level (without relying on the proxy), the `PermissionRegistry` can be called directly from token transfer hooks — this is a planned enhancement.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://cocoon.erigon.tech/reference/permission-rules.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
