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.
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").
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
- Navigate to http://localhost:3000/permissions
- The rule table shows all active rules
- Click Add Rule to create a new constraint
- Click any rule row to edit the constraint value
- 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.
// 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
# 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:
- The caller's role is read from the validated session token.
- The proxy queries the
PermissionRegistryfor rules matching(role, method, argument). - For each matching rule, the corresponding argument value from the request is compared against the constraint.
- If any rule is violated, the proxy returns JSON-RPC error
-32001 TransferNotAllowedwith a message describing the violated rule. - The blocked request is logged to the audit database with
status: blocked.
Error Response Format
{
"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: A compliance team requires that no single investor can redeem more than $500,000 worth of MMF tokens in a single transaction.
- In the admin dashboard, navigate to Permissions → Add Rule.
- Set:
- Role:
Trader - Method:
token_redeem - Argument:
shares - Constraint: Max Value = $500,000 (the dashboard converts to
500000000000000000000000)
- Role:
- Click Save. The rule is written to the
PermissionRegistrycontract and takes effect immediately.
Alternatively, via the contract:
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
PermissionRegistrycan be called directly from token transfer hooks — this is a planned enhancement.