0

I want to do a transaction, but I see that the receiver doesn't get the amount sent.

The regtest node started

bitcoind -rpcuser=test -rpcpassword=test -regtest -rpcport=16591 -fallbackfee=0.000045

My service class to interact with bitcoind API

const httpClient = require('axios');

const bitcoindConfig = {
  url: 'http://localhost:16591',
  headers: { 'content-type': 'text-plain' },
  auth: {
    username: 'test',
    password: 'test'
  },
};

class BitcoinService {
  _bitcoindRpcCall({ reqMethod = 'POST', walletName, method, params = [] } = {}) {
    const options = {
      url: walletName ? bitcoindConfig.url + `/wallet/${walletName}` : bitcoindConfig.url,
      method: reqMethod,
      data: JSON.stringify({'jsonrpc': '1.0', 'id': 'curltext', 'method': method, 'params': params}),
      headers: bitcoindConfig.headers,
      auth: bitcoindConfig.auth
    };
    return httpClient(options);
  }

  listWallets() {
    return this._bitcoindRpcCall({ method: 'listwallets' });
  }

  createWallet({ walletName }) {
    return this._bitcoindRpcCall({ method: 'createwallet', params: [walletName] });
  }

  getNewAddress({ walletName }) {
    return this._bitcoindRpcCall({ method: 'getnewaddress', walletName });
  }

  getBalance({ walletName }) {
    return this._bitcoindRpcCall({ method: 'getbalance', walletName });
  }

  listUnspent({ walletName }) {
    return this._bitcoindRpcCall({ method: 'listunspent', walletName });
  }

  dumpPrivKey({ address, walletName }) {
    return this._bitcoindRpcCall({ method: 'dumpprivkey', params: [address], walletName });
  }

  listTransactions({ walletName }) {
    return this._bitcoindRpcCall({ method: 'listtransactions', walletName });
  }

  generateToAddress({ address, nBlocks, walletName }) {
    return this._bitcoindRpcCall({ method: 'generatetoaddress', params: [nBlocks, address], walletName });
  }

  getTransaction({ txId, walletName }) {
    return this._bitcoindRpcCall({ method: 'gettransaction', params: [txId], walletName });
  }

  getRawTransaction({ txId, walletName }) {
    return this._bitcoindRpcCall({ method: 'getrawtransaction', params: [txId], walletName });
  }

  decodeRawTransaction({ hexString }) {
    return this._bitcoindRpcCall({ method: 'decoderawtransaction', params: [hexString] });
  }

  // https://bitcoincore.org/en/doc/0.17.0/rpc/wallet/sendtoaddress/
  async sendToAddress({ walletName, amount, toAddress, comment = '', commentTo = '', subtractFeeFromAmount = true } = {}) {
    return this._bitcoindRpcCall({
      method: 'sendtoaddress',
      params: [toAddress, amount, comment, commentTo, subtractFeeFromAmount],
      walletName
    });
  }

  // https://bitcoincore.org/en/doc/0.17.0/rpc/rawtransactions/createrawtransaction/
  async createRawTransaction({ walletName, amount, toAddress }) {
    const { data: { result: txs } } = await this.listUnspent({ walletName }); 
    
    const inputs = [];
    let n = amount;
    let i = 0;
    while (n > 0 && i < txs.length) {
      const tx = txs[i++];
      inputs.push({ txid: tx.txid, vout: tx.vout });
      n -= tx.amount;
    }
    
    const outputs = [
      { [toAddress]: amount }
    ];
    console.log('inputs, outputs', inputs, outputs);

    return this._bitcoindRpcCall({ method: 'createrawtransaction', params: [inputs, outputs] });
  }

  // https://chainquery.com/bitcoin-cli/signrawtransactionwithwallet
  signRawTransactionWithWallet({ hexString, walletName }) {
    return this._bitcoindRpcCall({ method: 'signrawtransactionwithwallet', params: [hexString], walletName });
  }

  // https://bitcoincore.org/en/doc/0.17.0/rpc/rawtransactions/sendrawtransaction/
  sendRawTransaction({ hexString, allowHighFees = true } = {}) {
    return this._bitcoindRpcCall({ method: 'sendrawtransaction', params: [hexString] });
  }

  async rawTransaction({ walletName, amount, toAddress }) {
    let res = await this.createRawTransaction({ walletName, amount, toAddress });
    res = await this.signRawTransactionWithWallet({ hexString: res.data.result, walletName });
    return this.sendRawTransaction({ hexString: res.data.result.hex });
  }
}

Two wallets created: alice and bob

const btc = new BitcoinService();

res = await btc.createWallet({ walletName: 'bob' });
console.log('create bob wallet', res.data);
// { result: { name: 'bob', warning: '' }, error: null, id: 'curltext' }
res = await btc.createWallet({ walletName: 'alice' });
console.log('create alice wallet', res.data);
// { result: { name: 'alice', warning: '' }, error: null, id: 'curltext' }

Check whether the wallets exist

res = await btc.listWallets();
console.log('listwallets', res.data);
// { result: [ 'bob', 'alice' ], error: null, id: 'curltext' }

Create addresses for the wallets

let aliceAddr;
let bobAddr;

res = await btc.getNewAddress({ walletName: 'alice' });
aliceAddr = res.data.result;
console.log('alice addr', aliceAddr);
// bcrt1qn4w4futa4j0mrt6frqn9u9zg9n5s9dvaeh2mrl

res = await btc.getNewAddress({ walletName: 'bob' });
bobAddr = res.data.result;
console.log('bob addr', bobAddr);
// bcrt1qecashk27r403nkeq09gvpfnr7dgfeet9xk97m5

Generate bitcoin for alice

for (let i = 0; i < 5; i++) {
  res = await btc.generateToAddress({ address: aliceAddr, nBlocks: 101 });
  console.log('generate bitcon for alice', res.data);
  // hashes in the output
}

Check balance

// Get balance
res = await btc.getBalance({ walletName: 'alice' });
console.log('alice balance', res.data);
// { result: 126.85546875, error: null, id: 'curltext' }

res = await btc.getBalance({ walletName: 'bob' });
console.log('bob balance', res.data);
// { result: 0, error: null, id: 'curltext' }

Send bitcoin from alice to bob

res = await btc.sendToAddress({ walletName: 'alice', toAddress: bobAddr, amount: 0.1 });
console.log('alice sends to bob', res.data);
// {
//   result: '0ae84b140e3be5d4933daa4f25e3d1cd5c02b9485ede54ad4c24a91e7d0d28f2',
//   error: null,
//   id: 'curltext'
// }

Checking the balance again

res = await btc.getBalance({ walletName: 'alice' });
console.log('alice balance', res.data);
// { result: 126.75546875, error: null, id: 'curltext' }

res = await btc.getBalance({ walletName: 'bob' });
console.log('bob balance', res.data);
// { result: 0, error: null, id: 'curltext' }

The alice balance was decreased by 0.1 as expected. Why is there no amount on the bob balance?

Also, I tried the sendrawtransaction, same result, bob got no bitcoin on the balance.

res = await btc.rawTransaction({ walletName: 'alice', toAddress: bobAddr, amount: 0.1 })
console.log('alice sends raw transaction', res.data);
// {
//   result: 'e1fc8cc8bbe38bdd793ff1f87ca59a52d90c9fa1523d93d166f6a53209bc5e56',
//   error: null,
//   id: 'curltext'
// }

But I can list the transaction that bob received

res = await btc.listTransactions({ walletName: 'bob' });
console.log('bob transactions', res.data);
bob transactions {
  result: [
    {
      address: 'bcrt1qyrjp4kcar7c60842zmd38wnwjxlgjhj6550nev',
      category: 'receive',
      amount: 0.1,
      label: '',
      vout: 0,
      confirmations: 0,
      trusted: false,
      txid: 'e1fc8cc8bbe38bdd793ff1f87ca59a52d90c9fa1523d93d166f6a53209bc5e56',
      walletconflicts: [],
      time: 1637406810,
      timereceived: 1637406810,
      'bip125-replaceable': 'no'
    },
    {
      address: 'bcrt1qyrjp4kcar7c60842zmd38wnwjxlgjhj6550nev',
      category: 'receive',
      amount: 0.1,
      label: '',
      vout: 0,
      confirmations: 0,
      trusted: false,
      txid: 'd4de85ff41b0386808b60a8ec0028923c42a2bc1667e5b8a7b865cacf21abd5d',
      walletconflicts: [],
      time: 1637407520,
      timereceived: 1637407520,
      'bip125-replaceable': 'no'
    },
    {
      address: 'bcrt1qyrjp4kcar7c60842zmd38wnwjxlgjhj6550nev',
      category: 'receive',
      amount: 0.1,
      label: '',
      vout: 0,
      confirmations: 0,
      trusted: false,
      txid: '573d8ef6b72fa3e029f3207ddc8b5f03a248e88b4ae643bc66be38ae84ffa01f',
      walletconflicts: [],
      time: 1637407554,
      timereceived: 1637407554,
      'bip125-replaceable': 'no'
    },
    {
      address: 'bcrt1qyrjp4kcar7c60842zmd38wnwjxlgjhj6550nev',
      category: 'receive',
      amount: 0.1,
      label: '',
      vout: 0,
      confirmations: 0,
      trusted: false,
      txid: '4fa4efff12348f0916cec1b39e47cf19ceb1aa91b7236f7c67905b2eef34433a',
      walletconflicts: [],
      time: 1637407824,
      timereceived: 1637407824,
      'bip125-replaceable': 'no'
    }
  ],
  error: null,
  id: 'curltext'
}

4
  • 1
    I assume Bob's balance just won't be counted until it is confirmed. Nov 20 at 15:06
  • @PieterWuille true, now I got it. The transactions are included in a block and it must be mined. For example bitcoin-cli -rpcport=16591 -rpcpassword=test -rpcuser=test --rpcwallet=alice -generate 1 Now I see the bob balance updated. But I can't find a way to do it via the RPC API. Is it possible? But maybe better to run the command above by the cron every 5 sec.
    – srgbnd
    Nov 20 at 15:11
  • 1
    I don't know anything about the interface you're using here, but Bitcoin Core can give you unconfirmed balances using the getbalances RPC (note: not getbalance). Nov 20 at 15:27
  • @PieterWuille thank you. It is helpful!
    – srgbnd
    Nov 20 at 16:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.