Traces
A transaction’s trace frames are the individual steps the transaction took. Using traces, Ape is able to offer features like:
Showing a pretty call-tree from a transaction receipt
Gas reporting in
ape test
Coverage tools in
ape test
Some network providers, such as Alchemy and Foundry, implement debug_traceTransaction
and Parity’s trace_transaction
affording tracing capabilities in Ape.
Warning
Without RPCs for obtaining traces, some features such as gas-reporting and coverage are limited.
To see a transaction trace, use the show_trace() method on a receipt API object.
Here is an example using show_trace()
in Python code to print out a transaction’s trace.
Note
This code runs assuming you are connected to ethereum:mainnet
using a provider with tracing RPCs.
To learn more about networks in Ape, see the networks guide.
from ape import chain
tx = chain.provider.get_receipt('0xb7d7f1d5ce7743e821d3026647df486f517946ef1342a1ae93c96e4a8016eab7')
# Show the steps the transaction took.
tx.show_trace()
You should see a (less-abridged) trace like:
Call trace for '0xb7d7f1d5ce7743e821d3026647df486f517946ef1342a1ae93c96e4a8016eab7'
tx.origin=0x5668EAd1eDB8E2a4d724C8fb9cB5fFEabEB422dc
DSProxy.execute(_target=LoanShifterTaker, _data=0x35..0000) -> "" [1421947 gas]
└── (delegate) LoanShifterTaker.moveLoan(
_exchangeData=[
0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE,
ZERO_ADDRESS,
...
# Abridged because is super long #
...
│ └── LendingRateOracle.getMarketBorrowRate(_asset=DAI) ->
│ 35000000000000000000000000 [1164 gas]
├── DSProxy.authority() -> DSGuard [1291 gas]
├── DSGuard.forbid(src=LoanShifterReceiver, dst=DSProxy, sig=0x1c..0000) [5253 gas]
└── DefisaverLogger.Log(
_contract=DSProxy,
_caller=tx.origin,
_logName="LoanShifter",
_data=0x00..0000
) [6057 gas]
Similarly, you can use the provider directly to get a trace. This is useful if you want to interact with the trace or change some parameters for creating the trace.
from ape import chain
# Change the `debug_traceTransaction` parameter dictionary
trace = chain.provider.get_transaction_trace(
"0x...", debug_trace_transaction_parameters={"enableMemory": False}
)
# You can still print the pretty call-trace (as we did in the example above)
print(trace)
# Interact with low-level logs for deeper analysis.
struct_logs = trace.get_raw_frames()
Tracing Calls
Some network providers trace calls in addition to transactions.
EVM-based providers best achieve this by implementing the debug_traceCall
RPC.
If you want to see the trace of call when making the call, use the show_trace=
flag:
token.balanceOf(account, show_trace=True)
Warning
If your provider does not properly support call-tracing (e.g. doesn’t implement debug_traceCall
), traces are limited to the top-level call.
Ape traces calls automatically when using --gas
or --coverage
in tests to build reports.
Learn more about testing in Ape in the testing guide and in the following sections.
Gas Reports
To view the gas report of a transaction receipt, use the ReceiptAPI.show_gas_report() method:
from ape import networks
txn_hash = "0x053cba5c12172654d894f66d5670bab6215517a94189a9ffc09bc40a589ec04d"
receipt = networks.provider.get_receipt(txn_hash)
receipt.show_gas_report()
It outputs tables of contracts and methods with gas usages that look like this:
DAI Gas
Method Times called Min. Max. Mean Median
────────────────────────────────────────────────────────────────
balanceOf 4 1302 13028 1302 1302
allowance 2 1377 1377 1337 1337
│ approve 1 22414 22414 22414 22414
│ burn 1 11946 11946 11946 11946
│ mint 1 25845 25845 25845 25845