dogecoin / dogecoin

very currency
MIT License
14.4k stars 2.8k forks source link

Prefix xpub to dgub #3477

Closed PlazaFer closed 2 months ago

PlazaFer commented 2 months ago

Hello, how are you? I have an issue that I can't solve. Through bitcoinjs-lib, I'm obtaining and generating dodge addresses, as well as public and private keys. The problem is that I get the public key as xpub, and the backend requires it with the dgub prefix instead of xpub. Alternatively, I might need to convert it from xpub to dgub. Could you assist me with this? Thanks! Here, I'm sharing the code that obtains addresses and keys for Dodge and other currencies. Additionally, I'm providing the derivation path I'm using for Dodge.

Derivations path for Dodgecoin

derivationPath: "m/44'/3'/0'/0/0",
  rootDerivation: "m/44'/3'/0'",

File

import { Network as BTCNetwork, payments } from 'bitcoinjs-lib';
import { HDNode } from 'ethers/lib/utils';
import b58 from 'bs58check';
import { btcNetworks, btcNetworksTestnet } from '../constants/predefinedNetworks';
import { WalletNetworkData } from '../stores/wallets';
import { BTCAddressType } from '../types/networks';
import bchaddr from 'bchaddrjs';

const convertXpubToZpub = (xpub: string) => {
  let data = b58.decode(xpub);
  data = data.slice(4);
  data = Buffer.concat([Buffer.from('04b24746', 'hex'), data]);
  return b58.encode(data);
};

export const convertZpubXoZpub = (xpub: string) => {
  let data = b58.decode(xpub);
  data = data.slice(4);
  data = Buffer.concat([Buffer.from('0488b21e', 'hex'), data]);
  return b58.encode(data);
};

export const getBtcAddressFromPublicKey = (params: {
  publicKey: string;
  addressType: BTCAddressType;
  networkData: BTCNetwork;
}) => {
  const { publicKey, networkData, addressType } = params;

  const { address } = payments[addressType]({ pubkey: Buffer.from(publicKey, 'hex'), network: networkData });

  // Special case BCH ADDRESS PARSE TO CashAddr Format
  if (networkData.messagePrefix === '\x18Bitcoin Cash Signed Message:\n') {
    return bchaddr.toCashAddress(address) || address;
  }

  return address;
};

export const getAllBtcNetworksAddresses = (params: { node: HDNode }) => {
  const { node } = params;

  const addresses: { [key in string]: string } = {};
  const networks: { [key in string]: WalletNetworkData } = {};

  [...btcNetworks, ...btcNetworksTestnet].forEach((network) => {
    const derivatedNode = node.derivePath(network.derivationPath)
    const accountKeys = node
      .derivePath((network as any).rootDerivation || network.derivationPath.replace(`/0/0`, ''))
      .neuter();

    const convertNodeToAddress = (nodeEthers: HDNode) => {
      const publicKey = nodeEthers.publicKey.replace('0x', '');

      return {
        path: nodeEthers.path,
        publicKey,
        address: getBtcAddressFromPublicKey({
          publicKey,
          addressType: network.addressType,
          networkData: network.networkData,
        }) as string,
      };
    };

    const publicKey = derivatedNode.publicKey.replace('0x', '');
    const { address } = convertNodeToAddress(derivatedNode);

    if (!address) throw new Error('Error while generating address');

    networks[network.walletId] = {
      address,
      publicKey,
      privateKey: derivatedNode.privateKey.replace('0x', ''),
      extendedPublicKey: network.derivationPath.startsWith(`m/44`)
        ? accountKeys.extendedKey
        : convertXpubToZpub(accountKeys.extendedKey),
      extendedPrivateKey: derivatedNode.extendedKey,
      utxos: {
        internal: Object.fromEntries(
          Array.from({ length: 1 })
            .map((_, index) => accountKeys.derivePath(`1/${index}`))
            .map(convertNodeToAddress)
            .entries()
        ),
        external: Object.fromEntries(
          Array.from({ length: 1 })
            .map((_, index) => accountKeys.derivePath(`0/${index}`))
            .map(convertNodeToAddress)
            .entries()
        ),
      },
    };
  });

  return { addresses, networks };
};
patricklodder commented 2 months ago

I'm moving this to discussions because this is not an issue with Dogecoin Core