Skip to content
This repository has been archived by the owner on Oct 19, 2024. It is now read-only.

feat(signers): Allow parsing of private key that has 0x prefix #2037

Merged
merged 1 commit into from
Jan 12, 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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,8 @@
- `eth-keystore-rs` crate updated. Allow an optional name for the to-be-generated
keystore file [#910](https://github.com/gakonst/ethers-rs/pull/910)
- [1983](https://github.com/gakonst/ethers-rs/pull/1983) Added a `from_bytes` function for the `Wallet` type.
- Allow parsing of private key that has `0x` prefix
[#2037](https://github.com/gakonst/ethers-rs/pull/2037)

### 0.6.0

Expand Down
61 changes: 61 additions & 0 deletions ethers-signers/src/wallet/private_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,12 +130,29 @@ impl FromStr for Wallet<SigningKey> {
type Err = WalletError;

fn from_str(src: &str) -> Result<Self, Self::Err> {
let src = src.strip_prefix("0x").or_else(|| src.strip_prefix("0X")).unwrap_or(src);
let src = hex::decode(src)?;
let sk = SigningKey::from_bytes(&src)?;
Ok(sk.into())
}
}

impl TryFrom<&str> for Wallet<SigningKey> {
type Error = WalletError;

fn try_from(value: &str) -> Result<Self, Self::Error> {
value.parse()
}
}

impl TryFrom<String> for Wallet<SigningKey> {
type Error = WalletError;

fn try_from(value: String) -> Result<Self, Self::Error> {
value.parse()
}
}
Comment on lines +140 to +154
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there's no transient impl when there's FromStr?

I guess we can add these

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason I added this is to enable user to have something like this:

fn create_client(url: &str, priv_key: impl TryInto<LocalWallet>) -> SignerMiddleware<Provider<Http>, LocalWallet>> {
    let wallet = priv_key.try_into().unwrap();
    // ...
}

And be able to pass as argument &str, String, SigningKey, and SecretKey<Secp256k1>.


#[cfg(test)]
#[cfg(not(target_arch = "wasm32"))]
mod tests {
Expand Down Expand Up @@ -325,4 +342,48 @@ mod tests {
assert_eq!(wallet.chain_id, wallet_from_bytes.chain_id);
assert_eq!(wallet.signer, wallet_from_bytes.signer);
}

#[test]
fn key_from_str() {
let wallet: Wallet<SigningKey> =
"0000000000000000000000000000000000000000000000000000000000000001".parse().unwrap();

// Check FromStr and `0x`
let wallet_0x: Wallet<SigningKey> =
"0x0000000000000000000000000000000000000000000000000000000000000001".parse().unwrap();
assert_eq!(wallet.address, wallet_0x.address);
assert_eq!(wallet.chain_id, wallet_0x.chain_id);
assert_eq!(wallet.signer, wallet_0x.signer);

// Check FromStr and `0X`
let wallet_0x_cap: Wallet<SigningKey> =
"0X0000000000000000000000000000000000000000000000000000000000000001".parse().unwrap();
assert_eq!(wallet.address, wallet_0x_cap.address);
assert_eq!(wallet.chain_id, wallet_0x_cap.chain_id);
assert_eq!(wallet.signer, wallet_0x_cap.signer);

// Check TryFrom<&str>
let wallet_0x_tryfrom_str: Wallet<SigningKey> =
"0x0000000000000000000000000000000000000000000000000000000000000001"
.try_into()
.unwrap();
assert_eq!(wallet.address, wallet_0x_tryfrom_str.address);
assert_eq!(wallet.chain_id, wallet_0x_tryfrom_str.chain_id);
assert_eq!(wallet.signer, wallet_0x_tryfrom_str.signer);

// Check TryFrom<String>
let wallet_0x_tryfrom_string: Wallet<SigningKey> =
"0x0000000000000000000000000000000000000000000000000000000000000001"
.to_string()
.try_into()
.unwrap();
assert_eq!(wallet.address, wallet_0x_tryfrom_string.address);
assert_eq!(wallet.chain_id, wallet_0x_tryfrom_string.chain_id);
assert_eq!(wallet.signer, wallet_0x_tryfrom_string.signer);

// Must fail because of `0z`
"0z0000000000000000000000000000000000000000000000000000000000000001"
.parse::<Wallet<SigningKey>>()
.unwrap_err();
}
}