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 and klkvr committed Feb 20, 2024
1 parent adf2d61 commit ce59859
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 8 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: WalletOpts,
},
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().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 @@ -23,4 +23,6 @@ pub enum WalletSignerError {
Io(#[from] std::io::Error),
#[error(transparent)]
InvalidHex(#[from] FromHexError),
#[error("{0} cannot sign raw hashes")]
CannotSignRawHash(&'static str),
}
14 changes: 14 additions & 0 deletions crates/wallets/src/wallet_signer.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::error::WalletSignerError;
use alloy_primitives::B256;
use async_trait::async_trait;
use ethers_core::types::{
transaction::{eip2718::TypedTransaction, eip712::Eip712},
Expand Down Expand Up @@ -153,6 +154,19 @@ impl Signer for &WalletSigner {
}
}

impl WalletSigner {
pub async fn sign_hash(&self, hash: &B256) -> Result<Signature> {
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")),
}
}
}

/// Signers that require user action to be obtained.
#[derive(Debug, Clone)]
pub enum PendingSigner {
Expand Down

0 comments on commit ce59859

Please sign in to comment.