diff --git a/CHANGELOG.md b/CHANGELOG.md index 3208a490..c82c1e7b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -278,6 +278,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 diff --git a/ethers-signers/src/wallet/private_key.rs b/ethers-signers/src/wallet/private_key.rs index ed10949c..f4b83ef0 100644 --- a/ethers-signers/src/wallet/private_key.rs +++ b/ethers-signers/src/wallet/private_key.rs @@ -130,12 +130,29 @@ impl FromStr for Wallet { type Err = WalletError; fn from_str(src: &str) -> Result { + 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 { + type Error = WalletError; + + fn try_from(value: &str) -> Result { + value.parse() + } +} + +impl TryFrom for Wallet { + type Error = WalletError; + + fn try_from(value: String) -> Result { + value.parse() + } +} + #[cfg(test)] #[cfg(not(target_arch = "wasm32"))] mod tests { @@ -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 = + "0000000000000000000000000000000000000000000000000000000000000001".parse().unwrap(); + + // Check FromStr and `0x` + let wallet_0x: Wallet = + "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 = + "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 = + "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 + let wallet_0x_tryfrom_string: Wallet = + "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::>() + .unwrap_err(); + } }