Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add example #194

Merged
merged 5 commits into from
Aug 25, 2023
Merged
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
646 changes: 324 additions & 322 deletions Cargo.lock

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions crates/contracts/src/entry_point.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,13 @@ impl<M: Middleware + 'static> EntryPoint<M> {
}
}

pub async fn get_nonce(&self, address: &Address, key: U256) -> Result<U256, EntryPointErr> {
self.entry_point_api
.get_nonce(*address, key)
.await
.map_err(|e| EntryPointErr::UnknownErr(format!("Error getting nonce: {e:?}")))
}

pub async fn get_sender_address(
&self,
init_code: Bytes,
Expand Down
25 changes: 23 additions & 2 deletions examples/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,36 @@ description = """
AA (ERC-4337) bundler examples
"""

[dev-dependencies]

[dependencies]
alloy-primitives = "0.3"
alloy-sol-types = "0.3"
anyhow = "1"
ethers = { workspace = true }
reqwest = { version = "0.11.4", features = ["json"] }
serde = "1"
serde_json = "1"
silius-contracts = { path = "../crates/contracts" }
silius-primitives = { path = "../crates/primitives" }
silius-tests = { path = "../tests" }
tokio = { workspace = true }

[package.metadata.cargo-udeps.ignore]
normal = ["anyhow", "silius-contracts", "silius-primitives", "silius-tests"]

[[example]]
name = "user-operation"
path = "user_operation.rs"

[[example]]
name = "simple_account_create"
path = "simple_account/simple_account_create.rs"

[[example]]
name = "simple_account_deposit"
path = "simple_account/deposit.rs"

[[example]]
name = "simple_account_transfer"
path = "simple_account/transfer.rs"


20 changes: 20 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,24 @@

```bash
cargo run --example user-operation
```

### Create simple account


```bash
SEED_PHRASE="test test test test test test test test test test test junk" BUNDLER_URL="http://127.0.0.1:3000" cargo run --example simple_account_create
```

### Deposit funds to entrypoint

```bash
SEED_PHRASE="test test test test test test test test test test test junk" PROVIDER_URL="http://127.0.0.1:3000" cargo run --example deposit
```


### Simple Account Transfer

```bash
SEED_PHRASE="test test test test test test test test test test test junk" BUNDLER_URL="http://127.0.0.1:3000" cargo run --example transfer
```
55 changes: 55 additions & 0 deletions examples/simple_account/deposit.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
use std::{env, sync::Arc, time::Duration};

use ethers::{
prelude::{gas_oracle::ProviderOracle, MiddlewareBuilder, SignerMiddleware},
providers::{Http, Middleware, Provider},
signers::{coins_bip39::English, MnemonicBuilder, Signer},
types::{transaction::eip2718::TypedTransaction, Address, U256},
utils::parse_ether,
};
use silius_contracts::entry_point::EntryPointAPI;
use silius_primitives::consts::entry_point::ADDRESS;
use silius_tests::common::gen::SimpleAccountFactory;

// stackup simple account factory
const SIMPLE_ACCOUNT_FACTORY: &str = "0x9406Cc6185a346906296840746125a0E44976454";
const CREATE_INDEX: u64 = 1;
const SEND_VALUE: &str = "0.01"; // ether unit

#[tokio::main]
async fn main() -> anyhow::Result<()> {
let seed_phrase = env::var("SEED_PHRASE").unwrap();
let provider_url = env::var("PROVIDER_URL").unwrap();
let wallet = MnemonicBuilder::<English>::default()
.phrase(seed_phrase.as_str())
.build()?;
let provider = Provider::<Http>::try_from(provider_url)?.interval(Duration::from_millis(10u64));
let client = SignerMiddleware::new(provider.clone(), wallet.clone().with_chain_id(5u64))
.nonce_manager(wallet.address())
.gas_oracle(ProviderOracle::new(provider.clone()));
let provider = Arc::new(client);

let simple_account_factory_address = SIMPLE_ACCOUNT_FACTORY.to_string().parse::<Address>()?;
let simple_account_factory =
SimpleAccountFactory::new(simple_account_factory_address, provider.clone());

let owner_address = wallet.address();
println!("simple_account_factory: {:?}", simple_account_factory);
println!("Signer address: {:x}", owner_address);
let address = simple_account_factory
.get_address(owner_address, U256::from(CREATE_INDEX))
.call()
.await?;
println!("Smart account addresss: {:?}", address);

let entrypoint = EntryPointAPI::new(ADDRESS.parse::<Address>()?, provider.clone());
let call = entrypoint.deposit_to(address);
let mut tx: TypedTransaction = call.tx;
tx.set_value(parse_ether(SEND_VALUE)?);
println!("tx: {:?}", tx);
let pending_tx = provider.send_transaction(tx, None).await?;
println!("pending_tx: {:?}", pending_tx);
let receipt = pending_tx.await?;
println!("receipt: {:?}", receipt);
Ok(())
}
144 changes: 144 additions & 0 deletions examples/simple_account/simple_account_create.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
use std::{env, sync::Arc, time::Duration};

use ethers::{
prelude::{MiddlewareBuilder, SignerMiddleware},
providers::{Http, Middleware, Provider},
signers::{coins_bip39::English, MnemonicBuilder, Signer},
types::{transaction::eip2718::TypedTransaction, Address, Bytes, U256},
};
use reqwest;
use silius_examples::{simple_account::SimpleAccountExecute, EstimateResult, Request, Response};
use silius_primitives::consts::entry_point::ADDRESS;
use silius_primitives::UserOperation;
use silius_primitives::Wallet as UoWallet;
use silius_tests::common::gen::SimpleAccountFactory;

// stackup simple account factory
const SIMPLE_ACCOUNT_FACTORY: &str = "0x9406Cc6185a346906296840746125a0E44976454";
const CREATE_INDEX: u64 = 2;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
let seed_phrase = env::var("SEED_PHRASE").unwrap();
let bundler_url = env::var("BUNDLER_URL").unwrap();
let wallet = MnemonicBuilder::<English>::default()
.phrase(seed_phrase.as_str())
.build()?;
let provider =
Provider::<Http>::try_from(bundler_url.as_str())?.interval(Duration::from_millis(10u64));
let client = SignerMiddleware::new(provider.clone(), wallet.clone().with_chain_id(5u64))
.nonce_manager(wallet.address());
let provider = Arc::new(client);

let simple_account_factory_address = SIMPLE_ACCOUNT_FACTORY.to_string().parse::<Address>()?;
let simple_account_factory =
SimpleAccountFactory::new(simple_account_factory_address, provider.clone());

let owner_address = wallet.address();
println!("simple_account_factory: {:?}", simple_account_factory);
println!("Signer address: {:x}", owner_address);
let address = simple_account_factory
.get_address(owner_address, U256::from(CREATE_INDEX))
.call()
.await?;
println!("Smart account addresss: {:?}", address);
let nonce = provider.get_transaction_count(address, None).await?;
let call = simple_account_factory.create_account(owner_address, U256::from(CREATE_INDEX));
let tx: TypedTransaction = call.tx;
println!("tx: {:?}", tx);
let mut init_code = Vec::new();
init_code.extend_from_slice(simple_account_factory_address.as_bytes());
init_code.extend_from_slice(tx.data().unwrap().to_vec().as_slice());
println!("init_code: {:?}", init_code);

let (gas_price, priority_fee) = provider.estimate_eip1559_fees(None).await?;
println!(
"gas_price: {:?}, priority_fee: {:?}",
gas_price, priority_fee
);

let execution = SimpleAccountExecute::new(Address::zero(), U256::from(0), Bytes::default());
println!("{:}", Bytes::from(execution.encode()));
let user_op = UserOperation {
sender: address,
nonce,
init_code: Bytes::from(init_code),
call_data: Bytes::from(execution.encode()),
call_gas_limit: U256::from(1),
verification_gas_limit: U256::from(1000000u64),
pre_verification_gas: U256::from(1),
max_fee_per_gas: U256::from(1),
max_priority_fee_per_gas: priority_fee,
paymaster_and_data: Bytes::new(),
signature: Bytes::default(),
};
let uo_wallet = UoWallet::from_phrase(seed_phrase.as_str(), &U256::from(5), false)?;
let user_op = uo_wallet
.sign_uo(
&user_op,
&ADDRESS.to_string().parse::<Address>()?,
&U256::from(5),
)
.await?;

let value = serde_json::to_value(&user_op).unwrap();

let req_body = Request {
jsonrpc: "2.0".to_string(),
id: 1,
method: "eth_estimateUserOperationGas".to_string(),
params: vec![value, ADDRESS.to_string().into()],
};
println!("req_body: {:?}", serde_json::to_string(&req_body)?);
let post = reqwest::Client::builder()
.build()?
.post(bundler_url.as_str())
.json(&req_body)
.send()
.await?;
println!("post: {:?}", post);
let res = post.text().await?;
println!("res: {:?}", res);
let v = serde_json::from_str::<Response<EstimateResult>>(&res)?;
println!("json: {:?}", v);

let user_op = UserOperation {
pre_verification_gas: v
.result
.pre_verification_gas
.saturating_add(U256::from(1000)),
verification_gas_limit: v.result.verification_gas_limit,
call_gas_limit: v.result.call_gas_limit.saturating_add(U256::from(2000)),
max_priority_fee_per_gas: priority_fee,
max_fee_per_gas: gas_price,
..user_op
};
let user_op = uo_wallet
.sign_uo(
&user_op,
&ADDRESS.to_string().parse::<Address>()?,
&U256::from(5),
)
.await?;

let send_body = Request {
jsonrpc: "2.0".to_string(),
id: 1,
method: "eth_sendUserOperation".to_string(),
params: vec![
serde_json::to_value(&user_op).unwrap(),
ADDRESS.to_string().into(),
],
};
let post = reqwest::Client::builder()
.build()?
.post(bundler_url.as_str())
.json(&send_body)
.send()
.await?;

println!("post: {:?}", post);
let res = post.text().await?;
println!("res: {:?}", res);
Ok(())
}
Loading
Loading