Skip to content

sending a Tempo transaction via cast send #395

@Dargon789

Description

@Dargon789

Reviewer's Guide

Implements full support for Tempo transactions across Foundry (building, signing, and sending), refines Optimism base-fee handling using network-specific parameters, adjusts artifact lookup and documentation output behavior, introduces CLI options and workflows, and updates dependency and CI configurations.

Sequence diagram for sending a Tempo transaction via cast send

sequenceDiagram
    actor User
    participant CastSend as Cast_send
    participant CastTxBuilder
    participant WalletSigner
    participant FoundryTxReq as FoundryTransactionRequest
    participant FoundryTypedTx
    participant NetworkWallet as NetworkWallet_FoundryNetwork
    participant CastTxSender
    participant ProviderNode as Ethereum_Node

    User->>CastSend: cast send --tempo.fee-token ...
    CastSend->>CastTxBuilder: new(provider, tx_opts)
    CastTxBuilder->>CastTxBuilder: is_tempo() // checks other[feeToken]
    CastSend->>CastTxBuilder: build(&WalletSigner)
    CastTxBuilder->>CastTxBuilder: _build(sender, fill_defaults=true, for_signing=false)
    CastTxBuilder-->>CastSend: (WithOtherFields<TransactionRequest>, fn)
    CastSend->>FoundryTxReq: FoundryTransactionRequest::new(tx)

    Note over CastSend,WalletSigner: Tempo path selected (is_tempo == true)

    CastSend->>WalletSigner: sign_request(FoundryTransactionRequest)
    WalletSigner->>WalletSigner: default_signer_address()
    WalletSigner->>FoundryTxReq: build_typed_tx()
    FoundryTxReq->>FoundryTxReq: is_tempo(), complete_tempo()
    FoundryTxReq-->>WalletSigner: FoundryTypedTx::Tempo

    WalletSigner->>NetworkWallet: sign_transaction_from(sender, FoundryTypedTx::Tempo)
    NetworkWallet->>WalletSigner: validate sender == default_signer_address
    NetworkWallet->>FoundryTypedTx: sign_transaction(self, &mut TempoTx)
    FoundryTypedTx-->>NetworkWallet: Signature
    NetworkWallet->>FoundryTypedTx: into_signed(TempoSignature)
    NetworkWallet-->>WalletSigner: FoundryTxEnvelope::Tempo
    WalletSigner-->>CastSend: FoundryTxEnvelope::Tempo

    CastSend->>CastSend: encode_2718_len(), encode_2718(raw_tx)
    CastSend->>CastTxSender: new(provider)
    CastSend->>CastTxSender: send_raw(raw_tx)
    CastTxSender->>ProviderNode: eth_sendRawTransaction(raw_tx)
    ProviderNode-->>CastTxSender: PendingTransaction
    CastTxSender-->>CastSend: PendingTransactionBuilder
    CastSend-->>User: tx_hash / receipt
Loading

Updated class diagram for Tempo transaction support and signing

classDiagram
    class FoundryTransactionRequest {
        - inner : WithOtherFields_TransactionRequest
        + new(inner : WithOtherFields_TransactionRequest) FoundryTransactionRequest
        + into_inner() WithOtherFields_TransactionRequest
        + is_deposit() bool
        + is_tempo() bool
        + get_tempo_fee_token() Option_Address
        + complete_tempo() Result_void_vec_str
        + preferred_type() FoundryTxType
        + try_build() Option_FoundryTypedTx
        + build_typed_tx() Result_FoundryTypedTx_vec_str
        + build_unsigned() Result_FoundryTypedTx_vec_str
    }

    class FoundryTxType {
        <<enum>>
        Legacy
        Eip2930
        Eip1559
        Eip4844
        Eip7702
        Deposit
        Tempo
    }

    class FoundryTypedTx {
        <<enum>>
        Legacy
        Eip2930
        Eip1559
        Eip4844
        Eip7702
        Deposit
        Tempo
    }

    class TempoTransaction {
        + chain_id : u64
        + fee_token : Option_Address
        + max_fee_per_gas : u128
        + max_priority_fee_per_gas : u128
        + gas_limit : u128
        + nonce_key : U256
        + nonce : u64
        + calls : Vec_Call
        + access_list : AccessList
        + encoded_for_signing() Vec_u8
        + into_signed(sig : TempoSignature) Self
    }

    class Call {
        + to : Address
        + value : U256
        + input : Bytes
    }

    class FoundryTxEnvelope {
        <<enum>>
        Legacy
        Eip2930
        Eip1559
        Eip4844
        Eip7702
        Deposit
        Tempo
        + encode_2718_len() usize
        + encode_2718(buf : Vec_u8) void
    }

    class TempoSignature {
    }

    class WalletSigner {
        + default_signer_address() Address
        + has_signer_for(address : Address) bool
        + signer_addresses() Iterator_Address
        + sign_transaction_from(sender : Address, tx : FoundryTypedTx) Result_FoundryTxEnvelope
        + sign_request(request : FoundryTransactionRequest) Result_FoundryTxEnvelope
    }

    class TxSigner_Signature {
        <<trait>>
        + sign_transaction(self, tx : T) Future_Result_Signature
    }

    class NetworkWallet_FoundryNetwork {
        <<trait>>
        + default_signer_address() Address
        + has_signer_for(address : Address) bool
        + signer_addresses() Iterator_Address
        + sign_transaction_from(sender : Address, tx : FoundryTypedTx) Result_FoundryTxEnvelope
        + sign_request(request : FoundryTransactionRequest) Result_FoundryTxEnvelope
    }

    class DevSigner {
        + sign_transaction(tx : FoundryTypedTx) Result_Signature
    }

    class CastTxBuilder_P_InputState {
        + tx : WithOtherFields_TransactionRequest
        + build(sender : SenderKind) Result_FoundryTransactionRequest_Option_Function
        + build_unsigned_raw(from : Address) Result_String
        + is_tempo() bool
        + _build(sender : SenderKind, fill_defaults : bool, for_signing : bool) Result_WithOtherFields_TransactionRequest_Option_Function
    }

    class CastTxBuilder_P_InitState {
    }

    class CastTxBuilder_P_ToState {
    }

    class CastTxSender_P {
        + provider : Provider_AnyNetwork
        + new(provider : Provider_AnyNetwork) Self
        + send(tx_request : WithOtherFields_TransactionRequest) Result_PendingTransactionBuilder_AnyNetwork
        + send_raw(raw_tx : Vec_u8) Result_PendingTransactionBuilder_AnyNetwork
        + receipt(hash : String, block : Option_u64, confirmations : Option_u64, timeout : Option_Duration, cast_async : bool) Result_TransactionReceipt
    }

    FoundryTransactionRequest --> FoundryTypedTx : builds
    FoundryTypedTx o-- TempoTransaction : contains
    TempoTransaction o-- Call : contains
    FoundryTypedTx --> FoundryTxEnvelope : wrapped as
    FoundryTxEnvelope --> TempoSignature : uses

    WalletSigner ..|> TxSigner_Signature
    WalletSigner ..|> NetworkWallet_FoundryNetwork

    DevSigner ..> FoundryTypedTx : signs
    DevSigner ..> TempoSignature : converts Signature to TempoSignature

    CastTxBuilder_P_InputState --> FoundryTransactionRequest : build()
    CastTxBuilder_P_InputState --> WithOtherFields_TransactionRequest : internal tx

    CastTxSender_P --> Provider_AnyNetwork : uses
Loading

File-Level Changes

Change Details Files
Add end-to-end support for Tempo (type 0x76) transactions in transaction building, signing, and Cast/CLI flows.
  • Expose FoundryTransactionRequest::into_inner and use FoundryTransactionRequest as the primary builder output type.
  • Detect Tempo transactions via transaction_type or feeToken in other fields and compute their preferred type as Tempo.
  • Implement complete_tempo to validate required Tempo fields and integrate it into completeness checks and TransactionBuilder::can_build.
  • Construct TempoTransaction instances from FoundryTransactionRequest (including fee token, gas fields, nonce, calls, access list) and support conversion back to TransactionRequest with feeToken in OtherFields and TEMPO_TX_TYPE_ID set.
  • Extend WalletSigner with NetworkWallet to sign FoundryTypedTx variants, including Tempo via TempoSignature, and use this in Cast send/mktx for local Tempo signing and raw submission.
  • Teach CastTxBuilder and Send/MakeTx commands about Tempo (is_tempo, tempo.fee-token option, building unsigned/raw, browser wallet restrictions, and use of eth_sendRawTransaction for Tempo).
crates/primitives/src/transaction/request.rs
crates/wallets/src/signer.rs
crates/cast/src/cmd/send.rs
crates/cast/src/tx.rs
crates/cast/src/cmd/mktx.rs
crates/cli/src/opts/tempo.rs
crates/cli/src/opts/transaction.rs
crates/wallets/Cargo.toml
crates/anvil/src/eth/sign.rs
crates/anvil/Cargo.toml
Cargo.toml
Use network-specific base-fee parameters (especially Optimism Canyon) in Anvil and add a regression test.
  • Extend NetworkConfigs with base_fee_params, selecting Optimism Canyon or pre-Canyon params using OpChainHardforks and timestamp.
  • Pass BaseFeeParams from NodeConfig into FeeManager::new and store them inside FeeManager alongside elasticity.
  • Use FeeManager::base_fee_params when computing next_block_base_fee in mem backend and document calculate_next_block_base_fee as Ethereum-mainnet specific.
  • Add an anvil Optimism integration test that fills consecutive full blocks and asserts Optimism Canyon base-fee increase (2%) instead of Ethereum’s 12.5%.
  • Wire in additional alloy-* dependencies required for base-fee and hardfork handling.
crates/evm/networks/src/lib.rs
crates/anvil/src/config.rs
crates/anvil/src/eth/fees.rs
crates/anvil/src/eth/backend/mem/mod.rs
crates/anvil/tests/it/optimism.rs
crates/evm/networks/Cargo.toml
crates/anvil/Cargo.toml
Improve artifact lookup and error behavior for cheatcodes fs and strengthen docs generation semantics.
  • Refactor get_artifact_code to return None when there are no matching artifacts and only build a manual path when artifact metadata is missing or no artifact matched, improving error messages when reading artifacts fails.
  • Change artifact selection to wrap multiple-match resolution in an Option<Result<...>> and only error when there are still multiple artifacts after filtering by version/profile.
  • Make fs read errors from artifacts path surface a generic no matching artifact found when available_artifacts is set, preserving IO errors otherwise.
  • Simplify doc writer behavior by replacing write_dev_content with italic output, generating function headings from function names plus type-only parameter lists, filtering out @custom variant comments from enum descriptions while using them in variant tables, and adjusting inheritdoc resolution to use function names.
  • Tweak Comments / CommentsRef utilities (From<Vec>, iteration) to support new filtering behaviors and update enum-variant table rendering accordingly.
crates/cheatcodes/src/fs.rs
crates/doc/src/writer/as_doc.rs
crates/doc/src/writer/buf_writer.rs
crates/doc/src/parser/comment.rs
Adjust CLI, scripting, and simulation UX and robustness (transaction options, suggestions, script-sequence, gas reporting, error messaging).
  • Introduce TempoOpts and flatten it into TransactionOpts so CLI users can pass --tempo.fee-token for Tempo transactions.
  • Update CastTxBuilder::build to return FoundryTransactionRequest and adjust all call-sites (send, mktx, unsigned raw) to unwrap via into_inner where they still expect TransactionRequest.
  • Allow CastTxBuilder::build_unsigned_raw to produce signing payloads for all supported FoundryTypedTx variants, including Tempo.
  • In simulate scripts, always label estimated amount required as ETH (and drop chain-specific token symbols) for simpler JSON output and logs.
  • Change suggestions::get_predictions and ContractsByArtifact::best_match to use partial_cmp with Ordering::Equal fallback instead of total_cmp, improving compatibility across Rust versions.
  • Improve RestrictionsError::BothExactAndRelative message to be more user-friendly and explicit about configuration constraints.
  • Add a chisel-serial test group and widen nextest slow-timeout/overrides for certain tests.
  • Comment-only or cosmetic tweaks in script-sequence (marker comments) and flake.nix (shell toolchain cleanups).
crates/cli/src/opts/mod.rs
crates/cli/src/opts/transaction.rs
crates/cast/src/cmd/send.rs
crates/cast/src/tx.rs
crates/cast/src/cmd/mktx.rs
crates/script/src/simulate.rs
crates/cli/src/utils/suggestions.rs
crates/common/src/contracts.rs
crates/config/src/compilation.rs
.config/nextest.toml
crates/script-sequence/src/sequence.rs
flake.nix
Update dependency management, CI workflows, and add example Solidity counter project and assorted templates.
  • Replace the previous reusable dependencies workflow with an in-repo cargo update workflow that opens weekly PRs (peter-evans/create-pull-request) with a detailed log.
  • Relax tempo-primitives features in the workspace (disable default-features, enable serde) and add it as a dependency where Tempo support is used (anvil, wallets).
  • Introduce multiple GitHub Actions templates (Docker builds, GKE deploy, CodeQL, Snyk container scan, APIsec scan, Foundry build/deploy) and CircleCI configs (basic hello-world, Rust cargo CI, and a custom web3 GameFi config).
  • Add a sample counter Solidity project under counter/ (foundry.toml, Counter.sol, script, tests, README, gitignore, forge-std and openzeppelin submodules, CI workflow).
  • Vendor Remix testing helper contracts under .deps/remix-tests and add generic GitHub issue templates for bugs, features, and custom issues; also commit .codesandbox/tasks.json and .gitmodules placeholders and switch Cargo.lock from ignored to tracked.
.github/workflows/dependencies.yml
Cargo.toml
crates/anvil/Cargo.toml
crates/wallets/Cargo.toml
.github/workflows/google.yml
.github/workflows/docker.yml
.github/workflows/codeql.yml
.github/workflows/snyk-container.yml
.github/workflows/apisec-scan.yml
.github/workflows/deploy.yml
.github/workflows/docker-image.yml
.circleci/config.yml
.circleci/cargo.yml
.circleci/ci-web3-gamefi.yml
counter/README.md
counter/foundry.toml
counter/src/Counter.sol
counter/script/Counter.s.sol
counter/test/Counter.t.sol
counter/.github/workflows/test.yml
.deps/remix-tests/remix_tests.sol
.deps/remix-tests/remix_accounts.sol
.github/ISSUE_TEMPLATE/bug_report.md
.github/ISSUE_TEMPLATE/feature_request.md
.github/ISSUE_TEMPLATE/custom.md
.codesandbox/tasks.json
.gitmodules
.gitignore
Cargo.lock
counter/.gitignore
counter/lib/forge-std
counter/lib/openzeppelin-contracts

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Originally posted by @sourcery-ai[bot] in #303 (comment)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    Status

    Todo

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions