-
Notifications
You must be signed in to change notification settings - Fork 7
ICRC-124: blocks for recording management actions -- stopping, unstopping and deactivating ledgers #135
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
bogwar
wants to merge
9
commits into
main
Choose a base branch
from
bw/icrc-124
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
ICRC-124: blocks for recording management actions -- stopping, unstopping and deactivating ledgers #135
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
346ec7f
initial draft
bogwar 52d2660
example blocks
bogwar 735d4de
example names
bogwar baa31db
appended -> recorded
bogwar 4180d2b
consistent intro
bogwar 161de42
memo -> reason
bogwar 0ad037d
more relaxed semantics
bogwar 124a173
added caller to the tx, adapted the examples, refined semantics for s…
bogwar a5e8887
alignment with the new ICRC-3 version
bogwar File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,198 @@ | ||
# ICRC-124: Ledger Pausing, Unpausing, and Deactivation | ||
|
||
## Status | ||
|
||
Draft | ||
|
||
## Introduction | ||
|
||
This standard defines new block types for recording administrative actions that control the operational state of an ICRC-compliant ledger: pausing (`124pause`), unpausing (`124unpause`), and deactivating (`124deactivate`). These actions allow ledger operations to be temporarily halted (e.g., for maintenance), resumed, or permanently stopped (making the ledger immutable). This standard provides a consistent, auditable way to represent these ledger-wide state transitions within the ledger's block history, ensuring transparency and enabling robust governance mechanisms. | ||
|
||
## Motivation | ||
|
||
Ledger lifecycle management may require administrative actions like pausing for upgrades, unpausing after checks, or deactivating at the end of a token's useful life. These significant events must be recorded transparently on-chain. This standard provides explicit block types for these actions, defining a minimal block structure sufficient for semantics, while allowing optional provenance for auditability. | ||
|
||
## Common Elements | ||
|
||
This standard follows the conventions set by ICRC-3, inheriting key structural components: | ||
|
||
- **Principals** are represented using the ICRC-3 `Value` type as `variant { Blob = <principal_bytes> }`. | ||
- **Timestamps:** `ts` (and any optional `created_at_time`) are **nanoseconds since the Unix epoch**, encoded as `Nat` but **MUST fit into `nat64`**. | ||
- **Parent hash:** `phash : Blob` **MUST** be present if the block has a parent (omit for the genesis block). | ||
|
||
## Block Types & Schema | ||
|
||
Each block introduced by this standard MUST include a `tx` field containing a map. This map encodes the **minimal information** about the ledger state change. Additional provenance MAY be included but is not required for semantics. | ||
|
||
Each block consists of the following top-level fields: | ||
|
||
| Field | Type (ICRC-3 `Value`) | Required | Description | | ||
|-------|------------------------|----------|-------------| | ||
| `btype` | `Text` | Yes | MUST be one of: `"124pause"`, `"124unpause"`, or `"124deactivate"`. | | ||
| `ts` | `Nat` | Yes | Timestamp (ns since Unix epoch) when the block was added to the ledger. MUST fit in `nat64`. | | ||
| `phash` | `Blob` | Yes/No | Hash of the parent block; omitted only for the genesis block. | | ||
| `tx` | `Map(Text, Value)` | Yes | Minimal operation details (see below). | | ||
|
||
### `tx` Field Schema (minimal) | ||
|
||
For all `124pause`, `124unpause`, and `124deactivate` blocks: | ||
|
||
- No required fields are needed for semantics. | ||
- The presence of the block type alone (`btype`) determines the state transition. | ||
|
||
### Optional Provenance (non-semantic) | ||
|
||
Producers MAY include fields such as: | ||
|
||
- `caller : Blob` — principal that invoked the operation. | ||
- `reason : Text` — human-readable context. | ||
- `created_at_time : Nat` — caller-supplied timestamp (ns; MUST fit nat64). | ||
- `policy_ref : Text` — identifier for proposal/vote/policy. | ||
- `op : Text` — namespaced operation identifier, e.g. `148pause_ledger`. | ||
|
||
These fields MUST NOT affect semantics or verification. Verifiers MUST ignore them. | ||
|
||
> **Informative note (recoverability):** Implementations **SHOULD** provide mechanisms (e.g., archives or lookups) to retrieve extended invocation context not present in `tx` when useful for audits. The authorization model that permits these actions is implementation-defined. | ||
|
||
--- | ||
|
||
## Semantics | ||
|
||
### Pause Ledger (`124pause`) | ||
- When a `124pause` block is recorded, the ledger MUST enter a "paused" state. | ||
- While paused, the ledger MUST reject all state-changing operations except those required for governance or recovery (e.g., `124unpause`, optionally `124deactivate`, and operations like freeze/unfreeze if permitted by governance policy). | ||
- Query calls SHOULD remain operational. | ||
|
||
### Unpause Ledger (`124unpause`) | ||
- When a `124unpause` block is recorded, the ledger MUST exit the "paused" state and resume normal operation, unless it is already in the terminal state due to deactivation. | ||
- An `124unpause` block has no effect if the ledger is already unpaused or deactivated. | ||
|
||
### Deactivate Ledger (`124deactivate`) | ||
- When a `124deactivate` block is recorded, the ledger MUST transition to a permanent "terminal" state. | ||
- In this state: | ||
- All ingress calls that modify state MUST be rejected (transfers, approvals, mints, burns, freezes, pauses, unpauses, etc.). | ||
- Query calls retrieving historical data MUST remain available. | ||
- The deactivated state is irreversible. | ||
|
||
--- | ||
|
||
## Guidance for Standards That Define Methods | ||
|
||
A standard that defines ledger methods which produce ICRC-124 blocks (e.g., “pause ledger” or “deactivate ledger”) SHOULD: | ||
|
||
1. **Include `tx.op`** in the resulting block’s `tx` map. | ||
- Use a namespaced value per ICRC-3: `<icrc_number><op_name>` (e.g., `148pause_ledger`). | ||
- This makes the call uniquely identifiable and prevents collisions across standards. | ||
|
||
2. **Define a canonical mapping** from the method’s call parameters to the block’s minimal `tx` fields. | ||
- Since 124 blocks have no required fields, only provenance may be mapped. | ||
|
||
3. **Document deduplication inputs** (if any). If the method uses a caller-supplied timestamp, put it in `tx.created_at_time`. | ||
|
||
--- | ||
|
||
## Compliance Reporting | ||
|
||
Ledgers implementing this standard MUST return the following entries (along with entries for other supported block types) from `icrc3_supported_block_types`: | ||
|
||
```candid | ||
vec { | ||
record { block_type = "124pause"; url = "https://github.com/dfinity/ICRC/blob/main/ICRCs/ICRC-124.md" }; | ||
record { block_type = "124unpause"; url = "https://github.com/dfinity/ICRC/blob/main/ICRCs/ICRC-124.md" }; | ||
record { block_type = "124deactivate"; url = "https://github.com/dfinity/ICRC/blob/main/ICRCs/ICRC-124.md" }; | ||
} | ||
``` | ||
|
||
## Example Blocks | ||
|
||
### 124pause Example | ||
|
||
```candid | ||
variant { Map = vec { | ||
// Block type identifier | ||
record { "btype"; variant { Text = "124pause" }}; | ||
|
||
// Timestamp when the block was recorded (nanoseconds since epoch) | ||
record { "ts"; variant { Nat = 1_747_774_560_000_000_000 : nat }}; // Example: 2025-05-19T12:56:00Z | ||
|
||
// Hash of the previous block in the ledger chain | ||
record { "phash"; variant { | ||
Blob = blob "\de\ad\be\ef\00\11\22\33\44\55\66\77\88\99\aa\bb\cc\dd\ee\ff\10\20\30\40\50\60\70\80\90\a0\b0\c0" | ||
}}; | ||
|
||
// Pause transaction details | ||
record { "tx"; variant { Map = vec { | ||
// The principal that invoked the pause_ledger operation | ||
record { "caller"; variant { Blob = blob "\00\00\00\00\00\00\f0\0d\01\03" }}; // Example caller principal (e.g., a governance canister) | ||
// Optional reason | ||
record { "reason"; variant { Text = "DAO vote #78: pause for scheduled maintenance." }}; | ||
}}}; | ||
}}; | ||
|
||
``` | ||
|
||
### 124unpause Example | ||
|
||
```candid | ||
variant { Map = vec { | ||
record { "btype"; variant { Text = "124unpause" }}; | ||
record { "ts"; variant { Nat = 1_747_778_160_000_000_000 : nat }}; // Example: 2025-05-19T13:56:00Z | ||
record { "phash"; variant { | ||
Blob = blob "\be\ba\fe\ca\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\10\11\12\13\14\15\16\17\18\19\1a\1b" | ||
}}; | ||
// Unpause transaction details | ||
record { "tx"; variant { Map = vec { | ||
// The principal that invoked the unpause_ledger operation | ||
record { "caller"; variant { Blob = blob "\00\00\00\00\00\00\f0\0d\01\03" }}; // Example caller principal | ||
// Optional reason | ||
record { "reason"; variant { Text = "Ledger resumes after maintenance window (DAO vote #79)." }}; | ||
}}}; | ||
}}; | ||
``` | ||
|
||
### 124deactivate Example | ||
|
||
```candid | ||
variant { Map = vec { | ||
record { "btype"; variant { Text = "124deactivate" }}; | ||
record { "ts"; variant { Nat = 1_747_864_560_000_000_000 : nat }}; // Example: 2025-05-20T12:56:00Z | ||
record { "phash"; variant { | ||
Blob = blob "\c0\ff\ee\00\10\20\30\40\50\60\70\80\90\a0\b0\c0\d0\e0\f0\00\11\22\33\44\55\66\77\88\99\aa\bb\cc" | ||
}}; | ||
// Deactivate transaction details | ||
record { "tx"; variant { Map = vec { | ||
// The principal that invoked the deactivate_ledger operation | ||
record { "caller"; variant { Blob = blob "\00\00\00\00\00\00\f0\0d\01\04" }}; // Example caller (e.g., project multisig or final DAO vote) | ||
// Optional reason | ||
record { "reason"; variant { Text = "Token project sunset. Ledger permanently archived as per SNS DAO proposal #314." }}; | ||
}}}; | ||
}}; | ||
|
||
``` | ||
|
||
### Informative Example: Integration with a Standardized Method | ||
ICRC-124 defines only block types and their semantics. It does not define any ledger methods. | ||
However, future standards may specify methods that map directly to these block types. | ||
|
||
For illustration, suppose a future standard (e.g., ICRC-148) introduces the method: | ||
``` | ||
icrc148_pause_ledger : (opt text) -> result nat | ||
``` | ||
|
||
Invoking this method with an optional reason could produce a `124pause` block: | ||
``` | ||
variant { Map = vec { | ||
record { "btype"; variant { Text = "124pause" }}; | ||
record { "ts"; variant { Nat = 1_747_900_000_000_000_000 : nat }}; | ||
record { "phash"; variant { | ||
Blob = blob "\aa\bb\cc\dd\ee\ff\00\11\22\33\44\55\66\77\88\99" | ||
}}; | ||
record { "tx"; variant { Map = vec { | ||
record { "op"; variant { Text = "148pause_ledger" }}; | ||
record { "caller"; variant { Blob = blob "\00\00\00\00\00\00\f0\0d\01\03" }}; | ||
record { "reason"; variant { Text = "DAO vote #101: emergency pause" }}; | ||
}}}; | ||
}}; | ||
``` | ||
|
||
This example is non-normative and illustrates how a standardized method can map into the ICRC-124 block structure while using a namespaced `tx.op` for unambiguous identification. The authoritative semantics remain defined by the ICRC-124 block types. |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.