Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 87 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,10 @@ ethereum_ssz = "0.10"
# Tempo
tempo-primitives = { git = "https://github.com/tempoxyz/tempo", tag = "tempo-primitives@1.7.2", default-features = false, features = ["serde"] }

# EIP-8130 (account abstraction) consensus types. Pinned to a base/base commit
# that contains the `eip8130` module. Used by `cast` to build/sign EIP-8130 transactions.
base-common-consensus = { git = "https://github.com/base/base.git", rev = "a70d193532171f8ad1299d1c80f46bc6625789aa", default-features = false, features = ["std", "serde", "k256"] }

## Pinned dependencies. Enabled for the workspace in crates/test-utils.

# testing
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ base-foundryup
This adds `base-foundryup` and the namespaced `base-forge`/`base-cast`/`base-anvil`/`base-chisel` commands, which enable Base precompiles by default.

- **Test your Base app with base-anvil:** [`docs/base.md`](./docs/base.md)
- **Send EIP-8130 (account abstraction) transactions with cast:** [`docs/eip8130.md`](./docs/eip8130.md)
- **Release model and the `base/base` pin (maintainers):** [`RELEASES.md`](./RELEASES.md)

Everything below is inherited from upstream Foundry and works unchanged; only the Base additions above are specific to this fork.
Expand Down
3 changes: 3 additions & 0 deletions crates/cast/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ foundry-wallets.workspace = true
forge-fmt.workspace = true
foundry-primitives.workspace = true

# EIP-8130 (tx type 0x79) consensus types for `cast send/mktx --8130`.
base-common-consensus.workspace = true

alloy-chains.workspace = true
alloy-consensus = { workspace = true, features = ["serde", "kzg"] }
alloy-contract.workspace = true
Expand Down
26 changes: 26 additions & 0 deletions crates/cast/src/cmd/mktx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,32 @@ impl MakeTxArgs {

let provider = get_provider(&config)?;

// EIP-8130 (type 0x79) transactions are built, signed, and encoded directly (alloy's
// `EthereumWallet` doesn't understand the type)
if tx.eip8130.eip8130 {
if raw_unsigned {
eyre::bail!("--raw-unsigned is not supported for EIP-8130 transactions yet.");
}
if ethsign {
eyre::bail!("--ethsign is not supported for EIP-8130 transactions.");
}
if code.is_some() {
eyre::bail!("EIP-8130 transactions can't be CREATE transactions.");
}

let signer = eth.wallet.signer().await?;
let from = signer.address();
tx::validate_from_address(eth.wallet.from, from)?;

let raw_tx = crate::eip8130::build_raw_transaction(
&provider, &signer, &tx, &config, to, sig, args,
)
.await?;

sh_println!("0x{}", hex::encode(&raw_tx))?;
return Ok(());
}

let tx_builder = CastTxBuilder::new(&provider, tx.clone(), &config)
.await?
.with_to(to)
Expand Down
50 changes: 48 additions & 2 deletions crates/cast/src/cmd/send.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,54 @@ impl SendTxArgs {
provider.client().set_poll_interval(Duration::from_secs(interval))
}

let timeout = send_tx.timeout.unwrap_or(config.transaction_timeout);

// EIP-8130 (type 0x79) transactions are built, signed, and encoded directly (alloy's
// `EthereumWallet` doesn't understand the type), then broadcast as raw transactions
if tx.eip8130.eip8130 {
if unlocked {
return Err(eyre!(
"EIP-8130 transactions require a local signer and can't be sent with --unlocked"
));
}
if send_tx.eth.wallet.browser {
return Err(eyre!("EIP-8130 transactions are not supported with browser wallets."));
}
if code.is_some() {
return Err(eyre!("EIP-8130 transactions can't be CREATE transactions."));
}

let signer = send_tx.eth.wallet.signer().await?;
let from = signer.address();
tx::validate_from_address(send_tx.eth.wallet.from, from)?;

let raw_tx = crate::eip8130::build_raw_transaction(
&provider, &signer, &tx, &config, to, sig, args,
)
.await?;

let cast = CastTxSender::new(&provider);
let pending_tx = cast.send_raw(&raw_tx).await?;
let tx_hash = pending_tx.inner().tx_hash();

if send_tx.cast_async {
sh_println!("{tx_hash:#x}")?;
} else {
let receipt = cast
.receipt(
format!("{tx_hash:#x}"),
None,
send_tx.confirmations,
Some(timeout),
false,
)
.await?;
sh_println!("{receipt}")?;
}

return Ok(());
}

let builder = CastTxBuilder::new(&provider, tx, &config)
.await?
.with_to(to)
Expand All @@ -134,8 +182,6 @@ impl SendTxArgs {
.await?
.with_blob_data(blob_data)?;

let timeout = send_tx.timeout.unwrap_or(config.transaction_timeout);

// Check if this is a Tempo transaction - requires special handling for local signing
let is_tempo = builder.is_tempo();

Expand Down
Loading
Loading