Skip to content

Commit

Permalink
Use custom filler for wallet
Browse files Browse the repository at this point in the history
  • Loading branch information
danhper committed Sep 8, 2024
1 parent ec704b7 commit 245c71c
Show file tree
Hide file tree
Showing 3 changed files with 152 additions and 9 deletions.
25 changes: 16 additions & 9 deletions src/interpreter/env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,24 @@ use alloy::{
primitives::{Address, B256},
providers::{
ext::AnvilApi,
fillers::{FillProvider, JoinFill, RecommendedFiller, WalletFiller},
fillers::{FillProvider, JoinFill, RecommendedFiller},
Provider, ProviderBuilder, RootProvider, WalletProvider,
},
signers::{ledger::HDPath, local::PrivateKeySigner, Signature},
signers::{ledger::HDPath, Signature},
transports::http::{Client, Http},
};
use anyhow::{anyhow, bail, Result};
use coins_ledger::{transports::LedgerAsync, Ledger};

use crate::{interpreter::Config, vendor::ledger_signer::LedgerSigner};
use crate::{
interpreter::Config,
vendor::{ledger_signer::LedgerSigner, optional_wallet_filler::OptionalWalletFiller},
};

use super::{evaluate_expression, types::Type, ContractInfo, Value};

type RecommendedFillerWithWallet = JoinFill<RecommendedFiller, WalletFiller<EthereumWallet>>;
type RecommendedFillerWithWallet =
JoinFill<RecommendedFiller, OptionalWalletFiller<EthereumWallet>>;
type EclairProvider =
FillProvider<RecommendedFillerWithWallet, RootProvider<Http<Client>>, Http<Client>, Ethereum>;

Expand All @@ -49,11 +53,9 @@ unsafe impl std::marker::Send for Env {}
impl Env {
pub fn new(config: Config) -> Self {
let rpc_url = config.rpc_url.parse().unwrap();
let random_signer = PrivateKeySigner::random();
let wallet = EthereumWallet::from(random_signer);
let provider = ProviderBuilder::new()
.with_recommended_fillers()
.wallet(wallet)
.filler(OptionalWalletFiller::<EthereumWallet>::new())
.on_http(rpc_url);
Env {
variables: vec![HashMap::new()],
Expand Down Expand Up @@ -306,10 +308,15 @@ impl Env {
};
self.config.rpc_url = rpc_url.to_string();

let wallet = wallet.unwrap_or_else(|| self.provider.wallet().clone());
let mut wallet_filler = OptionalWalletFiller::new();
if let Some(w) = wallet {
wallet_filler.set_wallet(w);
} else if self.is_wallet_connected {
wallet_filler.set_wallet(self.provider.wallet().clone());
}
let provider = ProviderBuilder::new()
.with_recommended_fillers()
.wallet(wallet)
.filler(wallet_filler)
.on_http(rpc_url);
self.provider = provider;
Ok(())
Expand Down
1 change: 1 addition & 0 deletions src/vendor/mod.rs
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
pub mod ledger_signer;
pub mod optional_wallet_filler;
135 changes: 135 additions & 0 deletions src/vendor/optional_wallet_filler.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
use alloy::network::{Network, NetworkWallet, TransactionBuilder};
use alloy::providers::fillers::{FillerControlFlow, TxFiller};
use alloy::providers::{Provider, SendableTx, WalletProvider};
use alloy::transports::{RpcError, Transport, TransportResult};

/// A layer that signs transactions locally.
///
/// The layer uses a [`NetworkWallet`] to sign transactions sent using
/// [`Provider::send_transaction`] locally before passing them to the node with
/// [`Provider::send_raw_transaction`].
/// If no wallet is set, it is a no-op.
///
/// ```
#[derive(Clone, Debug)]
pub struct OptionalWalletFiller<W> {
wallet: Option<W>,
}

impl<W> AsRef<Option<W>> for OptionalWalletFiller<W> {
fn as_ref(&self) -> &Option<W> {
&self.wallet
}
}

impl<W> AsMut<Option<W>> for OptionalWalletFiller<W> {
fn as_mut(&mut self) -> &mut Option<W> {
&mut self.wallet
}
}

impl<W> OptionalWalletFiller<W> {
/// Creates a new optional wallet layer.
pub const fn new() -> Self {
Self { wallet: None }
}

pub fn set_wallet(&mut self, wallet: W) {
self.wallet = Some(wallet);
}

pub fn unsafe_as_ref(&self) -> &W {
self.wallet.as_ref().unwrap()
}

pub fn unsafe_as_mut(&mut self) -> &mut W {
self.wallet.as_mut().unwrap()
}
}

impl<W> Default for OptionalWalletFiller<W> {
fn default() -> Self {
Self::new()
}
}

impl<W, N> TxFiller<N> for OptionalWalletFiller<W>
where
N: Network,
W: NetworkWallet<N> + Clone,
{
type Fillable = ();

fn status(&self, tx: &<N as Network>::TransactionRequest) -> FillerControlFlow {
if tx.from().is_none() {
return FillerControlFlow::Ready;
}
if self.wallet.is_none() {
return FillerControlFlow::Finished;
}

match tx.complete_preferred() {
Ok(_) => FillerControlFlow::Ready,
Err(e) => FillerControlFlow::Missing(vec![("Wallet", e)]),
}
}

fn fill_sync(&self, tx: &mut SendableTx<N>) {
if let Some(builder) = tx.as_mut_builder() {
if builder.from().is_none() && self.wallet.is_some() {
builder.set_from(self.wallet.as_ref().unwrap().default_signer_address());
}
}
}

async fn prepare<P, T>(
&self,
_provider: &P,
_tx: &<N as Network>::TransactionRequest,
) -> TransportResult<Self::Fillable>
where
P: Provider<T, N>,
T: Transport + Clone,
{
Ok(())
}

async fn fill(
&self,
_fillable: Self::Fillable,
tx: SendableTx<N>,
) -> TransportResult<SendableTx<N>> {
if self.wallet.is_none() {
return Ok(tx);
}
let builder = match tx {
SendableTx::Builder(builder) => builder,
_ => return Ok(tx),
};

let envelope = builder
.build(self.wallet.as_ref().unwrap())
.await
.map_err(RpcError::local_usage)?;

Ok(SendableTx::Envelope(envelope))
}
}

impl<W, N> WalletProvider<N> for OptionalWalletFiller<W>
where
W: NetworkWallet<N> + Clone,
N: Network,
{
type Wallet = W;

#[inline(always)]
fn wallet(&self) -> &Self::Wallet {
self.unsafe_as_ref()
}

#[inline(always)]
fn wallet_mut(&mut self) -> &mut Self::Wallet {
self.unsafe_as_mut()
}
}

0 comments on commit 245c71c

Please sign in to comment.