github.com/cosmos/cosmos-sdk@v0.50.10/docs/architecture/adr-029-fee-grant-module.md (about)

     1  # ADR 029: Fee Grant Module
     2  
     3  ## Changelog
     4  
     5  * 2020/08/18: Initial Draft
     6  * 2021/05/05: Removed height based expiration support and simplified naming.
     7  
     8  ## Status
     9  
    10  Accepted
    11  
    12  ## Context
    13  
    14  In order to make blockchain transactions, the signing account must possess a sufficient balance of the right denomination
    15  in order to pay fees. There are classes of transactions where needing to maintain a wallet with sufficient fees is a
    16  barrier to adoption.
    17  
    18  For instance, when proper permissions are setup, someone may temporarily delegate the ability to vote on proposals to
    19  a "burner" account that is stored on a mobile phone with only minimal security.
    20  
    21  Other use cases include workers tracking items in a supply chain or farmers submitting field data for analytics
    22  or compliance purposes.
    23  
    24  For all of these use cases, UX would be significantly enhanced by obviating the need for these accounts to always
    25  maintain the appropriate fee balance. This is especially true if we wanted to achieve enterprise adoption for something
    26  like supply chain tracking.
    27  
    28  While one solution would be to have a service that fills up these accounts automatically with the appropriate fees, a better UX
    29  would be provided by allowing these accounts to pull from a common fee pool account with proper spending limits.
    30  A single pool would reduce the churn of making lots of small "fill up" transactions and also more effectively leverages
    31  the resources of the organization setting up the pool.
    32  
    33  ## Decision
    34  
    35  As a solution we propose a module, `x/feegrant` which allows one account, the "granter" to grant another account, the "grantee"
    36  an allowance to spend the granter's account balance for fees within certain well-defined limits.
    37  
    38  Fee allowances are defined by the extensible `FeeAllowanceI` interface:
    39  
    40  ```go
    41  type FeeAllowanceI {
    42    // Accept can use fee payment requested as well as timestamp of the current block
    43    // to determine whether or not to process this. This is checked in
    44    // Keeper.UseGrantedFees and the return values should match how it is handled there.
    45    //
    46    // If it returns an error, the fee payment is rejected, otherwise it is accepted.
    47    // The FeeAllowance implementation is expected to update it's internal state
    48    // and will be saved again after an acceptance.
    49    //
    50    // If remove is true (regardless of the error), the FeeAllowance will be deleted from storage
    51    // (eg. when it is used up). (See call to RevokeFeeAllowance in Keeper.UseGrantedFees)
    52    Accept(ctx sdk.Context, fee sdk.Coins, msgs []sdk.Msg) (remove bool, err error)
    53  
    54    // ValidateBasic should evaluate this FeeAllowance for internal consistency.
    55    // Don't allow negative amounts, or negative periods for example.
    56    ValidateBasic() error
    57  }
    58  ```
    59  
    60  Two basic fee allowance types, `BasicAllowance` and `PeriodicAllowance` are defined to support known use cases:
    61  
    62  ```protobuf
    63  // BasicAllowance implements FeeAllowanceI with a one-time grant of tokens
    64  // that optionally expires. The delegatee can use up to SpendLimit to cover fees.
    65  message BasicAllowance {
    66    // spend_limit specifies the maximum amount of tokens that can be spent
    67    // by this allowance and will be updated as tokens are spent. If it is
    68    // empty, there is no spend limit and any amount of coins can be spent.
    69    repeated cosmos_sdk.v1.Coin spend_limit = 1;
    70  
    71    // expiration specifies an optional time when this allowance expires
    72    google.protobuf.Timestamp expiration = 2;
    73  }
    74  
    75  // PeriodicAllowance extends FeeAllowanceI to allow for both a maximum cap,
    76  // as well as a limit per time period.
    77  message PeriodicAllowance {
    78    BasicAllowance basic = 1;
    79  
    80    // period specifies the time duration in which period_spend_limit coins can
    81    // be spent before that allowance is reset
    82    google.protobuf.Duration period = 2;
    83  
    84    // period_spend_limit specifies the maximum number of coins that can be spent
    85    // in the period
    86    repeated cosmos_sdk.v1.Coin period_spend_limit = 3;
    87  
    88    // period_can_spend is the number of coins left to be spent before the period_reset time
    89    repeated cosmos_sdk.v1.Coin period_can_spend = 4;
    90  
    91    // period_reset is the time at which this period resets and a new one begins,
    92    // it is calculated from the start time of the first transaction after the
    93    // last period ended
    94    google.protobuf.Timestamp period_reset = 5;
    95  }
    96  
    97  ```
    98  
    99  Allowances can be granted and revoked using `MsgGrantAllowance` and `MsgRevokeAllowance`:
   100  
   101  ```protobuf
   102  // MsgGrantAllowance adds permission for Grantee to spend up to Allowance
   103  // of fees from the account of Granter.
   104  message MsgGrantAllowance {
   105       string granter = 1;
   106       string grantee = 2;
   107       google.protobuf.Any allowance = 3;
   108   }
   109  
   110   // MsgRevokeAllowance removes any existing FeeAllowance from Granter to Grantee.
   111   message MsgRevokeAllowance {
   112       string granter = 1;
   113       string grantee = 2;
   114   }
   115  ```
   116  
   117  In order to use allowances in transactions, we add a new field `granter` to the transaction `Fee` type:
   118  
   119  ```protobuf
   120  package cosmos.tx.v1beta1;
   121  
   122  message Fee {
   123    repeated cosmos.base.v1beta1.Coin amount = 1;
   124    uint64 gas_limit = 2;
   125    string payer = 3;
   126    string granter = 4;
   127  }
   128  ```
   129  
   130  `granter` must either be left empty or must correspond to an account which has granted
   131  a fee allowance to fee payer (either the first signer or the value of the `payer` field).
   132  
   133  A new `AnteDecorator` named `DeductGrantedFeeDecorator` will be created in order to process transactions with `fee_payer`
   134  set and correctly deduct fees based on fee allowances.
   135  
   136  ## Consequences
   137  
   138  ### Positive
   139  
   140  * improved UX for use cases where it is cumbersome to maintain an account balance just for fees
   141  
   142  ### Negative
   143  
   144  ### Neutral
   145  
   146  * a new field must be added to the transaction `Fee` message and a new `AnteDecorator` must be
   147  created to use it
   148  
   149  ## References
   150  
   151  * Blog article describing initial work: https://medium.com/regen-network/hacking-the-cosmos-cosmwasm-and-key-management-a08b9f561d1b
   152  * Initial public specification: https://gist.github.com/aaronc/b60628017352df5983791cad30babe56
   153  * Original subkeys proposal from B-harvest which influenced this design: https://github.com/cosmos/cosmos-sdk/issues/4480