Skip to content

Conversation

@bogwar
Copy link
Collaborator

@bogwar bogwar commented Feb 17, 2025

Fee collection in ICRC-based ledgers (e.g., ckBTC) is inconsistently implemented. While transfer transactions often incur fees, approve transactions typically do not. However, there is no standardized way to:

  • Define fee collection rules—who receives fees, which operations are charged, and whether fees are burned.
  • Record fee collection settings directly on-chain in ledger blocks.
  • Provide consistent semantics for wallets, explorers, and other integrations to interpret fee structures.

ICRC-107 extends ICRC-3, adding semantics for fee collection while ensuring full compatibility with the existing block format. This proposal eliminates reliance on off-chain metadata, simplifies integration with wallets and explorers, and ensures full transparency in fee handling.

Copy link
Contributor

@mbjorkqvist mbjorkqvist left a comment

Choose a reason for hiding this comment

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

Thanks for writing this up, @bogwar! I left a few clarifying questions/comments.

Comment on lines +257 to +258
- If the block is of type `2approve` then the fee is burned
- If the block is a transfer block, i.e. of type `1xfer` or `2xfer`:
Copy link
Contributor

Choose a reason for hiding this comment

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

Wrt. the recently proposed changes to ICRC-3 and allowing burn and mint blocks to also have fees, should this be extended to also explicitly mention 1burn and 1mint blocks?

The `tx` field for a `107feecol` block is a `Map` that contains the following fields:
| Field | Type (ICRC-3 `Value`) | Required | Description |
|-------------------|------------------------|----------|-------------|
| `op` | `Text` | Yes | MUST be `"107_set_fee_col"`. |
Copy link
Contributor

Choose a reason for hiding this comment

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

No underscore between the ICRC standard number and the op name as per the latest ICRC-3 revision draft (also in some examples below)?

Suggested change
| `op` | `Text` | Yes | MUST be `"107_set_fee_col"`. |
| `op` | `Text` | Yes | MUST be `"107set_fee_col"`. |

- The provided `Account` is invalid (e.g., the minting account on ledgers, anonymous principal, malformed principal or subaccount).
- The transaction is a duplicate (as determined by its tx hash when deduplication is enabled), resulting in a `SetFeeCollectorError::Duplicate`.
- The caller is not authorized to modify fee collector.
- The provided `Account` is invalid (e.g., the minting account on ledgers, anonymous principal, malformed principal or subaccount).
Copy link
Contributor

Choose a reason for hiding this comment

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

Are these invalid accounts just examples of what a ledger implementation may do, or is it normative behavior defined by the standard? If it's the latter, and we want to disallow setting some principals/accounts as the fee collector, I feel we should specify that where we define the fee collector (in the "Effective Fee" section?), rather than here where we list some examples for error cases. If it's the former, it would be good to clarify.

We discussed disallowed accounts/principals here, but I'm wondering if it makes sense to put any limits here after all? Could/should this not be a ledger implementation detail? We don't say anything in any standard about how the minting account is set, and/or if it can be changed. So even if we want to disallow having the fee collector being set to the minting account, it may be possible (in some conformant ledger implementation - the DFINITY implementation currently does not allow changing the minting account) to install the ledger with minting account M, set the ICRC-107 fee collector to account A, then change the minting account to account A.

I think we at some point discussed setting the fee collector to the anonymous principal as a way of "unsetting" the fee collector, but this is no longer the case. Whereas I can't think of any reasonable use cases where someone may want to set the fee collector to the anonymous principal, I'm also wondering whether or not prohibiting it in the standard is the best approach.

github-merge-queue bot pushed a commit to dfinity/ic that referenced this pull request Nov 25, 2025
Introduce the ICRC-107 fee collector operation to the ICRC ledger blocks
and implement handling of the operation in the ICRC index. Since the
ledger does not produce the new blocks yet, the index handling is tested
using the icrc3 test ledger. The blocks structure and handling is
implemented according the the ICRC-107 standard as defined in
dfinity/ICRC#117. Although the standard allows
for 107 blocks to skip the `tx` entirely, we require the `tx` and the
field `tx.op` to be present in the block.

---------

Co-authored-by: Mathias Björkqvist <[email protected]>
@bogwar bogwar requested a review from marc0olo December 1, 2025 13:18
mraszyk pushed a commit to dfinity/ic that referenced this pull request Dec 1, 2025
Introduce the ICRC-107 fee collector operation to the ICRC ledger blocks
and implement handling of the operation in the ICRC index. Since the
ledger does not produce the new blocks yet, the index handling is tested
using the icrc3 test ledger. The blocks structure and handling is
implemented according the the ICRC-107 standard as defined in
dfinity/ICRC#117. Although the standard allows
for 107 blocks to skip the `tx` entirely, we require the `tx` and the
field `tx.op` to be present in the block.

---------

Co-authored-by: Mathias Björkqvist <[email protected]>
@marc0olo marc0olo self-requested a review December 2, 2025 10:24
@gregorydemay gregorydemay merged commit afcda0b into main Dec 3, 2025
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants