bitcoinjs / bitcoinjs-lib

A javascript Bitcoin library for node.js and browsers.
MIT License
5.6k stars 2.08k forks source link

Invalid network version from bitcoin.ECPair.fromWIF(senderPrivateKey, network) - bitcoinjs-lib ^5.2.0 #2120

Closed inspi-writer001 closed 5 days ago

inspi-writer001 commented 5 days ago

import axios from "axios";
import bitcoin from "bitcoinjs-lib"; // "bitcoinjs-lib": "^5.2.0",
import { initWasm, TW, KeyStore } from "@trustwallet/wallet-core";  // "@trustwallet/wallet-core": "3.0.8",

export const bitcoinMnemonicToPrivateKey = async (mnemonic) => {
  const start = new Date().getTime();
  console.log(`Initializing Wasm...`);
  const core = await initWasm();
  const { CoinType, HexCoding, HDWallet, AnyAddress, AnySigner, PrivateKey } =
    core;

  const storage = new KeyStore.FileSystemStorage("/tmp");
  const keystore = new KeyStore.Default(core, storage);

  const storedWallet = await keystore.import(mnemonic, "", "", [
    CoinType.bitcoin
  ]);

  const derivPath = "m/84'/0'/0'/0/0";
  const wallet = HDWallet.createWithMnemonic(mnemonic, "");

  const privateKey = wallet.getKey(CoinType.bitcoin, derivPath).data();
  const publickKey = wallet
    .getKey(CoinType.bitcoin, derivPath)
    .getPublicKeySecp256k1(true)
    .data();
  const walletAddress = storedWallet.activeAccounts[0].address;

  return { privateKey, publickKey, walletAddress };
};

const log = console.log;

log("==== btc ====\n", bitcoin.networks.bitcoin);
const BitcoinNet = {
  messagePrefix: "\x18Bitcoin Signed Message:\n",
  bech32: "bc",
  bip32: {
    public: 0x0488b21e,
    private: 0x0488ade4
  },
  pubKeyHash: 0x00,
  scriptHash: 0x05,
  wif: 0x80
};

bitcoin.networks.bitcoin = BitcoinNet;

const network = bitcoin.networks.bitcoin; // Use 'bitcoin.networks.bitcoin' for mainnet
log(" === from new btc ===");
log(network);

export const ttransferBitcoin = async (
  senderPrivateKey,
  senderAddress,
  receiverAddress,
  amountToTransfer
) => {
  const keyPair = bitcoin.ECPair.fromWIF(senderPrivateKey, network);
  const tx = new bitcoin.TransactionBuilder(network);

  // Fetch the sender's unspent transactions (UTXOs)
  const response = await axios.get(
    `https://api.blockcypher.com/v1/btc/main/addrs/${senderAddress}?unspentOnly=true`
  );
  const utxos = response.data.txrefs;
  log(" ============================= this is utxos Object");
  log(response.data);
  const lastTransaction = utxos[utxos.length - 1];

  const psbt = new bitcoin.Psbt({ network });

  // Use P2WPKH for both inputs and outputs
  const p2wpkhSender = bitcoin.payments.p2wpkh({
    pubkey: keyPair.publicKey,
    network
  });

  const p2wpkhReceiver = bitcoin.payments.p2wpkh({
    address: receiverAddress, // Ensure receiverAddress is a P2WPKH address
    network
  });

  const newww = psbt
    .addInput({
      hash: lastTransaction.tx_hash,
      index: lastTransaction.tx_output_n, // Use the correct output index
      witnessUtxo: {
        script: p2wpkhSender.output,
        value: lastTransaction.value // Use the value from the UTXO
      }
    })
    .addOutput({
      address: p2wpkhReceiver.address, // Use the P2WPKH address
      value: Number(amountToTransfer)
    })
    .addOutput({
      address: senderAddress, // Use the P2WPKH address
      value: Number(lastTransaction.value) - Number(amountToTransfer) - 10000
    })
    .signInput(0, keyPair)
    .finalizeInput(0)
    .extractTransaction();

  const transaction = await axios.post(
    `https://api.blockcypher.com/v1/btc/main/txs/push`,
    {
      tx: newww.toHex()
    }
  );

  return { transactionHash: transaction.data.tx.hash };
};

export const transferBitcoin = async (
  toAddress,
  encryptedMnemonics,
  amount
) => {
  const mnemonic = decrypt(encryptedMnemonics);
  const accountObject = await bitcoinMnemonicToPrivateKey(mnemonic);

  const pp = bitcoin.ECPair.fromPrivateKey(
    Buffer.from(accountObject.privateKey)
  );

  const response = await ttransferBitcoin(
    pp.toWIF(),
    accountObject.walletAddress,
    toAddress,
    toCustomLamport(amount, 8).toString()
  );

  return response;
};

Here's the codebase to recreate , but when I used this exact code for Litecoin just changing the Litecoin network to this

const LitecoinNet = {
  messagePrefix: "\x18Litecoin Signed Message:\n",
  bech32: "ltc",
  bip32: { public: 76067358, private: 76066276 },
  pubKeyHash: 48,
  scriptHash: 50,
  wif: 176
};

and the mnemonic converter to this


export const litecoinMnemonicToPrivateKey = async (mnemonic) => {
  const start = new Date().getTime();
  console.log(`Initializing Wasm...`);
  const core = await initWasm();
  const { CoinType, HexCoding, HDWallet, AnyAddress, AnySigner, PrivateKey } =
    core;

  const storage = new KeyStore.FileSystemStorage("/tmp");
  const keystore = new KeyStore.Default(core, storage);

  const storedWallet = await keystore.import(mnemonic, "", "", [
    CoinType.litecoin
  ]);

  const derivPath = "m/84'/2'/0'/0/0";
  const wallet = HDWallet.createWithMnemonic(mnemonic, "");

  const privateKey = wallet.getKey(CoinType.litecoin, derivPath).data();
  const publickKey = wallet
    .getKey(CoinType.litecoin, derivPath)
    .getPublicKeySecp256k1(true)
    .data();
  const walletAddress = storedWallet.activeAccounts[0].address;

  return { privateKey, publickKey, walletAddress };
};

it went through successfully for litecoin, of course I changed the blockcypher from btc to ltc also... I also tried using the networks.bitcoin from the package for bitcoin before hardcoding.. still didnt work, but i had initially tested this codebase for btc months ago and it worked, then i tweaked it for ltc and both were working months ago

junderw commented 5 days ago

Make sure you pass the same network into fromPrivateKey otherwise the toWIF() will give you a WIF for a different network potentially.