Skip to content

Commit

Permalink
feat(cast): add wallet sign --no-hash (#7180)
Browse files Browse the repository at this point in the history
* feat(cast): add `wallet sign --no-hash`

* doc

* doc
  • Loading branch information
DaniPopes authored Feb 20, 2024
1 parent 77332d6 commit 644e31e
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 42 deletions.
22 changes: 14 additions & 8 deletions crates/cast/bin/cmd/wallet/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,13 @@ pub enum WalletSubcommands {
/// Sign a message or typed data.
#[clap(visible_alias = "s")]
Sign {
/// The message or typed data to sign.
/// The message, typed data, or hash to sign.
///
/// Messages starting with 0x are expected to be hex encoded, which get decoded before
/// being signed.
///
/// Messages starting with 0x are expected to be hex encoded,
/// which get decoded before being signed.
/// The message will be prefixed with the Ethereum Signed Message header and hashed before
/// signing.
/// signing, unless `--no-hash` is provided.
///
/// Typed data can be provided as a json string or a file name.
/// Use --data flag to denote the message is a string of typed data.
Expand All @@ -92,15 +93,18 @@ pub enum WalletSubcommands {
/// The data should be formatted as JSON.
message: String,

/// If provided, the message will be treated as typed data.
/// Treat the message as JSON typed data.
#[clap(long)]
data: bool,

/// If provided, the message will be treated as a file name containing typed data. Requires
/// --data.
/// Treat the message as a file containing JSON typed data. Requires `--data`.
#[clap(long, requires = "data")]
from_file: bool,

/// Treat the message as a raw 32-byte hash and sign it directly without hashing it again.
#[clap(long, conflicts_with = "data")]
no_hash: bool,

#[clap(flatten)]
wallet: Wallet,
},
Expand Down Expand Up @@ -247,7 +251,7 @@ impl WalletSubcommands {
let addr = wallet.address();
println!("{}", addr.to_alloy().to_checksum(None));
}
WalletSubcommands::Sign { message, data, from_file, wallet } => {
WalletSubcommands::Sign { message, data, from_file, no_hash, wallet } => {
let wallet = wallet.signer(0).await?;
let sig = if data {
let typed_data: TypedData = if from_file {
Expand All @@ -258,6 +262,8 @@ impl WalletSubcommands {
serde_json::from_str(&message)?
};
wallet.sign_typed_data(&typed_data).await?
} else if no_hash {
wallet.sign_hash(&message.parse()?).await?
} else {
wallet.sign_message(Self::hex_str_to_bytes(&message)?).await?
};
Expand Down
2 changes: 2 additions & 0 deletions crates/wallets/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,6 @@ pub enum WalletSignerError {
Trezor(#[from] TrezorError),
#[error(transparent)]
Aws(#[from] AwsSignerError),
#[error("{0} cannot sign raw hashes")]
CannotSignRawHash(&'static str),
}
45 changes: 11 additions & 34 deletions crates/wallets/src/wallet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use crate::{
error::{PrivateKeyError, WalletSignerError},
raw_wallet::RawWallet,
};
use alloy_primitives::Address;
use alloy_primitives::{Address, B256};
use async_trait::async_trait;
use clap::Parser;
use ethers_core::types::{
Expand Down Expand Up @@ -457,39 +457,16 @@ impl Signer for WalletSigner {
}
}

#[async_trait]
impl Signer for &WalletSigner {
type Error = WalletSignerError;

async fn sign_message<S: Send + Sync + AsRef<[u8]>>(
&self,
message: S,
) -> Result<Signature, Self::Error> {
(*self).sign_message(message).await
}

async fn sign_transaction(&self, message: &TypedTransaction) -> Result<Signature, Self::Error> {
(*self).sign_transaction(message).await
}

async fn sign_typed_data<T: Eip712 + Send + Sync>(
&self,
payload: &T,
) -> Result<Signature, Self::Error> {
(*self).sign_typed_data(payload).await
}

fn address(&self) -> ethers_core::types::Address {
(*self).address()
}

fn chain_id(&self) -> u64 {
(*self).chain_id()
}

fn with_chain_id<T: Into<u64>>(self, chain_id: T) -> Self {
let _ = chain_id;
self
impl WalletSigner {
pub async fn sign_hash(&self, hash: &B256) -> Result<Signature, WalletSignerError> {
match self {
// TODO: AWS can sign hashes but utilities aren't exposed in ethers-signers.
// TODO: Implement with alloy-signer.
Self::Aws(_aws) => Err(WalletSignerError::CannotSignRawHash("AWS")),
Self::Ledger(_) => Err(WalletSignerError::CannotSignRawHash("Ledger")),
Self::Local(wallet) => wallet.sign_hash(hash.0.into()).map_err(Into::into),
Self::Trezor(_) => Err(WalletSignerError::CannotSignRawHash("Trezor")),
}
}
}

Expand Down

0 comments on commit 644e31e

Please sign in to comment.