Skip to content

Conversation

@elizabethengelman
Copy link
Collaborator

@elizabethengelman elizabethengelman commented Jun 5, 2025

What

Based on #2035

Closes #2064

Adds another command for seeing the breakdown of the transaction's fee.

stellar tx fetch fee <HASH>

stellar tx fetch fee --hash dfc58e0b3a96ac27d8c0e823d4f38c3500de18b4a8b18c20e01bdf4c7010f37e --network local
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.17s
     Running `target/debug/soroban tx fetch fee --hash dfc58e0b3a96ac27d8c0e823d4f38c3500de18b4a8b18c20e01bdf4c7010f37e --network local`
┌──────────────────────────────────────────────────────────────────────────────┐
│ tx.fee: 59680                                                                │
├──────────────────────────────────────────────────────────────────────────────┤
│ tx.v1.sorobanData.resourceFee: 59580                    │ inclusion fee: 100 │
├──────────────────────────────────────────────────────────────────────────────┤
│ fixed resource fee: 59501 │ refundable resource fee: 79 │ inclusion fee: 100 │
└──────────────────────────────────────────────────────────────────────────────┘

Why

To help with understanding and clarity around fees.

Known limitations

I'd love some feedback/ideas about the specifics of how we display the fee table.

elizabethengelman and others added 17 commits May 27, 2025 10:25
* Make envelope the default fetch when no subcommand is given

In order to flatten an optional field, I needed to remove the
group(skip) on network::Args. But this lead to a conflict because there
are multiple groups with an implicit name of 'Args' that were all trying
to be flattened. The solution to this was add a specific group id to
network::Args.

* Make envelope the default fetch when no subcommand is given

* Refactor to use args impl

* Clean up
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@github-project-automation github-project-automation bot moved this to Backlog (Not Ready) in DevX Jun 5, 2025
@elizabethengelman
Copy link
Collaborator Author

elizabethengelman commented Jun 16, 2025

I was able to test out fetching a failed soroban tx, and here was the result:

  • envelope:
{"tx":{"tx":{"source_account":"GCOCUG25QUDXOBL3OY7WR5GER2ALO666BDZIVCA37V5HVP6S734YL42O","fee":119938,"seq_num":227633266773,"cond":"none","memo":"none","operations":[{"source_account":null,"body":{"invoke_host_function":{"host_function":{"invoke_contract":{"contract_address":"CC4OCAL6FCRUSHK5RHFH3XP45W2NZYBXP3QZG24EBBTBZNTSGPEB3TMQ","function_name":"reset_count","args":[{"u64":1750104440}]}},"auth":[]}}}],"ext":{"v1":{"ext":"v0","resources":{"footprint":{"read_only":[{"contract_data":{"contract":"CC4OCAL6FCRUSHK5RHFH3XP45W2NZYBXP3QZG24EBBTBZNTSGPEB3TMQ","key":"ledger_key_contract_instance","durability":"persistent"}},{"contract_code":{"hash":"68d6ab09f6e6dd6f2d2ebebadee28e6830cb56dcc8d828484c06949e6dddd7a1"}}],"read_write":[{"contract_data":{"contract":"CC4OCAL6FCRUSHK5RHFH3XP45W2NZYBXP3QZG24EBBTBZNTSGPEB3TMQ","key":{"symbol":"COUNTER"},"durability":"persistent"}}]},"instructions":3121182,"read_bytes":15144,"write_bytes":80},"resource_fee":119838}}},"signatures":[{"hint":"d2fef985","signature":"66a11c7c6c383820990e0b38cabaee4bd6091c2c853a410af81b9a621e3439e9fdc25b6092fe1987cc528cd62747fedc6684ce380374aa2affda71ad581a7b01"}]}}
  • result
{"fee_charged":74949,"result":{"tx_failed":[{"op_inner":{"invoke_host_function":"trapped"}}]},"ext":"v0"}
  • meta
{"v3":{"ext":"v0","tx_changes_before":[{"state":{"last_modified_ledger_seq":19314,"data":{"account":{"account_id":"GCOCUG25QUDXOBL3OY7WR5GER2ALO666BDZIVCA37V5HVP6S734YL42O","balance":199730568646,"seq_num":227633266772,"num_sub_entries":0,"inflation_dest":null,"flags":0,"home_domain":"","thresholds":"01000000","signers":[],"ext":{"v1":{"liabilities":{"buying":0,"selling":0},"ext":{"v2":{"num_sponsored":0,"num_sponsoring":0,"signer_sponsoring_i_ds":[],"ext":{"v3":{"ext":"v0","seq_ledger":17813,"seq_time":1750102940}}}}}}}},"ext":"v0"}},{"updated":{"last_modified_ledger_seq":19314,"data":{"account":{"account_id":"GCOCUG25QUDXOBL3OY7WR5GER2ALO666BDZIVCA37V5HVP6S734YL42O","balance":199730568646,"seq_num":227633266773,"num_sub_entries":0,"inflation_dest":null,"flags":0,"home_domain":"","thresholds":"01000000","signers":[],"ext":{"v1":{"liabilities":{"buying":0,"selling":0},"ext":{"v2":{"num_sponsored":0,"num_sponsoring":0,"signer_sponsoring_i_ds":[],"ext":{"v3":{"ext":"v0","seq_ledger":19314,"seq_time":1750104449}}}}}}}},"ext":"v0"}}],"operations":[],"tx_changes_after":[{"state":{"last_modified_ledger_seq":19314,"data":{"account":{"account_id":"GCOCUG25QUDXOBL3OY7WR5GER2ALO666BDZIVCA37V5HVP6S734YL42O","balance":199730568646,"seq_num":227633266773,"num_sub_entries":0,"inflation_dest":null,"flags":0,"home_domain":"","thresholds":"01000000","signers":[],"ext":{"v1":{"liabilities":{"buying":0,"selling":0},"ext":{"v2":{"num_sponsored":0,"num_sponsoring":0,"signer_sponsoring_i_ds":[],"ext":{"v3":{"ext":"v0","seq_ledger":19314,"seq_time":1750104449}}}}}}}},"ext":"v0"}},{"updated":{"last_modified_ledger_seq":19314,"data":{"account":{"account_id":"GCOCUG25QUDXOBL3OY7WR5GER2ALO666BDZIVCA37V5HVP6S734YL42O","balance":199730613635,"seq_num":227633266773,"num_sub_entries":0,"inflation_dest":null,"flags":0,"home_domain":"","thresholds":"01000000","signers":[],"ext":{"v1":{"liabilities":{"buying":0,"selling":0},"ext":{"v2":{"num_sponsored":0,"num_sponsoring":0,"signer_sponsoring_i_ds":[],"ext":{"v3":{"ext":"v0","seq_ledger":19314,"seq_time":1750104449}}}}}}}},"ext":"v0"}}],"soroban_meta":{"ext":{"v1":{"ext":"v0","total_non_refundable_resource_fee_charged":74849,"total_refundable_resource_fee_charged":0,"rent_fee_charged":0}},"events":[],"return_value":{"bool":false},"diagnostic_events":[{"in_successful_contract_call":false,"event":{"ext":"v0","contract_id":null,"type_":"diagnostic","body":{"v0":{"topics":[{"symbol":"fn_call"},{"bytes":"b8e1017e28a3491d5d89ca7dddfcedb4dce0377ee1936b8408661cb67233c81d"},{"symbol":"reset_count"}],"data":{"u64":1750104440}}}}},{"in_successful_contract_call":false,"event":{"ext":"v0","contract_id":"b8e1017e28a3491d5d89ca7dddfcedb4dce0377ee1936b8408661cb67233c81d","type_":"diagnostic","body":{"v0":{"topics":[{"symbol":"log"}],"data":{"vec":[{"string":"count: {}"},{"u32":0}]}}}}},{"in_successful_contract_call":false,"event":{"ext":"v0","contract_id":"b8e1017e28a3491d5d89ca7dddfcedb4dce0377ee1936b8408661cb67233c81d","type_":"diagnostic","body":{"v0":{"topics":[{"symbol":"log"}],"data":{"vec":[{"string":"now: {}"},{"u64":1750104449}]}}}}},{"in_successful_contract_call":false,"event":{"ext":"v0","contract_id":"b8e1017e28a3491d5d89ca7dddfcedb4dce0377ee1936b8408661cb67233c81d","type_":"diagnostic","body":{"v0":{"topics":[{"symbol":"error"},{"error":{"wasm_vm":"invalid_action"}}],"data":{"vec":[{"string":"VM call trapped: UnreachableCodeReached"},{"symbol":"reset_count"}]}}}}},{"in_successful_contract_call":false,"event":{"ext":"v0","contract_id":null,"type_":"diagnostic","body":{"v0":{"topics":[{"symbol":"host_fn_failed"},{"error":{"wasm_vm":"invalid_action"}}],"data":"void"}}}},{"in_successful_contract_call":false,"event":{"ext":"v0","contract_id":null,"type_":"diagnostic","body":{"v0":{"topics":[{"symbol":"core_metrics"},{"symbol":"read_entry"}],"data":{"u64":3}}}}},{"in_successful_contract_call":false,"event":{"ext":"v0","contract_id":null,"type_":"diagnostic","body":{"v0":{"topics":[{"symbol":"core_metrics"},{"symbol":"write_entry"}],"data":{"u64":0}}}}},{"in_successful_contract_call":false,"event":{"ext":"v0","contract_id":null,"type_":"diagnostic","body":{"v0":{"topics":[{"symbol":"core_metrics"},{"symbol":"ledger_read_byte"}],"data":{"u64":15144}}}}},{"in_successful_contract_call":false,"event":{"ext":"v0","contract_id":null,"type_":"diagnostic","body":{"v0":{"topics":[{"symbol":"core_metrics"},{"symbol":"ledger_write_byte"}],"data":{"u64":0}}}}},{"in_successful_contract_call":false,"event":{"ext":"v0","contract_id":null,"type_":"diagnostic","body":{"v0":{"topics":[{"symbol":"core_metrics"},{"symbol":"read_key_byte"}],"data":{"u64":144}}}}},{"in_successful_contract_call":false,"event":{"ext":"v0","contract_id":null,"type_":"diagnostic","body":{"v0":{"topics":[{"symbol":"core_metrics"},{"symbol":"write_key_byte"}],"data":{"u64":0}}}}},{"in_successful_contract_call":false,"event":{"ext":"v0","contract_id":null,"type_":"diagnostic","body":{"v0":{"topics":[{"symbol":"core_metrics"},{"symbol":"read_data_byte"}],"data":{"u64":184}}}}},{"in_successful_contract_call":false,"event":{"ext":"v0","contract_id":null,"type_":"diagnostic","body":{"v0":{"topics":[{"symbol":"core_metrics"},{"symbol":"write_data_byte"}],"data":{"u64":0}}}}},{"in_successful_contract_call":false,"event":{"ext":"v0","contract_id":null,"type_":"diagnostic","body":{"v0":{"topics":[{"symbol":"core_metrics"},{"symbol":"read_code_byte"}],"data":{"u64":14960}}}}},{"in_successful_contract_call":false,"event":{"ext":"v0","contract_id":null,"type_":"diagnostic","body":{"v0":{"topics":[{"symbol":"core_metrics"},{"symbol":"write_code_byte"}],"data":{"u64":0}}}}},{"in_successful_contract_call":false,"event":{"ext":"v0","contract_id":null,"type_":"diagnostic","body":{"v0":{"topics":[{"symbol":"core_metrics"},{"symbol":"emit_event"}],"data":{"u64":0}}}}},{"in_successful_contract_call":false,"event":{"ext":"v0","contract_id":null,"type_":"diagnostic","body":{"v0":{"topics":[{"symbol":"core_metrics"},{"symbol":"emit_event_byte"}],"data":{"u64":0}}}}},{"in_successful_contract_call":false,"event":{"ext":"v0","contract_id":null,"type_":"diagnostic","body":{"v0":{"topics":[{"symbol":"core_metrics"},{"symbol":"cpu_insn"}],"data":{"u64":2958682}}}}},{"in_successful_contract_call":false,"event":{"ext":"v0","contract_id":null,"type_":"diagnostic","body":{"v0":{"topics":[{"symbol":"core_metrics"},{"symbol":"mem_byte"}],"data":{"u64":1632136}}}}},{"in_successful_contract_call":false,"event":{"ext":"v0","contract_id":null,"type_":"diagnostic","body":{"v0":{"topics":[{"symbol":"core_metrics"},{"symbol":"invoke_time_nsecs"}],"data":{"u64":270125}}}}},{"in_successful_contract_call":false,"event":{"ext":"v0","contract_id":null,"type_":"diagnostic","body":{"v0":{"topics":[{"symbol":"core_metrics"},{"symbol":"max_rw_key_byte"}],"data":{"u64":60}}}}},{"in_successful_contract_call":false,"event":{"ext":"v0","contract_id":null,"type_":"diagnostic","body":{"v0":{"topics":[{"symbol":"core_metrics"},{"symbol":"max_rw_data_byte"}],"data":{"u64":104}}}}},{"in_successful_contract_call":false,"event":{"ext":"v0","contract_id":null,"type_":"diagnostic","body":{"v0":{"topics":[{"symbol":"core_metrics"},{"symbol":"max_rw_code_byte"}],"data":{"u64":14960}}}}},{"in_successful_contract_call":false,"event":{"ext":"v0","contract_id":null,"type_":"diagnostic","body":{"v0":{"topics":[{"symbol":"core_metrics"},{"symbol":"max_emit_event_byte"}],"data":{"u64":0}}}}}]}}}
  • fee
┌─────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ tx.fee: 74949                                                                                       │
├─────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ tx.v1.sorobanData.resourceFee: 74849                                           │ inclusion fee: 100 │
├─────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ non-refundable resource fee: 74849                │ refundable resource fee: 0 │ inclusion fee: 100 │
│                                                   │                            │                    │
│ calculated based on tx.v1.sorobanData.resources.* │                            │                    │
│                                                   │                            │                    │
│ instructions                                      │ rent                       │                    │
│ read                                              │ events                     │                    │
│ write                                             │ return value               │                    │
│ bandwidth (size of tx)                            │                            │                    │
└─────────────────────────────────────────────────────────────────────────────────────────────────────┘

The way I was able to test a failed tx was to create a fn in the contract that was time based - so after a certain timestamp it would panic. And then I simulated the tx with a "passing" timestamp, and then sent it with a failing timestamp. Not sure if there is an easier way to reproduce this scenario, I was running into txns failing during simulation and therefore not making it to the ledger to be fetched later.

@janewang
Copy link
Contributor

Btw, this work really elucidates the fees for soroban transactions which is hugely beneficial for devs! Thank you @elizabethengelman

@elizabethengelman
Copy link
Collaborator Author

Just pushed up a change to the table, to include max fees. For a soroban tx:

┌──────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ Transaction Fee Charged: 185119                                                                          │
├──────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Resource Fee Charged: 185019                                                        │ Inclusion Fee: 100 │
├──────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Non-refundable Resource Fee: 59343                │ Refundable Resource Fee: 125676 │ Inclusion Fee: 100 │
│                                                   │                                 │                    │
│ calculated based on tx.v1.sorobanData.resources.* │                                 │                    │
│                                                   │                                 │                    │
│ instructions                                      │ rent                            │                    │
│ read                                              │ events                          │                    │
│ write                                             │ return value                    │                    │
│ bandwidth (size of tx)                            │                                 │                    │
├──────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Max Fee Set: 248869                                                                                      │
├──────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Max Resource Fee: 248769                                                            │ Inclusion Fee: 100 │
└──────────────────────────────────────────────────────────────────────────────────────────────────────────┘

And for a fee bump tx:

┌───────────────────────────────────┐
│ Transaction Fee Charged: 200      │
├───────────────────────────────────┤
│ Max Fee Set: 400                  │
└───────────────────────────────────┘

For the fee bump txns, should the inclusion fee be included in the table? Or are we okay with just the fee charged and max fee?

@leighmcculloch
Copy link
Member

The table presentation was very effective when all of the rows visually communicated that fees came together to make up the larger amounts (#2040 (comment)). But in the new table (#2040 (comment)), that property is lost a bit because the max fee is in the same table and its cell is the same size.

Is there a way we can represent the refund maybe as a component? The refund is a first class concept. The way that it shows up in events for example in protocol 23 is that there are two events, an initial fee event charging the max fee, and then a refund fee that pays back an amount.

For example, something like:

┌────────────────────────────────────────────────────────────────────────────────────┐
│ Fee Proposed: 185119                                                               │
├────────────────────────────────────────────────────────────────────────────────────┤
│ Inclusion Fee: 100 │ Resource Fee: 185019                                          │
├────────────────────────────────────────────────────────────────────────────────────┤
│ Inclusion Fee: 100 │ Non-Refundable: 59343 │ Refundable: 125676                    │
│                    │                       │                                       │
│                    │ cpu instructions      │ return value                          │
│                    │ storage read/write    │ storage rent                          │
│                    │ tx size               │ events                                │
└────────────────────────────────────────────────────────────────────────────────────┘
                           👆 Proposed Fee  👇 Final Fee
┌─────────────────────────────────────────────────────────────────┐┌─────────────────┐
│ Inclusion Fee: 100 │ Non-refundable: 59343 │ Refundable: 105676 ││ Refunded: 20000 │
├─────────────────────────────────────────────────────────────────││─────────────────┤
│ Inclusion Fee: 100 │ Resource Fee: 165019                       ││ Refunded: 20000 │
├─────────────────────────────────────────────────────────────────││─────────────────┤
│ Fee Charged: 165119                                             ││ Refunded: 20000 │
└─────────────────────────────────────────────────────────────────┘└─────────────────┘

@elizabethengelman
Copy link
Collaborator Author

@leighmcculloch

Is there a way we can represent the refund maybe as a component?

I like it! The refunded amount is the proposed fee - the charged fee, is that correct?

@elizabethengelman
Copy link
Collaborator Author

@leighmcculloch @janewang updated. I can also play with bolding and making text different colors as well.
Screenshot 2025-06-18 at 12 30 52 PM

@janewang
Copy link
Contributor

janewang commented Jul 7, 2025

@elizabethengelman is this ready to go in?

@elizabethengelman
Copy link
Collaborator Author

@janewang this branch is based off of #2035 which still needs an approval. I was holding off merging this into #2035 so that #2035 was easier to review.

Base automatically changed from feat/tx-fetch to main July 9, 2025 17:40
@janewang
Copy link
Contributor

janewang commented Jul 9, 2025

@elizabethengelman #2035 is merged. Could we resolve conflicts and merge this one too?

@elizabethengelman
Copy link
Collaborator Author

@janewang conflicts have been resolved! Besides waiting for CI to finish, i think we'd also need an approval to get this merged in.

@elizabethengelman elizabethengelman enabled auto-merge (squash) July 10, 2025 14:09
@elizabethengelman elizabethengelman merged commit b7f91bd into main Jul 10, 2025
35 checks passed
@elizabethengelman elizabethengelman deleted the feat/only-fee branch July 10, 2025 14:39
@github-project-automation github-project-automation bot moved this from Backlog (Not Ready) to Done in DevX Jul 10, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

stellar tx fetch fee <HASH>

4 participants