diff --git a/Cargo.lock b/Cargo.lock index cc7c40ffc0f46..90264969f4a61 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3529,6 +3529,7 @@ dependencies = [ "base64 0.13.1", "bcs 0.1.4", "ed25519-dalek-bip32", + "hex", "move-core-types", "once_cell", "rand 0.7.3", diff --git a/sdk/Cargo.toml b/sdk/Cargo.toml index 82640e7cb9a13..ee2105cbebd55 100644 --- a/sdk/Cargo.toml +++ b/sdk/Cargo.toml @@ -23,6 +23,7 @@ aptos-types = { workspace = true } base64 = { workspace = true } bcs = { workspace = true } ed25519-dalek-bip32 = { workspace = true } +hex = { workspace = true } move-core-types = { workspace = true } rand_core = { workspace = true } serde_json = { workspace = true } diff --git a/sdk/src/types.rs b/sdk/src/types.rs index db89a99992093..9fe8e149a8737 100644 --- a/sdk/src/types.rs +++ b/sdk/src/types.rs @@ -142,6 +142,16 @@ impl LocalAccount { Ok(Self::new(address, key, sequence_number)) } + /// Create a new account from the given private key in hex literal. + pub fn from_private_key(private_key: &str, sequence_number: u64) -> Result { + let key = AccountKey::from_private_key(Ed25519PrivateKey::try_from( + hex::decode(private_key.trim_start_matches("0x"))?.as_ref(), + )?); + let address = key.authentication_key().account_address(); + + Ok(Self::new(address, key, sequence_number)) + } + /// Generate a new account locally. Note: This function does not actually /// create an account on the Aptos blockchain, it just generates a new /// account locally. @@ -575,4 +585,25 @@ mod tests { // Return an error for empty mnemonic phrase. assert!(LocalAccount::from_derive_path(derive_path, "", 0).is_err()); } + + #[test] + fn test_create_account_from_private_key() { + let key = AccountKey::generate(&mut rand::rngs::OsRng); + let (private_key_hex_literal, public_key_hex_literal) = ( + hex::encode(key.private_key().to_bytes().as_ref()), + key.authentication_key().account_address().to_hex_literal(), + ); + + // Test private key hex literal without `0x` prefix. + let account = LocalAccount::from_private_key(&private_key_hex_literal, 0).unwrap(); + assert_eq!(account.address().to_hex_literal(), public_key_hex_literal); + + // Test private key hex literal with `0x` prefix. + let account = + LocalAccount::from_private_key(&format!("0x{}", private_key_hex_literal), 0).unwrap(); + assert_eq!(account.address().to_hex_literal(), public_key_hex_literal); + + // Test invalid private key hex literal. + assert!(LocalAccount::from_private_key("invalid_private_key", 0).is_err()); + } }