diff --git a/Cargo.lock b/Cargo.lock
index 381c653e0e..431423e6b7 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -7586,6 +7586,8 @@ checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1"
 name = "wasm-crypto"
 version = "0.1.2"
 dependencies = [
+ "bip39",
+ "common",
  "crypto",
  "getrandom 0.2.10",
  "rstest",
diff --git a/wasm-crypto/Cargo.toml b/wasm-crypto/Cargo.toml
index 5373c537f4..54a0f3ccc1 100644
--- a/wasm-crypto/Cargo.toml
+++ b/wasm-crypto/Cargo.toml
@@ -13,6 +13,9 @@ crate-type = ["cdylib"]
 [dependencies]
 crypto = { path = '../crypto' }
 serialization = { path = "../serialization" }
+common = { path = "../common" }
+
+bip39 = { workspace = true, default-features = false, features = ["std", "zeroize"] }
 
 # This crate is required for rand to work with wasm. See: https://docs.rs/getrandom/latest/getrandom/#webassembly-support
 getrandom = { version = "0.2", features = ["js"] }
diff --git a/wasm-crypto/js-bindings/crypto_test.js b/wasm-crypto/js-bindings/crypto_test.js
index 6e9d489793..a094d7a3da 100644
--- a/wasm-crypto/js-bindings/crypto_test.js
+++ b/wasm-crypto/js-bindings/crypto_test.js
@@ -10,6 +10,10 @@ import {
   public_key_from_private_key,
   sign_message,
   verify_signature,
+  make_default_account_pubkey,
+  make_receiving_address,
+  pubkey_to_string,
+  Network,
 } from "../pkg/wasm_crypto.js";
 
 export async function run_test() {
@@ -44,4 +48,66 @@ export async function run_test() {
     }
     console.log("Tested decoding bad private key successfully");
   }
+
+  try {
+    const invalid_mnemonic = "asd asd";
+    make_default_account_pubkey(invalid_mnemonic, Network.Mainnet);
+    throw new Error("Invalid mnemonic worked somehow!");
+  } catch (e) {
+    if (!e.includes("Invalid mnemonic string")) {
+      throw e;
+    }
+    console.log("Tested invalid menemonic successfully");
+  }
+
+  try {
+    make_receiving_address(bad_priv_key, 0);
+    throw new Error("Invalid public key worked somehow!");
+  } catch (e) {
+    if (!e.includes("Invalid public key encoding")) {
+      throw e;
+    }
+    console.log("Tested decoding bad account public key successfully");
+  }
+
+  const mnemonic = "walk exile faculty near leg neutral license matrix maple invite cupboard hat opinion excess coffee leopard latin regret document core limb crew dizzy movie";
+  {
+    const account_pubkey = make_default_account_pubkey(mnemonic, Network.Mainnet);
+    console.log(`acc pubkey = ${account_pubkey}`);
+
+    const receiving_pubkey = make_receiving_address(account_pubkey, 0);
+    console.log(`receiving pubkey = ${receiving_pubkey}`);
+
+    // test bad key index
+    try {
+      make_receiving_address(account_pubkey, 1<<31);
+      throw new Error("Invalid key index worked somehow!");
+    } catch (e) {
+      if (!e.includes("Invalid key index, MSB bit set")) {
+        throw e;
+      }
+      console.log("Tested invalid key index with set MSB bit successfully");
+    }
+
+    const address = pubkey_to_string(receiving_pubkey, Network.Mainnet);
+    console.log(`address = ${address}`);
+    if (address != "mtc1qyqmdpxk2w42w37qsdj0e8g54ysvnlvpny3svzqx") {
+      throw new Error("Incorrect address generated");
+    }
+  }
+
+
+  {
+    // Test generating an address for Testnet
+    const account_pubkey = make_default_account_pubkey(mnemonic, Network.Testnet);
+    console.log(`acc pubkey = ${account_pubkey}`);
+
+    const receiving_pubkey = make_receiving_address(account_pubkey, 0);
+    console.log(`receiving pubkey = ${receiving_pubkey}`);
+    const address = pubkey_to_string(receiving_pubkey, Network.Testnet);
+    console.log(`address = ${address}`);
+    if (address != "tmt1q9dn5m4svn8sds3fcy09kpxrefnu75xekgr5wa3n") {
+      throw new Error("Incorrect address generated");
+    }
+  }
 }
diff --git a/wasm-crypto/src/error.rs b/wasm-crypto/src/error.rs
index 378fa2743b..6f1ff34fcd 100644
--- a/wasm-crypto/src/error.rs
+++ b/wasm-crypto/src/error.rs
@@ -25,6 +25,10 @@ pub enum Error {
     InvalidPublicKeyEncoding,
     #[error("Invalid signature encoding")]
     InvalidSignatureEncoding,
+    #[error("Invalid mnemonic string")]
+    InvalidMnemonic,
+    #[error("Invalid key index, MSB bit set")]
+    InvalidKeyIndex,
 }
 
 // This is required to make an error readable in JavaScript
diff --git a/wasm-crypto/src/lib.rs b/wasm-crypto/src/lib.rs
index 13153189d8..5eadabc31d 100644
--- a/wasm-crypto/src/lib.rs
+++ b/wasm-crypto/src/lib.rs
@@ -13,19 +13,112 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-use crypto::key::{KeyKind, PrivateKey, PublicKey, Signature};
+pub use bip39::{Language, Mnemonic};
+use common::{
+    address::{pubkeyhash::PublicKeyHash, Address},
+    chain::{
+        config::{Builder, ChainType, BIP44_PATH},
+        Destination,
+    },
+};
+use crypto::key::{
+    extended::{ExtendedKeyKind, ExtendedPrivateKey, ExtendedPublicKey},
+    hdkd::{child_number::ChildNumber, derivable::Derivable, u31::U31},
+    KeyKind, PrivateKey, PublicKey, Signature,
+};
 use error::Error;
 use serialization::{DecodeAll, Encode};
 use wasm_bindgen::prelude::*;
 
 pub mod error;
 
+#[wasm_bindgen]
+pub enum Network {
+    Mainnet,
+    Testnet,
+    Regtest,
+    Signet,
+}
+
+impl From<Network> for ChainType {
+    fn from(value: Network) -> Self {
+        match value {
+            Network::Mainnet => ChainType::Mainnet,
+            Network::Testnet => ChainType::Testnet,
+            Network::Regtest => ChainType::Regtest,
+            Network::Signet => ChainType::Signet,
+        }
+    }
+}
+
 #[wasm_bindgen]
 pub fn make_private_key() -> Vec<u8> {
     let key = PrivateKey::new_from_entropy(KeyKind::Secp256k1Schnorr);
     key.0.encode()
 }
 
+#[wasm_bindgen]
+pub fn make_default_account_pubkey(mnemonic: &str, network: Network) -> Result<Vec<u8>, Error> {
+    let mnemonic = bip39::Mnemonic::parse_in(Language::English, mnemonic)
+        .map_err(|_| Error::InvalidMnemonic)?;
+    let seed = mnemonic.to_seed("");
+
+    let root_key = ExtendedPrivateKey::new_master(&seed, ExtendedKeyKind::Secp256k1Schnorr)
+        .expect("Should not fail to create a master key");
+
+    let chain_config = Builder::new(network.into()).build();
+
+    let account_index = U31::ZERO;
+    let path = vec![
+        BIP44_PATH,
+        chain_config.bip44_coin_type(),
+        ChildNumber::from_hardened(account_index),
+    ];
+    let account_path = path.try_into().expect("Path creation should not fail");
+    let account_privkey = root_key
+        .derive_absolute_path(&account_path)
+        .expect("Should not fail to derive path");
+
+    Ok(account_privkey.to_public_key().encode())
+}
+
+#[wasm_bindgen]
+pub fn make_receiving_address(public_key_bytes: &[u8], key_index: u32) -> Result<Vec<u8>, Error> {
+    const RECEIVE_FUNDS_INDEX: ChildNumber = ChildNumber::from_normal(U31::from_u32_with_msb(0).0);
+
+    let account_pubkey = ExtendedPublicKey::decode_all(&mut &public_key_bytes[..])
+        .map_err(|_| Error::InvalidPublicKeyEncoding)?;
+
+    let receive_funds_pkey = account_pubkey
+        .derive_child(RECEIVE_FUNDS_INDEX)
+        .expect("Should not fail to derive key");
+
+    let public_key: PublicKey = receive_funds_pkey
+        .derive_child(ChildNumber::from_normal(
+            U31::from_u32(key_index).ok_or(Error::InvalidKeyIndex)?,
+        ))
+        .expect("Should not fail to derive key")
+        .into_public_key();
+
+    Ok(public_key.encode())
+}
+
+#[wasm_bindgen]
+pub fn pubkey_to_string(public_key_bytes: &[u8], network: Network) -> Result<String, Error> {
+    let public_key = PublicKey::decode_all(&mut &public_key_bytes[..])
+        .map_err(|_| Error::InvalidPublicKeyEncoding)?;
+    let chain_config = Builder::new(network.into()).build();
+
+    let public_key_hash = PublicKeyHash::from(&public_key);
+
+    Ok(
+        Address::new(&chain_config, &Destination::Address(public_key_hash))
+            .expect("Should not fail to create address")
+            .get()
+            .to_owned(),
+    )
+}
+
 #[wasm_bindgen]
 pub fn public_key_from_private_key(private_key: &[u8]) -> Result<Vec<u8>, Error> {
     let private_key = PrivateKey::decode_all(&mut &private_key[..])