Sitelet https://github.com/SharkHand3/examples/commit/2659346a725ea99ed6068c92364f4d658980eccd
Skip to content

Commit 2659346

Browse files
committed
add initial wallet examples
1 parent f155aed commit 2659346

10 files changed

Lines changed: 377 additions & 8 deletions

File tree

‎Cargo.toml‎

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,48 @@ exclude = ["examples/"]
1414
publish = false
1515

1616
[workspace.dependencies]
17-
alloy = { git = "https://github.com/alloy-rs/alloy", rev = "818b3e9", default-features = false }
17+
alloy-consensus = { git = "https://github.com/alloy-rs/alloy", rev = "818b3e9", default-features = false }
18+
alloy-contract = { git = "https://github.com/alloy-rs/alloy", rev = "818b3e9", default-features = false }
19+
alloy-eips = { git = "https://github.com/alloy-rs/alloy", rev = "818b3e9", default-features = false }
20+
alloy-genesis = { git = "https://github.com/alloy-rs/alloy", rev = "818b3e9", default-features = false }
21+
alloy-json-rpc = { git = "https://github.com/alloy-rs/alloy", rev = "818b3e9", default-features = false }
22+
alloy-network = { git = "https://github.com/alloy-rs/alloy", rev = "818b3e9", default-features = false }
23+
alloy-node-bindings = { git = "https://github.com/alloy-rs/alloy", rev = "818b3e9", default-features = false }
24+
alloy-provider = { git = "https://github.com/alloy-rs/alloy", rev = "818b3e9", default-features = false }
25+
alloy-pubsub = { git = "https://github.com/alloy-rs/alloy", rev = "818b3e9", default-features = false }
26+
alloy-rpc-client = { git = "https://github.com/alloy-rs/alloy", rev = "818b3e9", default-features = false }
27+
alloy-rpc-engine-types = { git = "https://github.com/alloy-rs/alloy", rev = "818b3e9", default-features = false }
28+
alloy-rpc-trace-types = { git = "https://github.com/alloy-rs/alloy", rev = "818b3e9", default-features = false }
29+
alloy-rpc-types = { git = "https://github.com/alloy-rs/alloy", rev = "818b3e9", default-features = false }
30+
alloy-serde = { git = "https://github.com/alloy-rs/alloy", rev = "818b3e9", default-features = false }
31+
alloy-signer = { git = "https://github.com/alloy-rs/alloy", rev = "818b3e9", default-features = false }
32+
alloy-signer-aws = { git = "https://github.com/alloy-rs/alloy", rev = "818b3e9", default-features = false }
33+
alloy-signer-gcp = { git = "https://github.com/alloy-rs/alloy", rev = "818b3e9", default-features = false }
34+
alloy-signer-ledger = { git = "https://github.com/alloy-rs/alloy", rev = "818b3e9", default-features = false }
35+
alloy-signer-trezor = { git = "https://github.com/alloy-rs/alloy", rev = "818b3e9", default-features = false }
36+
alloy-transport = { git = "https://github.com/alloy-rs/alloy", rev = "818b3e9", default-features = false }
37+
alloy-transport-http = { git = "https://github.com/alloy-rs/alloy", rev = "818b3e9", default-features = false }
38+
alloy-transport-ipc = { git = "https://github.com/alloy-rs/alloy", rev = "818b3e9", default-features = false }
39+
alloy-transport-ws = { git = "https://github.com/alloy-rs/alloy", rev = "818b3e9", default-features = false }
40+
41+
alloy-primitives = { version = "0.6.4", default-features = false, features = [
42+
"std",
43+
] }
44+
alloy-sol-types = { version = "0.6.4", default-features = false, features = [
45+
"std",
46+
] }
47+
48+
# async
49+
tokio = "1"
50+
51+
# misc
52+
rand = "0.8"
53+
reqwest = { version = "0.11", default-features = false }
54+
55+
## serde
56+
serde = { version = "1.0", features = ["derive"] }
57+
58+
# TODO: remove after https://github.com/alloy-rs/alloy/pull/309
59+
coins-bip39 = { version = "0.8.7", default-features = false, features = [
60+
"english",
61+
] }

‎README.md‎

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -89,11 +89,11 @@ cargo run --example mnemonic_signer
8989
- [ ] Wallets
9090
- [ ] AWS signer
9191
- [ ] GCP signer
92-
- [ ] [Ledger signer]
93-
- [ ] [Private key signer]
94-
- [ ] [Mnemonic signer]
95-
- [ ] [Sign message]
96-
- [ ] [Sign permit hash]
97-
- [ ] [Trezor signer]
98-
- [ ] [Yubi signer]
92+
- [ ] [Ledger signer](./examples/wallets/examples/ledger_signer.rs)
93+
- [ ] [Private key signer](./examples/wallets/examples/private_key_signer.rs)
94+
- [ ] [Mnemonic signer](./examples/wallets/examples/mnemonic_signer.rs)
95+
- [ ] [Sign message](./examples/wallets/examples/sign_message.rs)
96+
- [ ] [Sign permit hash](./examples/wallets/examples/sign_permit_hash.rs)
97+
- [ ] [Trezor signer](./examples/wallets/examples/trezor_signer.rs)
98+
- [ ] [Yubi signer](./examples/wallets/examples/yubi_signer.rs)
9999
- [ ] Keystore signer

‎examples/wallets/Cargo.toml‎

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
[package]
2+
name = "examples-wallets"
3+
4+
version.workspace = true
5+
edition.workspace = true
6+
rust-version.workspace = true
7+
authors.workspace = true
8+
license.workspace = true
9+
homepage.workspace = true
10+
repository.workspace = true
11+
exclude.workspace = true
12+
publish.workspace = true
13+
14+
[dev-dependencies]
15+
alloy-network.workspace = true
16+
alloy-node-bindings.workspace = true
17+
alloy-primitives.workspace = true
18+
alloy-provider.workspace = true
19+
alloy-rpc-client.workspace = true
20+
alloy-rpc-types.workspace = true
21+
alloy-signer = { workspace = true, features = [
22+
"eip712",
23+
"mnemonic",
24+
"yubihsm",
25+
] }
26+
alloy-signer-ledger.workspace = true
27+
alloy-signer-trezor.workspace = true
28+
alloy-sol-types.workspace = true
29+
alloy-transport-http.workspace = true
30+
31+
# TODO: remove after https://github.com/alloy-rs/alloy/pull/309
32+
coins-bip39.workspace = true
33+
rand.workspace = true
34+
reqwest.workspace = true
35+
serde.workspace = true
36+
tokio = { workspace = true, features = ["macros", "rt-multi-thread"] }
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
//! Example of signing and sending a transaction using a Ledger device.
2+
3+
use alloy_network::{Ethereum, EthereumSigner};
4+
use alloy_primitives::{address, U256};
5+
use alloy_provider::{Provider, ProviderBuilder, RootProvider};
6+
use alloy_rpc_client::RpcClient;
7+
use alloy_rpc_types::request::TransactionRequest;
8+
use alloy_signer_ledger::{HDPath, LedgerSigner};
9+
use alloy_transport_http::Http;
10+
use reqwest::Client;
11+
12+
#[tokio::main]
13+
async fn main() -> Result<(), Box<dyn std::error::Error>> {
14+
// Instantiate the application by acquiring a lock on the Ledger device.
15+
let signer = LedgerSigner::new(HDPath::LedgerLive(0), Some(1)).await?;
16+
17+
// Create a provider with the signer and the network.
18+
let http = Http::<Client>::new("http://localhost:8545".parse()?);
19+
let provider = ProviderBuilder::<_, Ethereum>::new()
20+
.signer(EthereumSigner::from(signer))
21+
.network::<Ethereum>()
22+
.provider(RootProvider::new(RpcClient::new(http, true)));
23+
24+
// Create a transaction.
25+
let tx = TransactionRequest {
26+
value: Some(U256::from(100)),
27+
to: address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into(),
28+
gas_price: Some(U256::from(20e9)),
29+
gas: Some(U256::from(21000)),
30+
..Default::default()
31+
};
32+
33+
// Broadcast the transaction and wait for the receipt.
34+
let receipt = provider.send_transaction(tx).await?.with_confirmations(3).get_receipt().await?;
35+
36+
println!("Send transaction: {:?}", receipt.transaction_hash.unwrap());
37+
38+
Ok(())
39+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
//! Example of using `MnemonicBuilder` to access a wallet from a mnemonic phrase.
2+
3+
use alloy_signer::MnemonicBuilder;
4+
// TODO: remove after https://github.com/alloy-rs/alloy/pull/309
5+
use coins_bip39::English;
6+
7+
#[tokio::main]
8+
async fn main() -> Result<(), Box<dyn std::error::Error>> {
9+
let phrase = "work man father plunge mystery proud hollow address reunion sauce theory bonus";
10+
let index = 0u32;
11+
let password = "TREZOR123";
12+
13+
// Access mnemonic phrase with password
14+
// Child key at derivation path: m/44'/60'/0'/0/{index}
15+
let wallet = MnemonicBuilder::<English>::default()
16+
.phrase(phrase)
17+
.index(index)?
18+
// Use this if your mnemonic is encrypted
19+
.password(password)
20+
.build()?;
21+
22+
println!("Wallet: {:?}", wallet);
23+
24+
// Generate a random wallet (24 word phrase) at custom derivation path
25+
let mut rng = rand::thread_rng();
26+
let wallet = MnemonicBuilder::<English>::default()
27+
.word_count(24)
28+
.derivation_path("m/44'/60'/0'/2/1")?
29+
// Optionally add this if you want the generated mnemonic to be written
30+
// to a file
31+
// .write_to(path)
32+
.build_random(&mut rng)?;
33+
34+
println!("Random wallet: {:?}", wallet);
35+
36+
Ok(())
37+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
//! Example of using a local wallet to sign and broadcast a transaction on a local Anvil node.
2+
3+
use alloy_network::{Ethereum, EthereumSigner};
4+
use alloy_node_bindings::Anvil;
5+
use alloy_primitives::{U256, U64};
6+
use alloy_provider::{Provider, ProviderBuilder, RootProvider};
7+
use alloy_rpc_client::RpcClient;
8+
use alloy_rpc_types::request::TransactionRequest;
9+
use alloy_signer::LocalWallet;
10+
use alloy_transport_http::Http;
11+
use reqwest::Client;
12+
13+
#[tokio::main]
14+
async fn main() -> Result<(), Box<dyn std::error::Error>> {
15+
// Spin up an Anvil node.
16+
let anvil = Anvil::new().block_time(1).spawn();
17+
18+
// Set up the wallets.
19+
let alice: LocalWallet = anvil.keys()[0].clone().into();
20+
let bob: LocalWallet = anvil.keys()[1].clone().into();
21+
22+
// Create a provider with a signer and the network.
23+
let http = Http::<Client>::new(anvil.endpoint().parse()?);
24+
let provider = ProviderBuilder::<_, Ethereum>::new()
25+
.signer(EthereumSigner::from(alice))
26+
.network::<Ethereum>()
27+
.provider(RootProvider::new(RpcClient::new(http, true)));
28+
29+
// Create a transaction.
30+
let tx = TransactionRequest {
31+
value: Some(U256::from(100)),
32+
to: Some(bob.address()),
33+
nonce: Some(U64::from(0)),
34+
gas_price: Some(U256::from(20e9)),
35+
gas: Some(U256::from(21000)),
36+
..Default::default()
37+
};
38+
39+
// Broadcast the transaction and wait for the receipt.
40+
let receipt = provider.send_transaction(tx).await?.with_confirmations(1).get_receipt().await?;
41+
42+
println!("Send transaction: {:?}", receipt.transaction_hash.unwrap());
43+
44+
Ok(())
45+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//! Example of signing a message with a wallet.
2+
3+
use alloy_signer::{LocalWallet, Signer};
4+
5+
#[tokio::main]
6+
async fn main() -> Result<(), Box<dyn std::error::Error>> {
7+
// Setup up wallet.
8+
let wallet = LocalWallet::random();
9+
10+
// Optionally, the wallet's chain id can be set, in order to use EIP-155
11+
// replay protection with different chains
12+
let wallet = wallet.with_chain_id(Some(1337));
13+
14+
// The message to sign.
15+
let message = b"hello";
16+
17+
// Sign the message asynchronously with the wallet.
18+
let signature = wallet.sign_message(message).await?;
19+
20+
println!("Signature produced by {:?}: {:?}", wallet.address(), signature);
21+
println!(
22+
"Signature recovered address: {:?}",
23+
signature.recover_address_from_msg(&message[..]).unwrap()
24+
);
25+
26+
Ok(())
27+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
//! Example of signing a permit hash using a wallet.
2+
3+
use alloy_primitives::{address, keccak256, U256};
4+
use alloy_signer::{LocalWallet, Signer};
5+
use alloy_sol_types::{eip712_domain, sol, SolStruct};
6+
use serde::Serialize;
7+
8+
sol! {
9+
#[derive(Debug, Serialize)]
10+
struct Permit {
11+
address owner;
12+
address spender;
13+
uint256 value;
14+
uint256 nonce;
15+
uint256 deadline;
16+
}
17+
}
18+
19+
#[tokio::main]
20+
async fn main() -> Result<(), Box<dyn std::error::Error>> {
21+
// Setup up wallet.
22+
let wallet = LocalWallet::random();
23+
24+
let domain = eip712_domain! {
25+
name: "Uniswap V2",
26+
version: "1",
27+
chain_id: 1,
28+
verifying_contract: address!("B4e16d0168e52d35CaCD2c6185b44281Ec28C9Dc"),
29+
salt: keccak256("test"),
30+
};
31+
32+
let permit = Permit {
33+
owner: wallet.address(),
34+
spender: address!("B4e16d0168e52d35CaCD2c6185b44281Ec28C9Dc"),
35+
value: U256::from(100),
36+
nonce: U256::from(0),
37+
deadline: U256::from(0),
38+
};
39+
40+
// Derive the EIP-712 signing hash.
41+
let hash = permit.eip712_signing_hash(&domain);
42+
43+
// Sign the hash asynchronously with the wallet.
44+
let signature = wallet.sign_typed_data(&permit, &domain).await?;
45+
46+
println!(
47+
"Recovered address matches wallet address: {:?}",
48+
signature.recover_address_from_prehash(&hash)? == wallet.address()
49+
);
50+
51+
println!("Wallet signature matches: {:?}", wallet.sign_hash(&hash).await? == signature);
52+
53+
Ok(())
54+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
//! Example of signing and sending a transaction using a Trezor device.
2+
3+
use alloy_network::{Ethereum, EthereumSigner};
4+
use alloy_primitives::{address, U256};
5+
use alloy_provider::{Provider, ProviderBuilder, RootProvider};
6+
use alloy_rpc_client::RpcClient;
7+
use alloy_rpc_types::request::TransactionRequest;
8+
use alloy_signer_trezor::{TrezorHDPath, TrezorSigner};
9+
use alloy_transport_http::Http;
10+
use reqwest::Client;
11+
12+
#[tokio::main]
13+
async fn main() -> Result<(), Box<dyn std::error::Error>> {
14+
// Instantiate the application by acquiring a lock on the Trezor device.
15+
let signer = TrezorSigner::new(TrezorHDPath::TrezorLive(0), Some(1)).await?;
16+
17+
// Create a provider with the signer and the network.
18+
let http = Http::<Client>::new("http://localhost:8545".parse()?);
19+
let provider = ProviderBuilder::<_, Ethereum>::new()
20+
.signer(EthereumSigner::from(signer))
21+
.network::<Ethereum>()
22+
.provider(RootProvider::new(RpcClient::new(http, true)));
23+
24+
// Create a transaction.
25+
let tx = TransactionRequest {
26+
value: Some(U256::from(100)),
27+
to: address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into(),
28+
gas_price: Some(U256::from(20e9)),
29+
gas: Some(U256::from(21000)),
30+
..Default::default()
31+
};
32+
33+
// Broadcast the transaction and wait for the receipt.
34+
let receipt = provider.send_transaction(tx).await?.with_confirmations(3).get_receipt().await?;
35+
36+
println!("Send transaction: {:?}", receipt.transaction_hash.unwrap());
37+
38+
Ok(())
39+
}

0 commit comments

Comments
 (0)