I am a working on website where people should be able to deposit BTC to thier account balances and then do something with these balances. I figured out that I need deterministic wallet and generate different address for each user (based on user id) and perhaps for different deposit (based on total user deposit count - I've read that is best practicle to use 1 address for 1 transaction). I would like to be able to notify users when we see unconfirmed transaction and when it gets confirmed (add deposited amount to users balance).

Deposit flow:

1.1 on rawtx check if one of output addresses is in DB as some users deposit address

1.2 if it's some users address create new deposit in DB with 0 confirmations and mark is as pending

1.3 notify user that we can see his deposit but it's not confirmed yet and he will get BTC onto his balance once this transaction reaches 6 confirmations

1.4 on rawblock get all deposits with less than 6 confirmations and query blockchain.info to get confirmations count (see problem c).

1.5 update confirmationCount and if it's >= 6 assign coins to balance + notify user about balance change - from now on his deposit will be marked as confirmed

Now problems:

a) If server goes offline for any reason (app error/network issues/maintenance) potencially user can still deposit coins to previously copied address and we won't catch that transaction - so it will never go past 1.1. In ZMQ I can detect network issue by checking sequenceNumber (and query RPC for missing information?). I can't query all addresses on application startup to check if there were any deposits while application was down so meaby I should persist last block id (known to my app - updated after 1.4) in DB and on startup just check all newer blocks for already confirmed transactions (and perform 1.1, 1.5) and check mempool for all unconfirmed transactions and perform steps from 1.1 - 1.5.

b) My other idea of solving a) problem was to keep track of synced addresses/users in apps memory/redis. After user connects(registers/logins) check if such user was already synced in this application lifetime (this application start - node index.js, kill, node inde.js would be 2 lifetimes - I hope you know what I mean) if user is synced do nothing and if not scan all user addresses for all transactions and check if they are already added to DB. And mark user as synced. From now on 1.4, 1.5 should take care of the rest (?).

c) I would rather not use external service such as blockchain.info and just get information via RPC but whole confirmation checking flow seems complicated becuase of edge cases like double spends/block reorganization. Also I had hard time using bitcoin-core RPC (it meaby was because I first synced bitcoind and then added indexes and it's still syncing them).

d) Meaby there is some other more safe/easier/scalable way of doing such this?


These are indeed hard problems, but luckily already served by BTCPay Server, with extra features like lightning payments: https://github.com/btcpayserver/btcpayserver.

You can just run it via the included docker recipe (https://github.com/btcpayserver/btcpayserver-docker) and communicate with it via its API.

Or if you really want to reimplement the nitty gritty stuff yourself, look at its code or architecture documentation.

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.