You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@@ -15,7 +15,7 @@ This proposal suggests an alternative mechanism where, instead of requiring an u
15
15
16
16
Dozer suggested an alternative to the HTR deposit requirement when minting tokens. The idea is to create a new type of custom token where tokens would be minted for free (i.e., no deposits) and fees would be charged for transactions. [RFC](https://github.com/Dozer-Protocol/hathor-rfcs/blob/new-token-economics/projects/new-token-economics/token-economics.md)
17
17
18
-
This change would reduce the upfront cost of minting tokens, making it more accessible to users who may not have sufficient HTR at the time of minting.
18
+
This change would reduce the upfront cost of minting tokens, making them more accessible to users who may not have sufficient HTR at the time of minting.
@@ -41,10 +41,17 @@ This proposal suggests **0.01 HTR per output**.
41
41
Apart from accepting HTR for fee payment, any deposit-based token will be accepted. In this case, since the token was created with a 100:1 ratio of HTR ([deposit model](#deposit-based-model-as-is)), the fee needs to be 100x the HTR rate. That means **0.01 HTR or 1.00 deposit-based-token**.
42
42
43
43
### Fee and melting operations
44
-
The fee will be charged before any melting operation and doesn't require any authority for it.
44
+
Melting tokens without authority is forbidden. Fee payments will be accepted as long as their total is exactly equal to the required fee. Any other case will be rejected.
45
+
46
+
In the examples below we'll use Fee-based Token (FBT), and Deposit-based Token (DBT) as our tokens.
47
+
48
+
To accept deposit tokens, the transaction should have an amount >= 100, for example:
49
+
50
+
Inputs: [100 FBT, 150 DBT]
51
+
Outputs: [100 FBT, 100 DBT]
52
+
Since 50 DBT represents an withdraw of 0 HTR, this operation should be blocked and considered an attempt to melt without an authority.
45
53
46
54
For instance, if there is a transaction with:
47
-
Fee-based Token (FBT), Deposit-based Token (DBT)
48
55
49
56
Inputs: [1000 FBT, FBT Melt Authority, 500 DBT]
50
57
Outputs: [500 FBT, 400 DBT]
@@ -58,84 +65,205 @@ For a combination of paying the fee and also melting the token, we'll have the f
58
65
59
66
Here, 100 DBT is used to pay the fee, and there is a melt of 500 FBT and 100 DBT. For melting tokens, the behavior remains the same, requiring authority.
60
67
68
+
### Fee and nano contracts
69
+
70
+
Based on this [issue](https://github.com/HathorNetwork/rfcs/issues/97), the items below will be charged **0.01 HTR** when dealing with Fee-based tokens.
71
+
-#### Sys-call
72
+
- create_fee_token
73
+
- mint_tokens
74
+
- melt_tokens
75
+
-#### Actions
76
+
- Deposit
77
+
- Withdraw
78
+
79
+
For transactions that are calling a Deposit/Withdraw action, they will be charged both from the outputs count and by the action cost. Nano contracts transferring funds between each other will pay fees based on the actions they might call.
80
+
81
+
Transaction depositing funds in a nano contract:
82
+
```
83
+
0.01 * len(outputs) + len(deposits)
84
+
```
85
+
If the same fee-based token is in the inputs but not in the outputs, we'll consider the same fee used for melting operations: 0.01 HTR (check [Fee cost](#fee-cost)).
86
+
87
+
Transaction withdrawing funds from a nano contract:
88
+
```
89
+
0.01 * len(outputs) + len(withdraws)
90
+
```
91
+
92
+
Nano contracts transferring funds within a nano contract:
93
+
```
94
+
0.01 * (len(deposits) + len(withdraws))
95
+
```
96
+
97
+
To demonstrate the above with an example we will consider:
98
+
- A nano contract (nc1) that is already initialized.
99
+
- The initial balance of the nc1 is 0.00 HTR.
100
+
- The `create_token` method always creates 5 million FBT.
101
+
- The `create_token` method always charges fees from its own balance.
102
+
- The `no_op` method does nothing.
103
+
- The nc1 doesn't call any other contract.
104
+
105
+
##### Creating a Fee-based token (FBT) - UTXO x Nano contract
106
+
```
107
+
Inputs: [100.02 HTR]
108
+
Outputs: [1MM FBT]
109
+
Nano header:
110
+
nc_id: nc1,
111
+
action: deposit (100.00 HTR), withdraw (1B FBT),
112
+
method: create_token
113
+
```
114
+
Fee:
115
+
- 0.01 HTR from the outputs count
116
+
- 0.01 HTR from the `withdraw` action
117
+
- 0.01 HTR from the `create_fee_token` sys-call <- charged from the contract's balance
118
+
Contract State:
119
+
- balance:
120
+
HTR: 99.99
121
+
FBT: 4 MM (million)
61
122
### Fee destination
62
123
63
124
The fees will be burned.
64
125
65
-
## Explorer
126
+
## Affected projects
127
+
128
+
The implementation in the following projects does not support fee payments with custom deposit-based tokens, although it will be available at the protocol level.
66
129
67
-
Add the fee field in the transaction view, and the token_info_version in the token creation transaction.
130
+
### Wallet-lib
68
131
69
-
## Wallet (desktop, mobile, wallet-lib)
132
+
This project handles methods that are responsible for preparing a transaction and choosing UTXOs that will serve as inputs. That said, with the Fee-based token version, those methods need to be refactored to handle it and prepare the UTXOs according to the requirements described in this document.
70
133
71
-
Since Hathor has an easy-to-use approach, we should provide users the option to select between the two models (deposit and fee) when minting. Also, in the wallet, we should always require fee payment in HTR to incentivize HTR demand.
134
+
#### Wallet-service
72
135
73
-
**At the protocol level, other tokens are accepted**.
136
+
The wallet service has its own database with the token details data stored. It will be necessary to add the token `version` field introduced by this document, since before it wasn't used and was hardcoded.
137
+
### Explorer
138
+
139
+
The Explorer service ingestors are prepared to bring all columns from the wallet-service database into Elasticsearch, where they will be used by the Explorer service to provide data for the token detail API. We will update the token list view, token detail view, and transaction detail view by adding fee data and token version descriptions.
140
+
141
+
#### Wallet-headless
142
+
143
+
This is the official headless wallet of Hathor. There we'll need to update the create tokens methods (utxo and nano) arguments to support the new token version.
144
+
145
+
#### Rpc-lib
146
+
147
+
The rpc lib acts as a bridge between the wallet-lib and the desktop and mobile clients. It's required to update the create tokens handlers (utxo and nano) to accept the token version argument.
148
+
149
+
### Wallet (desktop, mobile)
150
+
151
+
The wallets will have a new create token experience. It will allow the user to choose between the tokens versions (deposit or fee based), see the fees and check the token detail data.
152
+
153
+
Also, we'll provide information about the transaction fee while approving a transaction and before sending it. The user will be able to check the paid fee in the transaction detail screen, similar to explorer.
In this section, technical details are expanded for what was described above.
79
159
80
-
## Token info version
81
-
Given Hathor's [Anatomy of a Transaction RFC](https://github.com/HathorNetwork/rfcs/blob/master/text/0015-anatomy-of-tx.md#token-creation), it is reasonable to suggest that the byte used by the token creation transaction `token_info_version` will be used to determine fee-created tokens.
160
+
## Token info version (aka Token Version)
161
+
Given Hathor's [Anatomy of a Transaction RFC](https://github.com/HathorNetwork/rfcs/blob/master/text/0015-anatomy-of-tx.md#token-creation), it is reasonable to suggest that the byte used by the token creation transaction `token_info_version` will be used to determine fee-based tokens.
82
162
83
163
Since each custom token `id` is the hash of the token creation transaction that created it, we can assume the enum values below can be assigned to the `token_info_version` byte in the token creation tx and then we can retrieve it.
84
164
85
-
So, by adding a TokenInfoVersion enum we have:
165
+
So, by adding a TokenVersion enum we have:
166
+
- NATIVE = 0 (internal)
86
167
- DEPOSIT = 1 (as is)
87
168
- FEE = 2
88
169
89
170
Then, we must allow the versions above in the `deserialize_token_info` method by checking the enum values.
90
171
91
-
## Transaction token_dict
92
-
From the section above, we know how to differentiate between deposit and fee tokens. Based on that, we need to add the input and output data to the current `token_dict` in order to calculate the outputs and check for melting operations without outputs.
172
+
## Transaction class
173
+
174
+
Inside the transaction class we can obtain a dictionary `token_dict: dict[TokenUid, TokenInfo]` which is generated by the `get_complete_token_info()` method. This method iterates over the inputs and the outputs consolidating the amount, and checking the authorities of each token. To determine the token info it requires checking the spent txs and fetching the spent outputs for each token input.
93
175
94
-
## Fee (fee.py)
95
-
This new file is responsible for keeping the fee logic, but not for orchestrating it; this will be done in the transaction verifier.
176
+
With the spent outputs and the authorities in hand we can define which of them are what we call `chargeable_outputs` (non authority outputs).
96
177
97
-
The `should_charge_fee` method will check if the transaction has any fee-based input or output and if the `FEE_FEATURE_FLAG` is enabled.
178
+
By creating `TokenInfoDict` class, that extends `dict[TokenUid, TokenInfo]`, we add two counters: chargeable_outputs and chargeable_spent_outputs. Since the previous token_dict iterates over the outputs as said before, incrementing the counters here saves resources by avoiding the need to retrieve the information elsewhere.
98
179
99
-
The `calculate_fee` method will receive a `token_dict` as input, then count the fee-based non-authority outputs and apply a constant value `FEE_OUTPUT_VALUE` to each, returning the total fee in HTR.
180
+
##### Calculate fee method:
181
+
With the counters in hand we just need to add a method to calculate the fee, below is the method implementation:
100
182
101
-
It will consider 1 output for melting operations that don't have any output.
The `collect_fee` method will receive the `token_dict` and the fee. It will use the differences between the input and output amounts and return the paid fee in HTR. For each token that has a difference, it will collect the fee by incrementing the amount value in the corresponding `token_dict` entry.
193
+
As mentioned in the [fee cost](#fee-cost) section:
194
+
>"For melting operations that don't contain any outputs, we'll count them as 1 output in the fee calculation."
105
195
106
196
## Transaction verifier
107
197
108
-
### verify_fee()
109
-
Inside the transaction verifier, the `verify_fee` method will be added. It's responsible for orchestrating the fee flow by checking if the fee should be charged, calculating it, and checking the payment availability:
198
+
### verify_sum()
199
+
200
+
With the new `TokenVersion` enum and the `calculate_fee` from the `token_dict` we'll be able to distinguish between fee and deposit based tokens.
201
+
202
+
From this point we'll accept an imbalance of HTR and deposit-based tokens; they should be used to pay fees.
203
+
204
+
As mentioned in the guide-level explanation:
205
+
> Melting tokens without authority is forbidden. Fee payments will be accepted as long as their total is exactly equal to the required fee. Any other case will be rejected.
206
+
207
+
The expected htr amount should be calculated this way:
110
208
111
-
Example:
112
209
```python
113
-
ifnot should_charge_fee(token_dict):
114
-
return
115
-
116
-
fee = calculate_fee(token_dict)
117
-
paid_fee = collect_fee(token_dict)
118
-
119
-
if fee - paid_fee >0:
120
-
raise InputOutputMismatch(
121
-
'HTR or deposit tokens are not enough to pay the fee. (amount={}, expected={})'.format(
withdraw: amount of HTR resulting from melting deposit-based tokens with authority
215
+
withdraw_without_authority: amount of HTR resulting from melting deposit-based tokens without authority
216
+
deposit: required amount in HTR for minting deposit-based tokens with authority
217
+
218
+
While iterating over the tokens in the tx we should consider:
219
+
220
+
Deposit tokens:
221
+
- It should sum all the deposit based tokens withdraws with melt authority
222
+
- It should sum all the deposit-based tokens withdrawals without a melt authority:
223
+
- When the token amount * 0.01 (deposit rate) is not an integer, it will be **treated as an attempt to melt without an authority**.
224
+
- For example, `99 DBT` doesn't represent `1 HTR` and an `InputOutputMismatch` error will be raised.
225
+
- Also, `101 DBT` and `199 DBT` represent `1 HTR` and an `InputOutputMismatch` error will be raised, blocking the melting.
226
+
- It will **reject** any deposit-based token which tries to **mint without an authority**.
227
+
- It'll **reject** if the sum of the **withdrawals without an authority** is **higher than** the `fee`. If this validation fails, an `InputOutputMismatch` error will be raised.
228
+
229
+
For fee tokens:
230
+
- It will reject any Fee-based token which tries to **mint** or **melt** without an authority.
231
+
232
+
Let's use the same example from the guide-level explanation using the following tokens: Deposit-Based Token (DBT), and Fee-Based Token (FBT).
Since we already normalized the `token_dict` values in the `verify_fee` method before calling this one, we just need to adjust the withdraw and deposit amounts here, collecting only for deposit tokens.
130
257
131
258
## Feature flag in settings
132
-
For development purposes, this feature will be feature-flagged to run only on the local network by setting the `FEE_FEATURE_FLAG` in settings to true.
259
+
For development purposes, this feature will be feature-flagged to run only on the local network by setting the `ENABLE_FEE_TOKENS` in settings to true.
133
260
134
261
## Feature activation
135
262
For production, we'll rely on feature activation to release this feature.
136
263
137
-
## Transaction fee resource
138
-
Add an endpoint to calculate fees based on the inputs and outputs, in order to expose the logic used in the transaction verifiers to the wallets.
264
+
## Transaction resource
265
+
266
+
We should provide a field with the tx fee and the token version in the detailed response.
139
267
140
268
# Drawbacks
141
269
@@ -164,9 +292,8 @@ The Base Fee is burned, reducing the Ether supply, while the Priority Tip goes t
164
292
# Unresolved questions
165
293
[unresolved-questions]: #unresolved-questions
166
294
167
-
- How should melt operations be handled for fee-based custom tokens?
168
-
-~~How will fee adjustments be governed?~~
169
-
- By removing the transaction fee from mining, how will it affect the tx-mining-service?
295
+
-~~How should melt operations be handled for fee-based custom tokens?
296
+
-~~How will fee adjustments be governed?
170
297
171
298
# Future possibilities
172
299
[future-possibilities]: #future-possibilities
@@ -182,3 +309,5 @@ The Base Fee is burned, reducing the Ether supply, while the Priority Tip goes t
0 commit comments