# Gno Fee Taskforce WIP ## Goal - Find how much gas is used for common types of transactions - Estimate the amount of transactions of each type can be done by an average GNOT token holder - Recommend gas fee adjustments ## Distribution (based on [indepence-day balances](https://github.com/gnolang/independence-day/blob/main/mkgenesis/balances.txt.gz)) Total number of accounts: 656,740 ### Totals - All: 752,454,999,663,089 ugnot - Top 1000 accounts: 621,654,079,086,191 ugnot - Bottom 1000 accounts: 2,000 ugnot - All excluding the top and bottom 1000: 130,800,920,574,898 ugnot ### Weight - Top 1000 accounts (0.15% of the total number of accounts) hold 82.62% of the total balance - Bottom 1000 accounts (0.15% of the total number of accounts) hold 0.0000000003% of the total balance ### Averages - All: 1,145,742,606.91 ugnot - Top 1000 accounts: 621,654,079,086.19 ugnot - Bottom 1000 accounts: 2.00 ugnot - All excluding the top and bottom 1000: 199,775,362.09 ugnot ### Spread - Variance of balances: 18,446,744,073,709,551,615 - Standard deviation of balances: 4,294,967,296 ### Percentiles - 99th percentile of balances: 4,060,691,105 ugnot - 95th percentile of balances: 552,862,608 ugnot - 90th percentile of balances: 239,673,979 ugnot - 75th percentile of balances: 52,359,891 ugnot - 50th percentile of balances: 8,388,001 ugnot (median) - 25th percentile of balances: 194,150 ugnot - 10th percentile of balances: 7,496 ugnot - 5th percentile of balances: 4,872 ugnot - 1st percentile of balances: 9 ugnot ## Gas usage - Global average cost: 6,744,429 ugnot - Median user (50th percentile) can call 1.24 times - Bottom quarter user (25th percentile) can call 0.03 times - Average user can call 169.88 times - Average (excluding top and bottom 1000) can call 29.62 times ### Bank transfer - Average cost: 45,116 ugnot - Median user (50th percentile) can transfer 185.92 times - Bottom quarter user (25th percentile) can transfer 4.30 times - Average user can transfer 25,395.48 times - Average (excluding top and bottom 1000) can transfer 4,428.04 times ### Realm "gno.land/r/demo/boards" - Realm average cost: 6,357,615 ugnot - Median user (50th percentile) can call 1.32 times - Bottom quarter user (25th percentile) can call 0.03 times - Average user can call 180.22 times - Average (excluding top and bottom 1000) can call 31.42 times #### Func "CreateBoard" - Func "CreateBoard" average cost: 10,282,870 ugnot - Median user (50th percentile) can call 0.82 times - Bottom quarter user (25th percentile) can call 0.02 times - Average user can call 111.42 times - Average (excluding top and bottom 1000) can call 19.43 times #### Func "GetBoardIDFromName" - Func "GetBoardIDFromName" average cost: 1,137,910 ugnot - Median user (50th percentile) can call 7.37 times - Bottom quarter user (25th percentile) can call 0.17 times - Average user can call 1,006.88 times - Average (excluding top and bottom 1000) can call 175.56 times #### Func "CreateThread" - Func "CreateThread" average cost: 6,821,067 ugnot - Median user (50th percentile) can call 1.23 times - Bottom quarter user (25th percentile) can call 0.03 times - Average user can call 167.97 times - Average (excluding top and bottom 1000) can call 29.29 times #### Func "CreateReply" - Func "CreateReply" average cost: 6,983,445 ugnot - Median user (50th percentile) can call 1.20 times - Bottom quarter user (25th percentile) can call 0.03 times - Average user can call 164.07 times - Average (excluding top and bottom 1000) can call 28.61 times #### Func "DeletePost" - Func "DeletePost" average cost: 6,562,785 ugnot - Median user (50th percentile) can call 1.28 times - Bottom quarter user (25th percentile) can call 0.03 times - Average user can call 174.58 times - Average (excluding top and bottom 1000) can call 30.44 times ### Realm "gno.land/r/demo/grc20factory" - Realm average cost: 7,131,244 ugnot - Median user (50th percentile) can call 1.18 times - Bottom quarter user (25th percentile) can call 0.03 times - Average user can call 160.67 times - Average (excluding top and bottom 1000) can call 28.01 times #### Func "NewWithAdmin" - Func "NewWithAdmin" average cost: 7,538,156 ugnot - Median user (50th percentile) can call 1.11 times - Bottom quarter user (25th percentile) can call 0.03 times - Average user can call 151.99 times - Average (excluding top and bottom 1000) can call 26.50 times #### Func "Mint" - Func "Mint" average cost: 6,575,337 ugnot - Median user (50th percentile) can call 1.28 times - Bottom quarter user (25th percentile) can call 0.03 times - Average user can call 174.25 times - Average (excluding top and bottom 1000) can call 30.38 times #### Func "Burn" - Func "Burn" average cost: 6,198,809 ugnot - Median user (50th percentile) can call 1.35 times - Bottom quarter user (25th percentile) can call 0.03 times - Average user can call 184.83 times - Average (excluding top and bottom 1000) can call 32.23 times #### Func "Transfer" - Func "Transfer" average cost: 8,212,674 ugnot - Median user (50th percentile) can call 1.02 times - Bottom quarter user (25th percentile) can call 0.02 times - Average user can call 139.51 times - Average (excluding top and bottom 1000) can call 24.33 times ## Onbloc Research & Notes ### Gno Transaction Fee Comparison in Devnet - General Transfer: - Fee: 0.000115 GNOT - Used/Wanted: 47,066/55,015 (85.55%) - Mint Transaction (GnoSwap): - Fee: 0.405793 GNOT - Used/Wanted: 162,318,280/194,780,448 (83.33%) - The Mint transaction consumes about x3500 more fees than a general GNOT transfer transaction - Even if the Mint transaction requires complex computation such as uint256, this gap is too large and seems abnormal. - Mint function: https://github.com/gnoswap-labs/gnoswap/blob/main/contract/r/gnoswap/position/position.gno#L75 - A simple direct swap (not a complex routed swap) consumes 0.251787 GNOT, Used/Wanted of (100,715,640/120,857,292 (83.33%). - Swap function: https://github.com/gnoswap-labs/gnoswap/blob/main/contract/r/gnoswap/pool/swap.gno#L44 ### Transaction Fee Comparison in Portal-loop - General Transfer: - Fee: 0.000114 GNOT - Used/Wanted: 44,310/54,271 (81.65%) - Deposit (r/demo/wugnot, a simple contract): - Fee: 0.01727 GNOT - Used/Wanted: 6,908,950/8,289,264 (83.35%) - A simple contract use consumes x151 more gas than a general transfer. ### Transaction execution information - Realm Package: gno.land/r/demo/wugnot - Function: Deposit ```shell gnokey maketx call \ -pkgpath "gno.land/r/demo/wugnot" \ -func "Deposit" \ -send "1000ugnot" \ -gas-fee 1000000ugnot \ -gas-wanted 20000000 \ -broadcast \ -chainid dev \ test1 ``` ### Gas consumption by item ``` description: ReadFlat , consumed: 10000 description: WriteFlat , consumed: 10000 description: WritePerByte , consumed: 17610 description: ante verify: secp256k1 , consumed: 1000 description: GetPackageRealmPerByte , consumed: 35632 description: SetObjectPerByte , consumed: 31360 description: txSize , consumed: 2510 description: ReadPerByte , consumed: 3522 description: GetObjectPerByte , consumed: 2668848 description: CPUCycles , consumed: 158313 description: SetPackageRealmPerByte , consumed: 35632 description: DeleteObjectFlat , consumed: 7430 ``` - Gas consumption is about 89.5% being consumed by the item called GetObjectPerByte. - Items that load the VM’s state objects Consuming gas to load objects seems like a reasonable gas consumption. However, the gas weight of `GetObjectPerByte` is multiplied by `16` and is consuming a lot of gas. I have a couple questions here. I’ll have to track what is being loaded further, but is a weight of `16` appropriate? - GasConfig: https://github.com/gnolang/gno/blob/f35bbf2669aab346e59f9b1f66aff3880f258f8f/gnovm/pkg/gnolang/store.go#L116 Or what do you think about separating the weight of load package realms from load state objects? - GetPackageRealm: https://github.com/gnolang/gno/blob/f35bbf2669aab346e59f9b1f66aff3880f258f8f/gnovm/pkg/gnolang/store.go#L342 - GetObject: https://github.com/gnolang/gno/blob/f35bbf2669aab346e59f9b1f66aff3880f258f8f/gnovm/pkg/gnolang/store.go#L397 --- ## Giuseppe / Milos gas fee message Here is where we do the fee validation: https://github.com/gnolang/gno/blob/6f91a35f3fcb0da593a8b45f6b19d70865406e05/tm2/pkg/sdk/auth/ante.go#L333-L406 The block gas context value is set in the app setup: https://github.com/gnolang/gno/blob/6f91a35f3fcb0da593a8b45f6b19d70865406e05/gno.land/pkg/gnoland/app.go#L124-L125 the initial value of the block gas context (price) is set in the init chainer: https://github.com/gnolang/gno/blob/6f91a35f3fcb0da593a8b45f6b19d70865406e05/gno.land/pkg/gnoland/app.go#L330-L331 this param value is set in the initial auth params: https://github.com/gnolang/gno/blob/6f91a35f3fcb0da593a8b45f6b19d70865406e05/tm2/pkg/sdk/auth/params.go#L34 (by default it's 0.001ugnot/gas, it's part of the genesis state in genesis.json): ```json "auth": { "params": { "max_memo_bytes": "65536", "tx_sig_limit": "7", "tx_size_cost_per_byte": "10", "sig_verify_cost_ed25519": "590", "sig_verify_cost_secp256k1": "1000", "gas_price_change_compressor": "10", "target_gas_ratio": "70", "initial_gasprice": { "gas": "1000", "price": "1ugnot" } } } ``` This block-level gas price is updated in the EndBlocker logic: https://github.com/gnolang/gno/blob/6f91a35f3fcb0da593a8b45f6b19d70865406e05/tm2/pkg/sdk/auth/keeper.go#L195-L205 The validators set the target gas ratio to move the minimum network gas fee up or down (check `calcBlockGasPrice`). This value is updated through the params keeper, which we can call through governance proposals in gno code --- The node-specific gas limit is also set in the app setup (config.toml param): https://github.com/gnolang/gno/blob/6f91a35f3fcb0da593a8b45f6b19d70865406e05/gno.land/pkg/gnoland/app.go#L88. Node operators can update this at any time before they start their node @Ray Qin can correct me if I missed something in haste, but this should be it: - network (block) gas fee limits are controlled through governance (govdao), using the params module. Initial state set in genesis state - validator (node) gas fee limits are set through the config.toml , and are node-specific