-
Notifications
You must be signed in to change notification settings - Fork 38
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #9 from alloy-rs/zerosnacks/middleware
feat(layers): Port `middleware` (layers) from `ethers-rs`
- Loading branch information
Showing
4 changed files
with
156 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
[package] | ||
name = "examples-layers" | ||
|
||
publish.workspace = true | ||
version.workspace = true | ||
edition.workspace = true | ||
rust-version.workspace = true | ||
authors.workspace = true | ||
license.workspace = true | ||
homepage.workspace = true | ||
repository.workspace = true | ||
|
||
[dev-dependencies] | ||
alloy.workspace = true | ||
|
||
eyre.workspace = true | ||
reqwest.workspace = true | ||
tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
//! Example of using the `ManagedNonceLayer` in the provider. | ||
use alloy::{ | ||
network::{EthereumSigner, TransactionBuilder}, | ||
node_bindings::Anvil, | ||
primitives::{address, U256}, | ||
providers::{layers::ManagedNonceLayer, Provider, ProviderBuilder}, | ||
rpc::{client::RpcClient, types::eth::request::TransactionRequest}, | ||
signers::wallet::LocalWallet, | ||
}; | ||
use eyre::Result; | ||
|
||
/// In Ethereum, the nonce of a transaction is a number that represents the number of transactions | ||
/// that have been sent from a particular account. The nonce is used to ensure that transactions are | ||
/// processed in the order they are intended, and to prevent the same transaction from being | ||
/// processed multiple times. | ||
/// | ||
/// The nonce manager in Alloy is a layer that helps you manage the nonce | ||
/// of transactions by keeping track of the current nonce for a given account and automatically | ||
/// incrementing it as needed. This can be useful if you want to ensure that transactions are sent | ||
/// in the correct order, or if you want to avoid having to manually manage the nonce yourself. | ||
#[tokio::main] | ||
async fn main() -> Result<()> { | ||
// Spin up a local Anvil node. | ||
// Ensure `anvil` is available in $PATH | ||
let anvil = Anvil::new().try_spawn()?; | ||
|
||
// Set up the wallets. | ||
let wallet: LocalWallet = anvil.keys()[0].clone().into(); | ||
let from = wallet.address(); | ||
|
||
// Create a provider with the signer. | ||
let http = anvil.endpoint().parse()?; | ||
let provider = ProviderBuilder::new() | ||
// Add the `ManagedNonceLayer` to the provider | ||
.layer(ManagedNonceLayer) | ||
.signer(EthereumSigner::from(wallet)) | ||
.on_client(RpcClient::new_http(http)); | ||
|
||
// Create an EIP-1559 type transaction. | ||
let tx = TransactionRequest::default() | ||
.with_from(from) | ||
.with_to(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into()) | ||
.with_value(U256::from(100)) | ||
.with_gas_limit(U256::from(21000)) | ||
.with_max_fee_per_gas(U256::from(20e9)) | ||
.with_max_priority_fee_per_gas(U256::from(1e9)) | ||
.with_chain_id(anvil.chain_id()); | ||
|
||
// Send the transaction, the nonce (0) is automatically managed by the provider. | ||
let builder = provider.send_transaction(tx.clone()).await?; | ||
let node_hash = *builder.tx_hash(); | ||
let pending_transaction = provider.get_transaction_by_hash(node_hash).await?; | ||
assert_eq!(pending_transaction.nonce, 0); | ||
|
||
println!("Transaction sent with nonce: {}", pending_transaction.nonce); | ||
|
||
// Send the transaction, the nonce (1) is automatically managed by the provider. | ||
let builder = provider.send_transaction(tx).await?; | ||
let node_hash = *builder.tx_hash(); | ||
let pending_transaction = provider.get_transaction_by_hash(node_hash).await?; | ||
assert_eq!(pending_transaction.nonce, 1); | ||
|
||
println!("Transaction sent with nonce: {}", pending_transaction.nonce); | ||
|
||
Ok(()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
//! Example of using the `SignerLayer` in the provider. | ||
use alloy::{ | ||
network::{EthereumSigner, TransactionBuilder}, | ||
node_bindings::Anvil, | ||
primitives::{address, b256, U256}, | ||
providers::{Provider, ProviderBuilder}, | ||
rpc::{client::RpcClient, types::eth::request::TransactionRequest}, | ||
signers::wallet::LocalWallet, | ||
}; | ||
use eyre::Result; | ||
|
||
#[tokio::main] | ||
async fn main() -> Result<()> { | ||
// Spin up a local Anvil node. | ||
// Ensure `anvil` is available in $PATH | ||
let anvil = Anvil::new().try_spawn()?; | ||
|
||
// Set up the wallets. | ||
let wallet: LocalWallet = anvil.keys()[0].clone().into(); | ||
let from = wallet.address(); | ||
|
||
// Create a provider with the signer. | ||
let http = anvil.endpoint().parse()?; | ||
let provider = ProviderBuilder::new() | ||
// Add the `SignerLayer` to the provider | ||
.signer(EthereumSigner::from(wallet)) | ||
.on_client(RpcClient::new_http(http)); | ||
|
||
// Create a legacy type transaction. | ||
let tx = TransactionRequest::default() | ||
.with_nonce(0) | ||
.with_from(from) | ||
.with_to(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into()) | ||
.with_value(U256::from(100)) | ||
.with_gas_price(U256::from(20e9)) | ||
.with_gas_limit(U256::from(21000)); | ||
|
||
let builder = provider.send_transaction(tx).await?; | ||
let node_hash = *builder.tx_hash(); | ||
|
||
println!( | ||
"Node hash matches expected hash: {}", | ||
node_hash == b256!("eb56033eab0279c6e9b685a5ec55ea0ff8d06056b62b7f36974898d4fbb57e64") | ||
); | ||
|
||
let pending = builder.register().await?; | ||
let pending_transaction_hash = *pending.tx_hash(); | ||
|
||
println!( | ||
"Pending transaction hash matches node hash: {}", | ||
pending_transaction_hash == node_hash | ||
); | ||
|
||
let transaction_hash = pending.await?; | ||
assert_eq!(transaction_hash, node_hash); | ||
|
||
println!("Transaction hash matches node hash: {}", transaction_hash == node_hash); | ||
|
||
let receipt = | ||
provider.get_transaction_receipt(transaction_hash).await.unwrap().expect("no receipt"); | ||
let receipt_hash = receipt.transaction_hash; | ||
assert_eq!(receipt_hash, node_hash); | ||
|
||
println!("Transaction receipt hash matches node hash: {}", receipt_hash == node_hash); | ||
|
||
Ok(()) | ||
} |