Skip to content

Commit

Permalink
Implement recovering account from derive path. (aptos-labs#4374)
Browse files Browse the repository at this point in the history
  • Loading branch information
stevenatcrypto authored and areshand committed Dec 17, 2022
1 parent 3122557 commit 6e178d2
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 0 deletions.
50 changes: 50 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,7 @@ digest = "0.9.0"
dir-diff = "0.3.2"
dirs = "4.0.0"
ed25519-dalek = { version = "1.0.1", features = ["std", "serde"] }
ed25519-dalek-bip32 = "0.2.0"
either = "1.6.1"
enum_dispatch = "0.3.8"
env_logger = "0.9.0"
Expand Down Expand Up @@ -428,6 +429,7 @@ tempfile = "3.3.0"
termcolor = "1.1.2"
textwrap = "0.15.0"
thiserror = "1.0.31"
tiny-bip39 = "0.8.2"
tiny-keccak = { version = "2.0.2", features = ["keccak", "sha3"] }
tracing = "0.1.34"
tracing-subscriber = "0.3.11"
Expand Down
2 changes: 2 additions & 0 deletions sdk/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,11 @@ aptos-rest-client = { workspace = true }
aptos-types = { workspace = true }
bcs = { workspace = true }
cached-packages = { workspace = true }
ed25519-dalek-bip32 = { workspace = true }
move-core-types = { workspace = true }
rand_core = { workspace = true }
serde = { workspace = true }
tiny-bip39 = { workspace = true }

[dev-dependencies]
once_cell = { workspace = true }
Expand Down
52 changes: 52 additions & 0 deletions sdk/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,12 @@ use crate::{
},
};

use anyhow::Result;
use aptos_types::event::EventKey;
pub use aptos_types::*;
use bip39::{Language, Mnemonic, Seed};
use ed25519_dalek_bip32::{DerivationPath, ExtendedSecretKey};
use std::str::FromStr;

/// LocalAccount represents an account on the Aptos blockchain. Internally it
/// holds the private / public key pair and the address of the account. You can
Expand Down Expand Up @@ -42,6 +46,29 @@ impl LocalAccount {
}
}

/// Recover an account from derive path (e.g. m/44'/637'/0'/0'/0') and mnemonic phrase,
pub fn from_derive_path(
derive_path: &str,
mnemonic_phrase: &str,
sequence_number: u64,
) -> Result<Self> {
let derive_path = DerivationPath::from_str(derive_path)?;
let mnemonic = Mnemonic::from_phrase(mnemonic_phrase, Language::English)?;
// TODO: Make `password` as an optional argument.
let seed = Seed::new(&mnemonic, "");
let key = ExtendedSecretKey::from_seed(seed.as_bytes())?
.derive(&derive_path)?
.secret_key;
let key = AccountKey::from(Ed25519PrivateKey::try_from(key.as_bytes().as_ref())?);
let address = key.authentication_key().derived_address();

Ok(Self {
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.
Expand Down Expand Up @@ -183,3 +210,28 @@ impl From<Ed25519PrivateKey> for AccountKey {
Self::from_private_key(private_key)
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_recover_account_from_derive_path() {
// Same constants in test cases of TypeScript
// https://github.com/aptos-labs/aptos-core/blob/main/ecosystem/typescript/sdk/src/aptos_account.test.ts
let derive_path = "m/44'/637'/0'/0'/0'";
let mnemonic_phrase =
"shoot island position soft burden budget tooth cruel issue economy destroy above";
let expected_address = "0x7968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30";

// Validate if the expected address.
let account = LocalAccount::from_derive_path(derive_path, mnemonic_phrase, 0).unwrap();
assert_eq!(account.address().to_hex_literal(), expected_address);

// Return an error for empty derive path.
assert!(LocalAccount::from_derive_path("", mnemonic_phrase, 0).is_err());

// Return an error for empty mnemonic phrase.
assert!(LocalAccount::from_derive_path(derive_path, "", 0).is_err());
}
}

0 comments on commit 6e178d2

Please sign in to comment.