From f301c4faee84f32129ff90dfb64077d2b2d5d864 Mon Sep 17 00:00:00 2001 From: Marco Granelli Date: Wed, 21 May 2025 12:44:25 +0200 Subject: [PATCH 1/2] Updates specs for fee reserve account --- .../specs/pages/base-ledger/fee-system.mdx | 178 ++++++++++-------- 1 file changed, 101 insertions(+), 77 deletions(-) diff --git a/packages/specs/pages/base-ledger/fee-system.mdx b/packages/specs/pages/base-ledger/fee-system.mdx index 1a5960fb..e0a8a11c 100644 --- a/packages/specs/pages/base-ledger/fee-system.mdx +++ b/packages/specs/pages/base-ledger/fee-system.mdx @@ -11,16 +11,23 @@ block producers to add transactions to the blocks that they create and publish. Namada transaction fees can be paid in any fungible token that is a member of a whitelist controlled by Namada governance. Governance also sets minimum fee rates (which can be periodically updated so that they are usually sufficient) -that transactions must pay in order to be accepted. However, transactions can always pay -more to encourage the proposer to prioritize them. When using the shielded -pool, transactions can also unshield tokens in order to pay the required fees. +that transactions must pay in order to be accepted. However, transactions can +always pay more to encourage the proposer to prioritize them. When using the +shielded pool, transactions can also unshield tokens in order to pay the +required fees. The token whitelist consists of a list of $(T, GP_{min})$ pairs, where $T$ is a token identifier and $GP_{min}$ is the minimum (base) price per unit gas that must be paid by a transaction paying fees using that asset. This whitelist can -be updated with a standard governance proposal. All fees collected are paid -directly to the block proposer (incentive-compatible, so that side payments are -no more profitable). +be updated with a standard governance proposal. All fees collected are paid as +follows: + +- The base fee (i.e. the one up to the minimum gas price) is burnt if the fee + token is the native one or is sent to an internal reserve account if the fee + token is a foreign one +- The tip (the amount exceeding the minimum gas price) is always sent directly + to the block proposer, regardless of the fee token (incentive-compatible, so + that side payments are no more profitable) ## Fee payment @@ -41,65 +48,69 @@ block. Fees are not distributed among the validators who actively participate in the block validation process. This is because a tx submitter could be side-paying -the block proposer for tx inclusion, which would prevent the correct distribution -of fees among validators. The fair distribution of fees is enforced by the -stake-proportional block proposer rotation policy of CometBFT. +the block proposer for tx inclusion, which would prevent the correct +distribution of fees among validators. The fair distribution of fees is enforced +by the stake-proportional block proposer rotation policy of CometBFT. -By requesting an upfront payment, fees also serve as prevention against denial-of-service (DoS) -attacks since the signer needs to pay for all the submitted transactions. More -specifically, to serve as a DoS and spam prevention mechanism, the -fee system needs to enforce: +By requesting an upfront payment, fees also serve as prevention against +denial-of-service (DoS) attacks since the signer needs to pay for all the +submitted transactions. More specifically, to serve as a DoS and spam prevention +mechanism, the fee system needs to enforce: 1. **Successful** payment at block inclusion time (implying the ability to check the good outcome at block creation time) 2. Minimal payment overhead in terms of computation/memory requirements (otherwise fee payment itself could be exploited as a DoS vector) -The protocol executes the fee payment part of a transaction before any of the inner transactions that compose the batch. -By doing this, we make sure to prevent inner transactions from draining -the addresses of the funds needed to pay fees. The proposers will be able to -check in advance that fee payers have enough unshielded funds and, if this is -not the case, exclude the transaction from the block and leave it in the mempool -for future inclusion. This behavior ultimately leads to more resource-optimized -blocks. +The protocol executes the fee payment part of a transaction before any of the +inner transactions that compose the batch. By doing this, we make sure to +prevent inner transactions from draining the addresses of the funds needed to +pay fees. The proposers will be able to check in advance that fee payers have +enough unshielded funds and, if this is not the case, exclude the transaction +from the block and leave it in the mempool for future inclusion. This behavior +ultimately leads to more resource-optimized blocks. -As a drawback, this behavior could cause some inner txs to fail because funds have -been moved to the block proposer as a fee payment for another transaction included earlier in -the same block. This is somehow undesirable since inner transactions' execution -should have priority over the wrapper. There are two ways to overcome this -issue: +As a drawback, this behavior could cause some inner txs to fail because funds +have been moved to the block proposer as a fee payment for another transaction +included earlier in the same block. This is somehow undesirable since inner +transactions' execution should have priority over the wrapper. There are two +ways to overcome this issue: 1. Users are responsible for correctly timing/funding their transactions with the help of the wallet -2. Namada forces in protocol that a block should execute transactions right after the fee payment operation +2. Namada forces in protocol that a block should execute transactions right + after the fee payment operation If we follow the second option the block proposers will no more be able to optimize the block (this would require running the inner transactions to -calculate the possible new balance) and, inevitably, some wrapper -transactions for which fees cannot be paid will end up in the block. These will -be deemed invalid during validation so that the corresponding inner transaction -will not be executed, preserving the correctness of the state machine, but it -represents a slight underoptimization of the block and a potential vector for -DoS attacks since the invalid wrapper has allocated space and gas in the block -without being charged due to the lack of funds. Because of this, we stick to the -first option. +calculate the possible new balance) and, inevitably, some wrapper transactions +for which fees cannot be paid will end up in the block. These will be deemed +invalid during validation so that the corresponding inner transaction will not +be executed, preserving the correctness of the state machine, but it represents +a slight underoptimization of the block and a potential vector for DoS attacks +since the invalid wrapper has allocated space and gas in the block without being +charged due to the lack of funds. Because of this, we stick to the first option. Fees are collected via protocol for `WrapperTx`s that have been processed with success; this is to prevent a malicious block proposer from including transactions that are known in advance to be invalid just to collect more fees. -Note that in this case we imply the correctness of the transaction's `Header`, i.e. we make sure that this is correct with respect to the constraints that we impose on it, and we don't validate anything about the actual inner transactions that could end up failing. +Note that in this case we imply the correctness of the transaction's `Header`, +i.e. we make sure that this is correct with respect to the constraints that we +impose on it, and we don't validate anything about the actual inner transactions +that could end up failing. Since a signer might submit more than one transaction per block, the -`process_proposal` function needs to cache the updated balances to -correctly manage fees. +`process_proposal` function needs to cache the updated balances to correctly +manage fees. -For every transaction in the block, if enough funds are available, these are deducted from the storage -balances of the fee payers and directed to the balance of the block proposer. If -instead, the balance is not enough to cover fees, then the entire proposed block is -considered invalid and rejected, and a new CometBFT round is initiated. +For every transaction in the block, if enough funds are available, these are +deducted from the storage balances of the fee payers and directed to the balance +of the block proposer. If instead, the balance is not enough to cover fees, then +the entire proposed block is considered invalid and rejected, and a new CometBFT +round is initiated. -From the consensus block proposer's address (included in the CometBFT -request), it is possible to derive the relative Namada address for the payment. +From the consensus block proposer's address (included in the CometBFT request), +it is possible to derive the relative Namada address for the payment. The `Fee` field of `WrapperTx` is defined as follows: @@ -117,8 +128,10 @@ paid among those available in the token whitelist. At the same time, he also sets the amount which must meet the minimum price per gas unit for that token, $GP_{min}$ (also defined in the whitelist). The difference between the minimum and the actual value set by the submitter represents the incentive for the block -proposer to prefer the inclusion of this transaction over other ones. The block proposer can check the validity of these two parameters while -constructing the block. These validity checks are also replicated in `process_proposal` and `mempool_check`. +proposer to prefer the inclusion of this transaction over other ones. The block +proposer can check the validity of these two parameters while constructing the +block. These validity checks are also replicated in `process_proposal` and +`mempool_check`. Since the whitelist can be changed via governance, transactions could fail these checks in the block where the whitelist change happens. For `mempool_check`, the @@ -129,53 +142,63 @@ track any changes in these parameters and act accordingly. ### MASP fee payment -To provide improved data protection, Namada allows to unshield some funds on the go to cover the cost of the fee. This also -addresses a possible locked-out problem in which a user doesn't have enough -funds to pay fees (preventing any sort of operation on the chain). +To provide improved data protection, Namada allows to unshield some funds on the +go to cover the cost of the fee. This also addresses a possible locked-out +problem in which a user doesn't have enough funds to pay fees (preventing any +sort of operation on the chain). -When the transparent fee payment performed directly from the implicit address of the signer fails, the protocol tries to execute the first transaction of the batch: -if this is a **valid MASP transaction**, it then reattempts to perform the same exact transparent fee payment operation. -If it is successful, the transaction is accepted, otherwise it gets rejected (possibly the entire block is rejected if we are validating a new block). -So, essentially, MASP fee payment involves allowing the transaction to unshield some tokens to the balance of the fee payer to cover the missing amount. +When the transparent fee payment performed directly from the implicit address of +the signer fails, the protocol tries to execute the first transaction of the +batch: if this is a **valid MASP transaction**, it then reattempts to perform +the same exact transparent fee payment operation. If it is successful, the +transaction is accepted, otherwise it gets rejected (possibly the entire block +is rejected if we are validating a new block). So, essentially, MASP fee payment +involves allowing the transaction to unshield some tokens to the balance of the +fee payer to cover the missing amount. In case of an atomic batch the masp fee payment transaction will be committed even if the batch eventually fails. That is, all the state changes coming from the other inner transactions of the batch will be dropped (as per the default behavior of an atomic batch), but an exception will be made for the fee paying inner transaction that will instead be committed to storage to guarantee that fees are paid. -Since this operation comes before the actual payment, it can be exploited as a DoS vector. -To prevent this, the protocol enforces a maximum gas limit that can be used for this operation. -When the time comes, the protocol picks the gas limit for this operation as the minimum between the gas available to the transaction and the protocol parameter; -if the transaction runs out of gas, it gets discarded. If instead it gets applied correctly, the gas meter of the transaction accounts for the gas used and the execution proceeds. +Since this operation comes before the actual payment, it can be exploited as a +DoS vector. To prevent this, the protocol enforces a maximum gas limit that can +be used for this operation. When the time comes, the protocol picks the gas +limit for this operation as the minimum between the gas available to the +transaction and the protocol parameter; if the transaction runs out of gas, it +gets discarded. If instead it gets applied correctly, the gas meter of the +transaction accounts for the gas used and the execution proceeds. -The spending key(s) associated with this operation could be relative to any address -as long as the signature of the transfer itself is valid. +The spending key(s) associated with this operation could be relative to any +address as long as the signature of the transfer itself is valid. ### Governance proposals -Governance [proposals](../modules/governance.mdx) may carry some WASM code to -be executed in case the proposal passed. This code is embedded into a new transaction crafted directly by the validators at block processing time and is not -inserted into the block itself. These transactions are exempt from fees and +Governance [proposals](../modules/governance.mdx) may carry some WASM code to be +executed in case the proposal passed. This code is embedded into a new +transaction crafted directly by the validators at block processing time and is +not inserted into the block itself. These transactions are exempt from fees and don't charge gas. ### Protocol transactions Protocol transactions can only be correctly crafted by validators and serve a -role in allowing the chain to function properly. Thus, they are not -subject to fees and do not charge gas. +role in allowing the chain to function properly. Thus, they are not subject to +fees and do not charge gas. ## Gas accounting Gas must take into account the two scarce resources of a block: gas and space. -Regarding the space limit, Namada charges a fixed amount -of gas per byte for every transaction. +Regarding the space limit, Namada charges a fixed amount of gas per byte for +every transaction. The cost of a WASM tx/vp is given by the run time cost of it. In addition to these, each inner transaction spends gas for loading the WASM module from storage, compilation costs (of both the tx and the associated, non-native, VPs) which are charged even if the compiled transactions was already -available in cache, the calls to the exposed host functions and the sections of native vps that are more computationally complex. +available in cache, the calls to the exposed host functions and the sections of +native vps that are more computationally complex. To summarize, the gas for a given transaction can be computed as: @@ -197,16 +220,18 @@ Gas accounting is about preventing a transaction from exceeding two gas limits: The protocol injects a gas counter in each transaction and VP to be executed, which allows monitoring of the exact amount of gas utilized. -As soon as the gas limit defined in the transaction's header is exceeded, the transaction is immediately terminated and all the modifications applied to the WAL get discarded. +As soon as the gas limit defined in the transaction's header is exceeded, the +transaction is immediately terminated and all the modifications applied to the +WAL get discarded. ### Block GasLimit This constraint is given by the following two: -- The compliance of each inner transaction with the tx gas limit - explained in the previous section -- The compliance of the cumulative transactions' `GasLimit`s with the - maximum gas allowed for a block +- The compliance of each inner transaction with the tx gas limit explained in + the previous section +- The compliance of the cumulative transactions' `GasLimit`s with the maximum + gas allowed for a block CometBFT provides a `BlockSize.MaxGas` parameter, and applies some optional validation in mempool if this parameter is initialized. It doesn't instead @@ -222,9 +247,8 @@ exceeds the maximum amount of gas allowed, the validators will reject it. This section summarizes the checks performed in protocol. -| Method | Checks | If check fails | -| ------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------- | -| `CheckTx` and `ProcessProposal` | | Reject the block | -| `ProcessProposal` | | Reject the block | -| `FinalizeBlock` | | Reject the transaction and discard its modification to the state | - +| Method | Checks | If check fails | +| ------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------- | +| `CheckTx` and `ProcessProposal` | | Reject the block | +| `ProcessProposal` | | Reject the block | +| `FinalizeBlock` | | Reject the transaction and discard its modification to the state | From 73299d8948b6a2ce642f2da452b0a87d2169db1c Mon Sep 17 00:00:00 2001 From: Marco Granelli Date: Wed, 21 May 2025 15:13:32 +0200 Subject: [PATCH 2/2] Updates fee docs --- packages/docs/pages/users/fees.mdx | 210 +++++++++++++++++++++-------- 1 file changed, 151 insertions(+), 59 deletions(-) diff --git a/packages/docs/pages/users/fees.mdx b/packages/docs/pages/users/fees.mdx index 0b4e10b8..0bc33c13 100644 --- a/packages/docs/pages/users/fees.mdx +++ b/packages/docs/pages/users/fees.mdx @@ -2,17 +2,23 @@ import { Callout } from "nextra-theme-docs"; # Fees on Namada -In order to settle the market for Namada blockspace demand, fees are coupled with transactions. -In order for any namada transaction to be considered valid, the correct corresponding fee must be paid. -The exact fee is set by the user, and must be greater than or equal to the minimum `gas-price` set by governance, which is included in the genesis file under `gas_cost`. +In order to settle the market for Namada blockspace demand, fees are coupled +with transactions. In order for any namada transaction to be considered valid, +the correct corresponding fee must be paid. The exact fee is set by the user, +and must be greater than or equal to the minimum `gas-price` set by governance, +which is included in the genesis file under `gas_cost`. ## How fees are paid -Fees are **always** paid from the balance of an **implicit** address. When explicitly stated, the gas fee is paid by the `--gas-payer` flag. -If no `--gas-payer` flag is specified, the gas fee is paid by the first key in the `--signing-keys` flag, if those are specified. -If no `--signing-keys` flag is specified, the client will try to infer the signer from the source of the transaction and use that account as the fee payer. +Fees are **always** paid from the balance of an **implicit** address. When +explicitly stated, the gas fee is paid by the `--gas-payer` flag. If no +`--gas-payer` flag is specified, the gas fee is paid by the first key in the +`--signing-keys` flag, if those are specified. If no `--signing-keys` flag is +specified, the client will try to infer the signer from the source of the +transaction and use that account as the fee payer. + +First consider the example of a simple transfer: -First consider the example of a simple transfer: ```shell copy namadac transparent-transfer \ --source my-acc \ @@ -21,11 +27,16 @@ namadac transparent-transfer \ --amount 10 \ ``` -With no `--gas-payer` or `--signing-keys` explicitly provided, the client will infer the proper account related to `my-acc` from which to take the fees. -If `my-acc` is an implicit address, the fees will be taken directly from it. -If it is an established address, the fees will be taken from the implicit address associated with `my-acc` (usually the account used to initialize the established address). +With no `--gas-payer` or `--signing-keys` explicitly provided, the client will +infer the proper account related to `my-acc` from which to take the fees. If +`my-acc` is an implicit address, the fees will be taken directly from it. If it +is an established address, the fees will be taken from the implicit address +associated with `my-acc` (usually the account used to initialize the established +address). + +However, another gas payer can be specified in this transaction by providing +another implicit address for which the user owns the private key: -However, another gas payer can be specified in this transaction by providing another implicit address for which the user owns the private key: ```shell copy namadac transparent-transfer \ --source my-acc \ @@ -36,6 +47,7 @@ namadac transparent-transfer \ ``` Now consider the example of a transfer from a 2-of-n multisignature account: + ```shell copy namadac transparent-transfer \ --source my-multisig \ @@ -45,8 +57,10 @@ namadac transparent-transfer \ --signing-keys key1,key2 ``` -In this case, the fees will be taken from the first key provided to `--signing-keys`: `key1`. -As before, any gas payer can be specified by supplying the desired key to the `--gas-payer` argument like such: +In this case, the fees will be taken from the first key provided to +`--signing-keys`: `key1`. As before, any gas payer can be specified by supplying +the desired key to the `--gas-payer` argument like such: + ```shell copy namadac transparent-transfer \ --source my-multisig \ @@ -57,25 +71,34 @@ namadac transparent-transfer \ --gas-payer key2 ``` -For testnet purposes, we recommend [using the faucet](../networks/testnets/faucet.mdx) to source NAM for transaction fees. +For testnet purposes, we recommend +[using the faucet](../networks/testnets/faucet.mdx) to source NAM for +transaction fees. ## How fees are calculated -The fee for a transaction is calculated by multiplying `gas-limit` by the gas price. -Both the `--gas-limit` and the `--gas-price` can be specified by the user. If neither is specified, the default gas limit and minimum gas price is used. -The default gas limit for any transaction is currently set to `50_000`. +The fee for a transaction is calculated by multiplying `gas-limit` by the gas +price. Both the `--gas-limit` and the `--gas-price` can be specified by the +user. If neither is specified, the default gas limit and minimum gas price is +used. The default gas limit for any transaction is currently set to `50_000`. + +The minimum gas price is set in the genesis file under `minimum_gas_price`. One +can query the minimum gas prices for all tokens accepted for gas payment in a +network with: -The minimum gas price is set in the genesis file under `minimum_gas_price`. -One can query the minimum gas prices for all tokens accepted for gas payment in a network with: ```shell copy namadac query-protocol-parameters ``` ## How to set the gas price and gas limit -It is recommended to set the `gas-limit` based on the transaction being conducted. In order to estimate the `gas-limit` for a particular transaction, the `--dry-run-wrapper` argument should be provided. This means that the transaction is simulated, but not yet sent to the ledger. +It is recommended to set the `gas-limit` based on the transaction being +conducted. In order to estimate the `gas-limit` for a particular transaction, +the `--dry-run-wrapper` argument should be provided. This means that the +transaction is simulated, but not yet sent to the ledger. -For example, the following command will simulate a transfer transaction, and return the gas used: +For example, the following command will simulate a transfer transaction, and +return the gas used: ```shell copy namadac transfer \ @@ -87,12 +110,15 @@ namadac transfer \ --dry-run-wrapper ``` -Which will output something along the lines of +Which will output something along the lines of ```md -Dry-run result: Transaction consumed 14850 gas. Inner transaction was successfully applied. +Dry-run result: Inner transaction was successfully applied. The batch +consumed 14850 gas units. ``` -This means that we could reasonably make this transfer transaction with a `gas-limit` of 15000. + +This means that we could reasonably make this transfer transaction with a +`gas-limit` of 15000. Hence, when making the transfer, we could specify the `gas-limit` as follows: @@ -106,7 +132,8 @@ namadac transfer \ --gas-limit 15000 ``` -If for some reason, we wanted to pay a higher gas fee, we could also specify that as follows: +If for some reason, we wanted to pay a higher gas fee, we could also specify +that as follows: ```shell copy namadac transfer \ @@ -119,19 +146,40 @@ namadac transfer \ --gas-price 0.01 ``` -This **might** incentivise validators to prioritise this transaction above those with a lower gas price. +This **might** incentivise validators to prioritise this transaction above those +with a lower gas price. + +Finally, it is also possible to pay fees using a token different than the one +(possibly) involved in the transaction: + +```shell copy +namadac transfer \ + --source my-acc \ + --target validator-1 \ + --token NAM \ + --amount 10 \ + --gas-token transfer/channel-12/uatom \ + --signing-keys key1 \ +``` ## Paying fees with tokens in the MASP -It is also possible to pay for fees using the MASP when dealing with a transaction involving shielded inputs (shielded and unshielding transfers both natively and over IBC). -This is a good practice when trying to maximize data protection and minimize information leakage. +It is also possible to pay for fees using the MASP when dealing with a +transaction involving shielded inputs (shielded and unshielding transfers both +natively and over IBC). This is a good practice when trying to maximize data +protection and minimize information leakage. -When dealing with MASP fee payment, the client will first try to deduct the fees from the spending key specfied by `--gas-spending-key` of the shielded transaction and unshield them to the transparent balance of the `--gas-payer` (or the address corresponding to the first key in the `--signing-keys`). -Then, these fees are paid to the block proposer from the gas payer. +When dealing with MASP fee payment, the client will first try to deduct the fees +from the spending key specfied by `--gas-spending-key` of the shielded +transaction and unshield them to the transparent balance of the `--gas-payer` +(or the address corresponding to the first key in the `--signing-keys`). Then, +these fees are paid transparently from the gas payer. -For example, if the user has a spending key `spending-key-1` in their wallet, and they want to pay for the fees of a shielded transfer transaction using the MASP, they would run the following command: +For example, if the user has a spending key `spending-key-1` in their wallet, +and they want to pay for the fees of a shielded transfer transaction using the +MASP, they would run the following command: -```shell copy +```shell copy namadac transfer \ --source spending-key-1 \ --target payment-addr-b \ @@ -141,9 +189,11 @@ namadac transfer \ --gas-spending-key spending-key-1 ``` -If `spending-key-1` does not have enough balance or the user simply wants to use a separate key for gas, they can specify a different spending key for fee payment: +If `spending-key-1` does not have enough balance or the user simply wants to use +a separate key for gas, they can specify a different spending key for fee +payment: -```shell copy +```shell copy namadac transfer \ --source spending-key-1 \ --target payment-addr-b \ @@ -153,9 +203,13 @@ namadac transfer \ --gas-spending-key spending-key-2 ``` -In these examples, `my-implicit` may only have an OSMO balance in their transparent balance, but `spending-key-1` (or possibly `spending-key-2`) may have a positive NAM balance in their shielded balance. -In this case, the NAM will be unshielded to the transparent balance of `my-implicit` and then used to pay for the transaction fee. -So it is requried to unshield just the difference between the gas cost and the transparent balance of the gas payer implicit address. +In these examples, `my-implicit` may only have an OSMO balance in their +transparent balance, but `spending-key-1` (or possibly `spending-key-2`) may +have a positive NAM balance in their shielded balance. In this case, the NAM +will be unshielded to the transparent balance of `my-implicit` and then used to +pay for the transaction fee. So it is requried to unshield just the difference +between the gas cost and the transparent balance of the gas payer implicit +address. For an atomic batch, the masp fee payment transaction (the first one in the batch) is guaranteed to be committed even if the batch eventually fails. @@ -164,11 +218,16 @@ For an atomic batch, the masp fee payment transaction (the first one in the batc ### Using a disposable gas payer (recommended) It is also possible to use a disposable gas payer to pay for transaction fees. -This is useful (and recommended) in cases where the user does not want to leak information and reveal the identity of the `--gas-payer`. -In order to use a disposable gas payer, the user must include the `--disposable-gas-payer` flag. -The fees will be deducted from the shielded balance of the shielded transactions `--gas-spending-key` and unshielded to the transparent balance of an ephemeral transparent address before being paid by the ephemeral address. +This is useful (and recommended) in cases where the user does not want to leak +information and reveal the identity of the `--gas-payer`. In order to use a +disposable gas payer, the user must include the `--disposable-gas-payer` flag. +The fees will be deducted from the shielded balance of the shielded transactions +`--gas-spending-key` and unshielded to the transparent balance of an ephemeral +transparent address before being paid by the ephemeral address. -For example, if the user has the same two spending keys from the previous example in their wallet, and they want to pay for the fees of an unshield transaction using a disposable address, they would run the following command: +For example, if the user has the same two spending keys from the previous +example in their wallet, and they want to pay for the fees of an unshield +transaction using a disposable address, they would run the following command: ```shell copy namadac unshield \ @@ -182,27 +241,51 @@ namadac unshield \ ### MASP fee payment gas limit -To prevent spamming the network, the protocol establishes a maximum gas limit (`masp_fee_payment_gas_limit`) that can be used when fees are paid via the MASP (this limit applies to the gas used to run the transaction and the validity predicates but does not apply to the gas used by the wrapper transaction). It can be queried with: +To prevent spamming the network, the protocol establishes a maximum gas limit +(`masp_fee_payment_gas_limit`) that can be used when fees are paid via the MASP +(this limit applies to the gas used to run the transaction and the validity +predicates but does not apply to the gas used by the wrapper transaction). It +can be queried with: ```bash copy namadac query-protocol-parameters ``` -If the transaction exceeds this limit it won't be accepted; as such, the protocol sets a value that should allow for most transactions to be accepted. Should the user be in need to submit a more complex (and therefore gas-demanding) transaction, there are two ways around it, both taking advantage of the fact that the protocol gas limit only applies to the first transaction of the batch. - -1. The user can submit a batch of two transactions: the first one just unshields the necessary funds to pay fees for the entire batch, while the second transaction applies the desired transfer. -Since the protocol gas limit only applies to the first transaction of the batch (the one paying fees), the second transaction is free from this limit and can be as complex as required (within the size and gas limits of the entire block). - -2. The user can submit a first transaction paying fees via the MASP. This time though, the transaction unshields an amount that is enough to cover both the gas fees of itself and of the desired MASP transaction. -After this, the gas payer of the first transaction will still have a transparent balance large enough to cover fees for a second MASP transaction that actually performs the desired transfer and does not require any more fee unshielding. +If the transaction exceeds this limit it won't be accepted; as such, the +protocol sets a value that should allow for most transactions to be accepted. +Should the user be in need to submit a more complex (and therefore +gas-demanding) transaction, there are two ways around it, both taking advantage +of the fact that the protocol gas limit only applies to the first transaction of +the batch. + +1. The user can submit a batch of two transactions: the first one just unshields + the necessary funds to pay fees for the entire batch, while the second + transaction applies the desired transfer. Since the protocol gas limit only + applies to the first transaction of the batch (the one paying fees), the + second transaction is free from this limit and can be as complex as required + (within the size and gas limits of the entire block). + +2. The user can submit a first transaction paying fees via the MASP. This time + though, the transaction unshields an amount that is enough to cover both the + gas fees of itself and of the desired MASP transaction. After this, the gas + payer of the first transaction will still have a transparent balance large + enough to cover fees for a second MASP transaction that actually performs the + desired transfer and does not require any more fee unshielding. The first solution proposed above is currently not supported by the CLI client and requires direct usage of the SDK. -Each of these solutions has its own advanatages and drawbacks compared to the other one. -Using a single batch with two transactions allows for faster confirmation times and lower gas costs (since a batch will cost less than two separate transactions), but because of the way the SDK builds MASP transactions, it could fail sometimes (specifically the SDK invalidates notes that have been spent by the first transaction in the batch, which could cause a lack of funds for the second one). -Using two separate transactions instead avoids this issue (since the user can call `shielded-sync` after the first one to recollect all the available funds), but requires more gas overall and longer confirmation times. +Each of these solutions has its own advanatages and drawbacks compared to the +other one. Using a single batch with two transactions allows for faster +confirmation times and lower gas costs (since a batch will cost less than two +separate transactions), but because of the way the SDK builds MASP transactions, +it could fail sometimes (specifically the SDK invalidates notes that have been +spent by the first transaction in the batch, which could cause a lack of funds +for the second one). Using two separate transactions instead avoids this issue +(since the user can call `shielded-sync` after the first one to recollect all +the available funds), but requires more gas overall and longer confirmation +times. It is also possible, using either of the two solutions presented above, to use MASP fee payment to pay fees for non-MASP transactions. @@ -211,9 +294,13 @@ Please note that this is discouraged since it could establish a linkage between ## Having someone else to pay for tx gas fees -When, for example, you don't have enough balance left to cover transaction's gas fees, you can have someone else to wrap the raw transaction and submit it on your behalf. +When, for example, you don't have enough balance left to cover transaction's gas +fees, you can have someone else to wrap the raw transaction and submit it on +your behalf. -First, dump the raw transaction by adding `--dump-tx` flag and specify the `--gas-payer`'s public key and an `--output-folder-path` for the serialized tx. E.g.: +First, dump the raw transaction by adding `--dump-tx` flag and specify the +`--gas-payer`'s public key and an `--output-folder-path` for the serialized tx. +E.g.: ```shell copy namadac transparent-transfer \ @@ -235,7 +322,8 @@ namadac utils sign-offline \ --output-folder-path tx-dump-dir ``` -You can now pass on the serialized transaction (`\*.tx` file) and signature (`\offline_signature_*.sig`) to whoever is going to wrap it. +You can now pass on the serialized transaction (`\*.tx` file) and signature +(`\offline_signature_*.sig`) to whoever is going to wrap it. They can then wrap this tx and submit it to the chain with e.g.: @@ -246,7 +334,9 @@ namadac tx \ --gas-payer gas-payer-key ``` -They can also produce the wrapper signature offline if this is required. In this case, instead of the previous command, they should first wrap and dump the tx as follows: +They can also produce the wrapper signature offline if this is required. In this +case, instead of the previous command, they should first wrap and dump the tx as +follows: ```shell copy namadac tx \ @@ -257,7 +347,8 @@ namadac tx \ --output-folder-path tx-dump-dir ``` -This will generate a separate serialized transaction (`\*.tx` file). They can then produce the wrapper signature offline: +This will generate a separate serialized transaction (`\*.tx` file). They can +then produce the wrapper signature offline: ```shell copy namadac utils sign-offline \ @@ -266,11 +357,12 @@ namadac utils sign-offline \ --output-folder-path tx-dump-dir ``` -Which generates a serialized wrapper signature (`\offline_wrapper_signature_*.sig`). Finally they can submit the transaction with: +Which generates a serialized wrapper signature +(`\offline_wrapper_signature_*.sig`). Finally they can submit the transaction +with: ```shell copy namadac tx \ --tx-path wrapper_transaction.tx \ --gas-signature wrapper_signature.sig ``` -