Skip to content
Open
Changes from 1 commit
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
d8bbe07
account examples, no btype for legacy blocks
bogwar Jul 29, 2025
6e85916
Update standards/ICRC-3/README.md
bogwar Aug 6, 2025
ce7be73
Update standards/ICRC-3/README.md
bogwar Aug 6, 2025
c0201b0
added principles of recording transactions in blocks and extended Int…
bogwar Aug 15, 2025
d4d5856
introduced a section on kinds of blocks
bogwar Aug 15, 2025
825f3f1
added guideliness for defining blocks/cannonical mappings
bogwar Aug 15, 2025
1091df4
Merge branch 'bw/icrc-3update' of github.com:dfinity/ICRC-1 into bw/i…
bogwar Aug 15, 2025
9f7a603
core state transition, bypte vs tx
bogwar Aug 27, 2025
79018dc
typos
bogwar Sep 1, 2025
4e88917
minor changes
bogwar Sep 1, 2025
164f310
fixed some corner cases
bogwar Sep 3, 2025
ec99a9d
Update standards/ICRC-3/README.md
bogwar Sep 5, 2025
570e13c
timestampe is nanoseconds
bogwar Sep 5, 2025
797aa1d
Merge branch 'bw/icrc-3update' of github.com:dfinity/ICRC-1 into bw/i…
bogwar Sep 5, 2025
231779c
removed the consolidation section
bogwar Sep 5, 2025
d2e6f3e
clarified tx.op includes standard number
bogwar Sep 15, 2025
df78e30
promoted effective fee to a first class citizen; minor typos and rewr…
bogwar Sep 18, 2025
f4fd592
minor changes
bogwar Sep 18, 2025
35f2c3f
q-int's comment & fix transfer from based mints semantic
bogwar Sep 18, 2025
45a4b8e
make the standard about an event log
bogwar Oct 7, 2025
5d9c8d8
spelled out the generic aspect
bogwar Oct 7, 2025
6251107
language ledger agnonstic
bogwar Oct 8, 2025
f4a5211
relaxed core state transition
bogwar Oct 9, 2025
06ae958
relaxed the btype/tx recommmendations
bogwar Oct 9, 2025
1f12fa2
explicit demand that tx captures the user's call
bogwar Oct 9, 2025
85bf500
use producer canister throughout
bogwar Oct 9, 2025
dbbfcb4
added back
bogwar Oct 13, 2025
460bb51
semantics for top level ts
bogwar Oct 13, 2025
a96fbca
added one more example, removed a spurious line
bogwar Oct 16, 2025
f987387
Nat64 --> Nat
bogwar Oct 16, 2025
a495e4f
non-normative section with encodings of bools and optionals
bogwar Oct 16, 2025
71bda9d
draft methods section
bogwar Nov 19, 2025
abacc47
semantics for the remaining methods, small fixes
bogwar Nov 20, 2025
ef6013d
clearer gudiance on user calls, clearer language on icrc3_get_blocks …
bogwar Nov 21, 2025
a974a97
further clarifications on tx, tx.op etc
bogwar Nov 21, 2025
7fe04c6
refined Semantics of Blocks section
bogwar Nov 21, 2025
2476490
refined Namespacing for Operations
bogwar Nov 21, 2025
bb53670
removed duplicate sections
bogwar Nov 21, 2025
cd0374c
minor rewording
bogwar Nov 21, 2025
6194432
Candid spec
bogwar Nov 21, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 53 additions & 25 deletions standards/ICRC-3/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,63 +103,91 @@ digit = "0" / nonzero_digit
op_name = a-z *(a-z / digit / "_" / "-")
```

For instance, `1xfer` is the identifier of the ICRC-1 transfer operation.

## Supported Standards

An ICRC-3 compatible Ledger MUST expose an endpoint listing all the supported block types via the endpoint `icrc3_supported_block_types`. The Ledger MUST return only blocks with `btype` set to one of the values returned by this endpoint.

## [ICRC-1](../ICRC-1/README.md) and [ICRC-2](../ICRC-2/README.md) Block Schema

ICRC-1 and ICRC-2 use the `tx` field to store input from the user and use the external block to store data set by the Ledger. For instance, the amount of a transaction is stored in the field `tx.amt` because it has been specified by the user, while the time when the block was added to the Ledger is stored in the field `ts` because it is set by the Ledger.
This section describes how ICRC-1 and ICRC-2 operations are recorded in ICRC-3-compliant blocks.



### No `btype` Field
ICRC-1 and ICRC-2 blocks MUST NOT include a `btype` field. These standards use the legacy block format where the type of block is determined exclusively by the content of the `tx` field. ICRC-1 and ICRC-2 blocks use the `tx` field to store input from the user and use the external block to store data set by the Ledger. For instance, the amount of a transaction is stored in the field `tx.amt` because it has been specified by the user, while the time when the block was added to the Ledger is stored in the field `ts` because it is set by the Ledger.

#### Block Structure Requirements

A generic ICRC-1 or ICRC-2 Block:

- **MUST** use the legacy format, i.e., it **MUST NOT** include a `"btype"` field.
- **MUST** be a `Value::Map` containing at least the following fields:
- `"phash"`: `Blob` — the hash of the parent block.
- `"ts"`: `Nat` — the timestamp (set by the ledger at block creation).
- `"tx"`: `Value::Map` — representing the user’s transaction intent.
- **CAN** include:
- `"fee"`: `Nat` — only if the ledger requires a fee and the user did not specify one in `tx.fee`.


#### `tx` Field Semantics

The `tx` field:

- **MUST** represent the user intent derived from the method call.
- **MUST** be encoded using the ICRC-3 `Value` type.
- **MUST NOT** contain any fields that were not explicitly present in the original user call.
- **MUST** follow the canonical mapping rules described in the next section.





1. it MUST contain a field `ts: Nat` which is the timestamp of when the block was added to the Ledger
2. if the operation requires a fee and if the `tx` field doesn't specify the fee then it MUST contain a field `fee: Nat` which specifies the fee payed to add this block to the Ledger
3. its field `tx`
1. CAN contain a field `op: String` that uniquely defines the type of operation
1. MUST contain a field `op: String` that uniquely defines the type of operation
2. MUST contain a field `amt: Nat` that represents the amount
3. MUST contain the `fee: Nat` field for operations that require a fee if the user specifies the fee in the request. If the user does not specify the fee in the request, then this field is not set and the top-level `fee` is set.
4. CAN contain the `memo: Blob` field if specified by the user
5. CAN contain the `ts: Nat` field if the user sets the `created_at_time` field in the request.

Operations that require paying a fee: Transfer, and Approve.

The type of a generic ICRC-1 or ICRC-2 Block is defined by either the field `btype` or the field `tx.op`. The first approach is preferred, the second one exists for backward compatibility. If both are specified then `btype` defines the type of the block regardless of `tx.op`.

`icrc3_supported_block_types` should always return all the `btype`s supported by the Ledger even if the Ledger doesn't support the `btype` field yet. For example, if the Ledger supports mint blocks using the backward compatibility schema, i.e. without `btype`, then the endpoint `icrc3_supported_block_types` will have to return `"1mint"` among the supported block types.

### Account Type
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i still think it would be valuable to have a Principal variant in the Value. this way there is no ambiguity on how to interpret arrays


ICRC-1 Account is represented as an `Array` containing the `owner` bytes and optionally the subaccount bytes.
ICRC-1 Account is represented as an `Array` containing the `owner` bytes and optionally the subaccount bytes. Two examples of accounts, one with subaccount and the second without are below.

### Burn Block Schema
Example of account representation as an array with two blobs, one for the owner principal and the second for the subaccount:

1. the `btype` field MUST be `"1burn"` or `tx.op` field MUST be `"burn"`
2. it MUST contain a field `tx.from: Account`
```
variant { Array = vec {
variant { Blob = blob "\00\00\00\00\00\f0\13x\01\01" };
variant { Blob = blob "\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00" };
}};
```

Example with `btype`:

Example of account representation as an array with one blob encoding the owner principal.
```
variant { Map = vec {
record { "btype"; "variant" { Text = "1burn" }};
record { "phash"; variant {
Blob = blob "\a1\a9p\f5\17\e5\e2\92\87\96(\c8\f1\88iM\0d(tN\f4-~u\19\88\83\d8_\b2\01\ec"
}};
record { "ts"; variant { Nat = 1_701_108_969_851_098_255 : nat }};
record { "tx"; variant { Map = vec {
record { "amt"; variant { Nat = 1_228_990 : nat } };
record { "from"; variant { Array = vec {
variant { Blob = blob "\00\00\00\00\020\00\07\01\01" };
variant { Blob = blob "&\99\c0H\7f\a4\a5Q\af\c7\f4;\d9\e9\ca\e5 \e3\94\84\b5c\b6\97/\00\e6\a0\e9\d3p\1a" };
}}};
record { "memo"; variant { Blob = blob "\82\00\83x\223K7Bg3LUkiXZ5hatPT1b9h3XxJ89DYSU2e\19\07\d0\00"
variant { Array = vec {
variant { Blob = blob "\00\00\00\00\00\f0\13x\01\01" };

}};
}}};
}};
```

Example without `btype`:

### Burn Block Schema

1. the `btype` MUST not be set and `tx.op` field MUST be `"burn"`
2. it MUST contain a field `tx.from: Account`
3. it MUSAT contain a field `tx.amt: Nat`
4. it MUST contain a field `tx.memo` if the `icrc1_transfer` call that creates the block has a memo field, and its value is the value of that field.


```
variant { Map = vec {
record { "phash"; variant {
Expand Down
Loading