Skip to content

Commit b2dc992

Browse files
bogwarclaude
andcommitted
refactor: generalize tx.op to method discriminator in ICRC-3
Replace hardcoded references to `tx.op` with the concept of a "method discriminator" — a field whose namespaced value uniquely identifies the standardized method that created a block. The recommended field name remains `op`, but standards MAY use alternatives (e.g., `mthd`) provided the choice is documented in the canonical `tx` mapping. This accommodates ICRC-107 which uses `tx.mthd` rather than `tx.op` as its method discriminator field, while preserving backward compatibility with legacy ICRC-1/2 blocks that use `tx.op`. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 6194432 commit b2dc992

1 file changed

Lines changed: 26 additions & 25 deletions

File tree

standards/ICRC-3/README.md

Lines changed: 26 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -259,11 +259,11 @@ Not all blocks contain a `tx` field, and not all blocks with a `tx` field corres
259259
For any ICRC standard that defines a **user-callable method which produces blocks**:
260260

261261
- Blocks produced by that method SHOULD include a `tx` field.
262-
- The `tx` field for such blocks SHOULD include an operation discriminator `op`.
263-
- The `op` value SHOULD be namespaced with the standard’s ICRC number
262+
- The `tx` field for such blocks SHOULD include a **method discriminator** — a field whose namespaced value uniquely identifies the standardized method that created the block. The recommended field name is `op`, but standards MAY use an alternative (e.g., `mthd`) provided the choice is documented in the method’s canonical `tx` mapping.
263+
- The discriminator value SHOULD be namespaced with the standard’s ICRC number
264264
(e.g., `122freeze_account`, `107set_fee_collector`) to avoid collisions with operations defined by other standards.
265265

266-
Typed blocks that **do not** represent method calls (e.g., upgrade markers, maintenance events, migration records, or system actions) MAY omit the `tx` field entirely and therefore MAY omit `tx.op`.
266+
Typed blocks that **do not** represent method calls (e.g., upgrade markers, maintenance events, migration records, or system actions) MAY omit the `tx` field entirely and therefore MAY omit the method discriminator.
267267

268268
Legacy ICRC-1/2 blocks continue to use their historical operation names (`"xfer"`, `"mint"`, `"burn"`, `"approve"`), and are exempt from namespacing requirements.
269269

@@ -273,7 +273,7 @@ Legacy ICRC-1/2 blocks continue to use their historical operation names (`"xfer"
273273
If a block represents the result of a **standardized user-initiated method call**, then:
274274

275275
- The block **SHOULD** include a `tx` field.
276-
- For user-initiated blocks, a namespaced `tx.op` **SHOULD** be included (see above).
276+
- For user-initiated blocks, a namespaced method discriminator **SHOULD** be included (see above).
277277
- The `tx` field MUST follow the canonical mapping defined by the method standard.
278278
Semantic fields required by the block type may appear **outside** `tx` when defined
279279
as top-level fields by the block-type specification (e.g., `fee`, `caller`).
@@ -283,12 +283,12 @@ If a block represents the result of a **standardized user-initiated method call*
283283
However:
284284

285285
- Blocks that are **not** created by user calls — such as system-generated blocks, upgrade or migration markers, or internal bookkeeping events — MAY omit the `tx` field entirely.
286-
- Typed blocks created by system logic MAY include a `tx` field without an `op`, or MAY use a `tx` whose structure is defined solely by the block type (`btype`) specification.
286+
- Typed blocks created by system logic MAY include a `tx` field without a method discriminator, or MAY use a `tx` whose structure is defined solely by the block type (`btype`) specification.
287287

288288
This distinction allows ICRC-3 to support both:
289289
- canonical, audit-ready records of user calls, and
290290
- domain-specific or system-generated events,
291-
without over-constraining block structure or requiring the presence of `tx` or `tx.op` in every block.
291+
without over-constraining block structure or requiring the presence of `tx` or a method discriminator in every block.
292292

293293

294294
### 5. Future-Proofing and Extensibility
@@ -567,13 +567,13 @@ A standard that defines a new block type MUST:
567567
- **Assign a unique `btype` string** for that block type.
568568
This identifier determines how the block is interpreted.
569569

570-
- **Not define or constrain `tx.op`**, because:
571-
- `tx.op` belongs to the standard that defines the *method* which creates the
570+
- **Not define or constrain the method discriminator** (e.g., `tx.op`, `tx.mthd`), because:
571+
- The method discriminator belongs to the standard that defines the *method* which creates the
572572
block, not to the block-type standard.
573573
- A single block type may be produced by multiple methods, potentially from
574574
different standards.
575575
- Some blocks (e.g., system-generated events or migration markers) do not
576-
include `tx.op` at all.
576+
include a method discriminator at all.
577577

578578
- **Specify the minimal structure** required to interpret the block and recover its
579579
semantic meaning.
@@ -622,10 +622,11 @@ A standard that defines a method which produces blocks MUST:
622622
populated, whether they live inside `tx` or at the top level.
623623
- Include only caller-provided optional fields in `tx`; omit optionals that were
624624
not supplied.
625-
- For methods that represent user-initiated calls, include an `op` field in
625+
- For methods that represent user-initiated calls, include a **method discriminator** field in
626626
`tx` (namespaced as described below) to identify the operation and avoid
627-
collisions.
628-
- Ensure that a namespaced `tx.op` **uniquely identifies the standardized
627+
collisions. The recommended field name is `op`, but standards MAY use an
628+
alternative (e.g., `mthd`) provided the choice is documented in the canonical `tx` mapping.
629+
- Ensure that the namespaced discriminator value **uniquely identifies the standardized
629630
method** that created the block within the ICRC namespace.
630631

631632
This division of responsibility ensures that:
@@ -634,37 +635,37 @@ This division of responsibility ensures that:
634635
- Methods define **how blocks are created** (intent capture).
635636
- Tooling and clients can rely on predictable, non-colliding `tx` values.
636637

637-
#### Namespacing for Operations
638+
#### Namespacing for Method Discriminators
638639

639640
The namespacing rules apply to **standards that define user-callable methods**, not to the
640641
standards that define block types.
641642

642-
If a standard defines a method that produces blocks, and those blocks include a `tx.op`,
643-
then:
643+
If a standard defines a method that produces blocks, and those blocks include a method
644+
discriminator in `tx` (whether named `op`, `mthd`, or otherwise), then:
644645

645-
- `tx.op` MUST be namespaced using the ICRC number of the **method’s standard**, not the
646+
- The discriminator value MUST be namespaced using the ICRC number of the **method’s standard**, not the
646647
block-type standard.
647-
- The value of `op` MUST uniquely identify the standardized method that created the
648+
- The discriminator value MUST uniquely identify the standardized method that created the
648649
block within the global ICRC namespace.
649650

650-
Formally:
651+
Formally, the discriminator value follows this grammar:
651652

652-
- `op = <method_standard_number><operation_name>`
653-
- `method_standard_number`: a non-zero digit followed by zero or more digits
653+
- `value = <method_standard_number><operation_name>`
654+
- `method_standard_number`: a non-zero digit followed by zero or more digits
654655
- `operation_name`: starts with a lowercase letter, then lowercase letters, digits,
655656
`_`, or `-`
656657

657-
**Examples**
658+
**Examples**
658659
If ICRC-107 defines a user-callable method `set_fee_collector`, and that method produces
659660
blocks of type `107feecol`, then:
660661

661-
- `btype = "107feecol"` is defined by the **block-type standard** (ICRC-107)
662-
- `tx.op = "107set_fee_collector"` is defined by the **method standard** (also ICRC-107)
662+
- `btype = "107feecol"` is defined by the **block-type standard** (ICRC-107)
663+
- `tx.mthd = "107set_fee_collector"` is defined by the **method standard** (also ICRC-107, using `mthd` as its discriminator field)
663664

664665
If a method in ICRC-122 produces blocks of type `122freeze`, then:
665666

666-
- `btype = "122freeze"`
667-
- `tx.op = "122freeze_account"`
667+
- `btype = "122freeze"`
668+
- `tx.op = "122freeze_account"` (using the default `op` discriminator field)
668669

669670
Legacy ICRC-1 and ICRC-2 blocks continue to use their historical operation names
670671
(`"xfer"`, `"mint"`, `"burn"`, `"approve"`) and are exempt from namespacing.

0 commit comments

Comments
 (0)