Overview
Permissions control who can perform actions on collections and user balances, and when those actions can be executed.
Typically, user permissions are always set to allowed / empty. In advanced cases like escrows, user permissions can be set to forbidden to make certain on-chain actions impossible.
Collection permissions are important to be set correctly: If there is no manager, the collection permission values do not matter.
Overview
Action Request
↓
Permission Check
↓
┌─────────────────┬─────────────────┐
│ Collection │ User │
│ Permissions │ Permissions │
│ (Manager Only) │ (User Control) │
└─────────────────┴─────────────────┘
↓
Permitted/Forbidden
↓
Execute/Deny
Permission Types
Collection
Manager only
Control collection-level actions
User
Individual users
Control user-specific actions
Permission States
Note: Once a permission is set to permanently permitted or forbidden, it cannot be changed.
Permanently Permitted
Action ALWAYS allowed
Can be executed
Permanently Forbidden
Action ALWAYS blocked
Cannot be executed
Neutral
Not specified
Allowed by default
There is no forbidden + not frozen state because theoretically, it could be updated to permitted at any time and executed (thus making it permitted).
Time Control
All permissions support time-based control via UNIX millisecond UintRanges.
{
"permanentlyPermittedTimes": [{ "start": "1", "end": "1000" }],
"permanentlyForbiddenTimes": [
{ "start": "1001", "end": "18446744073709551615" }
]
}
Permission Categories
There are five types of permissions, each with different criteria:
Action Permissions - Simple time-based permissions (no criteria)
Timeline Permissions - Control timeline updates (timelineTimes)
Timeline with Badge IDs - Control badge-specific timeline updates (timelineTimes + badgeIds)
Badge ID Action Permissions - Control badge-specific actions (badgeIds)
Approval Permissions - Control approval updates (transfer criteria + approvalId)
Correct Categorization
Based on the proto definitions:
Action Permissions (only time control):
canDeleteCollection
(collection)canUpdateAutoApproveSelfInitiatedOutgoingTransfers
(user)canUpdateAutoApproveSelfInitiatedIncomingTransfers
(user)canUpdateAutoApproveAllIncomingTransfers
(user)
Timeline Permissions (timelineTimes + time control):
canArchiveCollection
canUpdateOffChainBalancesMetadata
canUpdateStandards
canUpdateCustomData
canUpdateManager
canUpdateCollectionMetadata
Timeline with Badge IDs (timelineTimes + badgeIds + time control):
canUpdateBadgeMetadata
Badge ID Action Permissions (badgeIds + time control):
canUpdateValidBadgeIds
Approval Permissions (transfer criteria + approvalId + time control):
canUpdateCollectionApprovals
(collection)canUpdateIncomingApprovals
(user)canUpdateOutgoingApprovals
(user)
Quick Examples
Lock Collection Deletion
When can the collection be deleted?
{
"canDeleteCollection": [
{
"permanentlyPermittedTimes": [],
"permanentlyForbiddenTimes": [
{ "start": "1", "end": "18446744073709551615" }
]
}
]
}
Freeze Badge Metadata
When can the badge metadata be updated? And which (badge IDs, timeline time) pairs does it apply to?
{
"canUpdateBadgeMetadata": [
{
"timelineTimes": [{ "start": "1", "end": "18446744073709551615" }],
"badgeIds": [{ "start": "1", "end": "100" }],
"permanentlyPermittedTimes": [],
"permanentlyForbiddenTimes": [
{ "start": "1", "end": "18446744073709551615" }
]
}
]
}
First Match Policy
Permissions are evaluated as a linear array where each element has criteria and time controls. Only the first matching element is applied - all subsequent matches are ignored.
Key Rules
First Match Only: Only the first element that matches all criteria is used
Deterministic State: Each criteria combination has exactly one permission state
No Overlap: Times cannot be in both
permanentlyPermittedTimes
andpermanentlyForbiddenTimes
Order Matters: Array order affects which permissions are applied
Example: Timeline Permissions
"canUpdateCollectionMetadata": [
{
"timelineTimes": [{ "start": "1", "end": "10" }],
"permanentlyPermittedTimes": [],
"permanentlyForbiddenTimes": [{ "start": "1", "end": "10" }]
},
{
"timelineTimes": [{ "start": "1", "end": "100" }],
"permanentlyPermittedTimes": [{ "start": "1", "end": "18446744073709551615" }],
"permanentlyForbiddenTimes": []
}
]
Result:
Timeline times 1-10: Forbidden (first element matches, second element does not)
Timeline times 11-100: Permitted (second element matches)
Satisfying Criteria
All criteria in a permission element must match for it to be applied. Partial matches are ignored.
Example: Badge Metadata Permissions
"canUpdateBadgeMetadata": [
{
"timelineTimes": [{ "start": "1", "end": "10" }],
"badgeIds": [{ "start": "1", "end": "10" }],
"permanentlyPermittedTimes": [{ "start": "1", "end": "18446744073709551615" }],
"permanentlyForbiddenTimes": []
}
]
This permission only covers:
Timeline times 1-10 AND badge IDs 1-10
It does NOT cover:
Timeline time 1 with badge ID 11
Timeline time 11 with badge ID 1
Timeline time 11 with badge ID 11
These combinations are unhandled and allowed by default since they do not match the permission criteria.
Brute Force Pattern
To lock specific criteria, you must specify the target and set all other criteria to maximum ranges.
Example: Lock Badge IDs 1-10
{
"fromListId": "All",
"toListId": "All",
"initiatedByListId": "All",
"badgeIds": [{ "start": "1", "end": "10" }],
"transferTimes": [{ "start": "1", "end": "18446744073709551615" }],
"ownershipTimes": [{ "start": "1", "end": "18446744073709551615" }],
"approvalId": "All",
"permanentlyPermittedTimes": [],
"permanentlyForbiddenTimes": [
{ "start": "1", "end": "18446744073709551615" }
]
}
Important Notes
First Match Policy: Only the first matching permission is applied
Default Allow: Unspecified permissions are allowed by default
Manager Required: Collection permissions require a manager
User Control: User permissions typically remain empty for full control
Brute Force: Use maximum ranges to ensure complete coverage
Order Matters: Array order affects permission evaluation
Last updated