-
Notifications
You must be signed in to change notification settings - Fork 5
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
ICRC-107: standard for fee collector #117
base: main
Are you sure you want to change the base?
Conversation
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.
Thanks for writing this up, @bogwar! I left a few clarifying questions/comments.
ICRCs/ICRC-107/ICRC-107.md
Outdated
|
||
### 2.1 Overview | ||
|
||
For each block added to the ledger, some party must pay a fee. The amount and payer of the fee depend on the specific transaction type. |
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.
The fee may be set to 0
, in which case no party is paying a fee. Also, what if the fee collector is set to the minting account? Should that explicitly be forbidden, or should the standard say that setting the fee collector to the minting account is effectively a way to go back from collecting fees, to burning them, i.e., a way to unset the fee collector (which is otherwise currently not possible)?
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.
I think the minting account section of icrc1 would assume that the minting account would be burned: https://github.com/dfinity/ICRC-1/blob/main/standards/ICRC-1/README.md#minting-account-
There probably is no harm in mentioning it here as that would be expected behavior from icrc1
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.
Yes, good suggestion (to allow setting the fee collector to the minting account). I was thinking how to deal with going back to burning and this is the best idea.
ICRCs/ICRC-107/ICRC-107.md
Outdated
|
||
This ensures that existing tools and explorers relying on the current `fee_col` format remain functional. | ||
|
||
A block **MAY** include the following fields to define or update fee collection settings: |
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.
Why do we need 3 fields? Couldn't we just say if fee_col
is set, it receives the fee, otherwise fee is burned?
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.
For backwards compatibility: we have to deal with the case where fee_col
is set but we only collect for transfers.
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.
How about announcing the block number ranges which follow the standard in the icrc10_supported_standards
URL? Something like https://github.com/dfinity/ICRC/blob/main/ICRCs/ICRC-107.md#blockRange=[[123,)]
would mean that all blocks >= 123
would follow the standard. I think this would simplify implementation for clients because all you need to determine if a fee was burned or collected for a given block are the block ranges. You don't have to lookup fee collector settings from previous blocks.
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.
This would not allow to accurately calculate the balance of fee collectors (if they were set prior to the standard)
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.
@bogwar can you elaborate again on this a little bit? I kind of understand where we are coming from, but this seems super weird for somebody who is not aware of the history.
are there already past blocks that define the fee collector? does this apply for transfers and approvals?
is the full col_ops
list expected to be provided for each block type (transfer, approval, ...)? if so, it seems a little bit weird to provide this information in each block.
we should keep in mind that fee collection was not clearly specified in a standard before and that the behavior could generally differ among different implementations.
I would prefer the this standard to not rely on implementation specifics of the reference implementation. wouldn't it be better to just use the field fee_col
as @tmu0 initially proposed (ignoring the history), but document the historical behavior for the rust reference implementation?
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.
and document the semantics for legacy fields per Thomas' suggestion.
the semantics for the legacy fields would be documented in the ledger implementation, right? or also in this standard? 🤔
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.
I'll keep it part of the standard, otherwise it's going to be folklore that will get lost at some point. Do you see an issue with doing so?
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.
I definitely think it is important to be documented. I am not sure if this standard is the best place for that, but I also do not have a strong opinion on it. it just kind of feels wrong here.
maybe we should at least highlight that the legacy fee handling is specifically referring to the Rust implementation of DFINITY before ICRC-107 was introduced.
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.
@bogwar I read through it again and looks like I misunderstood you.
My preferred solution would be adding a new field icrc107_fee_col
to the block and not an entirely new block type for setting the fee collector. The idea is that if the ledger supports ICRC-107 he has to specify the field in each block that has a non-zero fee (even if the new field is empty) and in this case the legacy field fee_col
is ignored.
Why is this better IMO?
- self contained: Clients can determine the fee collector of every block without having to look at other blocks
- allows implementing flexible policies that scale: Ledgers can implement arbitrary complex fee collection logic, e.g., different fee collector for each trx type, round robin fee collection, etc, without having to worry about scalability (current approach would reuqire adding a
107feecol
block every time the FC changes)
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.
There are indeed advantages to have a field per block, but... in practice this would add a lot of redundant data per block for the benefit of very few clients of the ledger. Even in the previous incarnation, we used a field to point to the block where the fee collector was set. The saving was 8bytes vs 61bytes.
ICRCs/ICRC-107/ICRC-107.md
Outdated
|
||
- If `icrc107_fee_col` is set to a ledger account, that account collects all subsequent fees. | ||
- If `icrc107_fee_col` is set to the empty account (see below), the ledger burns all subsequent fees. | ||
- The most recent `icrc107_fee_col` setting applies to each block. |
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.
Could this be extended to be something like "An icrc107_fee_col
block configures the fee collection for all subsequent blocks, until superseded by another icrc107_fee_col
block"?
ICRCs/ICRC-107/ICRC-107.md
Outdated
- If `icrc107_fee_col` is set to a ledger account, that account collects all subsequent fees. | ||
- If `icrc107_fee_col` is set to the empty account (see below), the ledger burns all subsequent fees. | ||
- The most recent `icrc107_fee_col` setting applies to each block. | ||
- By default, the ledger burns all block fees until the first `icrc107_fee_col` setting is applied. If `icrc107_fee_col` has never been set, the ledger follows legacy `fee_col` logic (see Section 5). |
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.
This currently doesn't seem to cover the case where some legacy fee collection has been configured, and later an icrc107_fee_col
block is created - in particular, the fees for blocks before the icrc107_fee_col
block may have been collected according to the legacy logic.
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.
@mbjorkqvist do you mean that we should explicitly provide the information that there MIGHT be ledger (custom, non DFINITY) implementations out there where the legacy fee_col
logic in section 5 does not apply?
if so, I think we should say the ledger most likely burns all block fees ...
and elaborate more on that in section 5
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.
I was thinking about a ledger with the DFINITY legacy fee collector implementation, and then later implements ICRC-107 and adds an icrc107_fee_col
block. For this case, I feel this bullet point does not apply (since an icrc107_fee_col
block HAS been set), and therefore it's unclear whether section 5 applies to the pre-icrc107_fee_col
blocks or not.
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.
Yes, the wording is not good; let me rewrite it.
ICRCs/ICRC-107/ICRC-107.md
Outdated
|
||
### 3.1 `icrc107_set_fee_collection` | ||
|
||
This method allows a ledger controller to update the fee collection settings. It modifies the `icrc107_fee_col` account, which determines where collected fees are sent. The updated settings are recorded in the next block added to the ledger. |
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.
"The updated settings are recorded in the next block added to the ledger."
Since we are now proposing a new block type, it should be added to the ledger immediately as a result of a call to icrc107_set_fee_collection
, rather than having the new configuration added to the next (unrelated) block added to the ledger.
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.
Good point; i'll rewrite to state that it is recorded in a new block type
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.
I second that, but I assume this was just a wording/phrasing/interpretation issue.
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.
rewrote
|
||
### 5.1 Legacy Behavior (`fee_col`) | ||
|
||
- If `fee_col` is set in a block, the designated account collects only transfer fees (`1xfer`, `2xfer`). Fees for all other operations (e.g., `2approve`) were always burned in legacy behavior as implemented in Dfinity-maintained ICRC-3 ledgers. |
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.
Should we explicitly say that if fee_col
is not set, all fees are burned?
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.
I think that applies more to the next line (187) and should be added there
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.
I've reorganised the points to be more explicit. PTAL
ICRCs/ICRC-107/ICRC-107.md
Outdated
- If `fee_col` is set in a block, the designated account collects only transfer fees (`1xfer`, `2xfer`). Fees for all other operations (e.g., `2approve`) were always burned in legacy behavior as implemented in Dfinity-maintained ICRC-3 ledgers. | ||
- If `icrc107_fee_col` is not set, the ledger follows this legacy behavior, using `fee_col` only for transfers. | ||
|
||
New implementations SHOULD avoid using fee_col and instead use `icrc107_fee_col` for all fee collection settings. Legacy behavior is provided for backward compatibility only and MAY be deprecated in future versions of this standard. |
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.
New implementations SHOULD avoid using fee_col and instead use `icrc107_fee_col` for all fee collection settings. Legacy behavior is provided for backward compatibility only and MAY be deprecated in future versions of this standard. | |
New implementations SHOULD avoid using `fee_col` and instead use `icrc107_fee_col` for all fee collection settings. Legacy behavior is provided for backward compatibility only and MAY be deprecated in future versions of this standard. |
Co-authored-by: Mathias Björkqvist <[email protected]>
Co-authored-by: Mathias Björkqvist <[email protected]>
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.
@bogwar provided some additional comments
@mbjorkqvist thanks for the in-depth review 🙏
ICRCs/ICRC-107/ICRC-107.md
Outdated
- If `icrc107_fee_col` is set to a ledger account, that account collects all subsequent fees. | ||
- If `icrc107_fee_col` is set to the empty account (see below), the ledger burns all subsequent fees. | ||
- The most recent `icrc107_fee_col` setting applies to each block. | ||
- By default, the ledger burns all block fees until the first `icrc107_fee_col` setting is applied. If `icrc107_fee_col` has never been set, the ledger follows legacy `fee_col` logic (see Section 5). |
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.
@mbjorkqvist do you mean that we should explicitly provide the information that there MIGHT be ledger (custom, non DFINITY) implementations out there where the legacy fee_col
logic in section 5 does not apply?
if so, I think we should say the ledger most likely burns all block fees ...
and elaborate more on that in section 5
ICRCs/ICRC-107/ICRC-107.md
Outdated
|
||
### 3.1 `icrc107_set_fee_collection` | ||
|
||
This method allows a ledger controller to update the fee collection settings. It modifies the `icrc107_fee_col` account, which determines where collected fees are sent. The updated settings are recorded in the next block added to the ledger. |
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.
I second that, but I assume this was just a wording/phrasing/interpretation issue.
}; | ||
``` | ||
|
||
This method MUST only be callable by the ledger controller or authorized principals. Unauthorized calls SHOULD result in an error. |
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.
Unauthorized calls SHOULD result in an error.
SHOULD or MUST? 🤔
do we need to define the expected error, too?
|
||
### 5.1 Legacy Behavior (`fee_col`) | ||
|
||
- If `fee_col` is set in a block, the designated account collects only transfer fees (`1xfer`, `2xfer`). Fees for all other operations (e.g., `2approve`) were always burned in legacy behavior as implemented in Dfinity-maintained ICRC-3 ledgers. |
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.
I think that applies more to the next line (187) and should be added there
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.
Addressed most of the comments
ICRCs/ICRC-107/ICRC-107.md
Outdated
|
||
### 3.1 `icrc107_set_fee_collection` | ||
|
||
This method allows a ledger controller to update the fee collection settings. It modifies the `icrc107_fee_col` account, which determines where collected fees are sent. The updated settings are recorded in the next block added to the ledger. |
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.
Good point; i'll rewrite to state that it is recorded in a new block type
ICRCs/ICRC-107/ICRC-107.md
Outdated
- If `icrc107_fee_col` is set to a ledger account, that account collects all subsequent fees. | ||
- If `icrc107_fee_col` is set to the empty account (see below), the ledger burns all subsequent fees. | ||
- The most recent `icrc107_fee_col` setting applies to each block. | ||
- By default, the ledger burns all block fees until the first `icrc107_fee_col` setting is applied. If `icrc107_fee_col` has never been set, the ledger follows legacy `fee_col` logic (see Section 5). |
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.
Yes, the wording is not good; let me rewrite it.
ICRCs/ICRC-107/ICRC-107.md
Outdated
|
||
### 3.1 `icrc107_set_fee_collection` | ||
|
||
This method allows a ledger controller to update the fee collection settings. It modifies the `icrc107_fee_col` account, which determines where collected fees are sent. The updated settings are recorded in the next block added to the ledger. |
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.
rewrote
|
||
### 5.1 Legacy Behavior (`fee_col`) | ||
|
||
- If `fee_col` is set in a block, the designated account collects only transfer fees (`1xfer`, `2xfer`). Fees for all other operations (e.g., `2approve`) were always burned in legacy behavior as implemented in Dfinity-maintained ICRC-3 ledgers. |
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.
I've reorganised the points to be more explicit. PTAL
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:
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.