Project combat: Bitcoin charge and withdrawal integration
Recently, I have done a bitcoin charging and testing function. As a technology enthusiast, I have no previous experience in this area. It is difficult to find suitable information on the Internet, so I explored a demo and wrote this article. The idea may not be mature enough. In the real production environment, more considerations and designs are needed. For example, regarding the consideration of handling fees, I hope that the big cattle with relevant experience will give pointers and correct errors.
Goal: Suppose a website provides member charging and withdrawal functions. Users can use the traditional online banking checkout or WeChat Alipay to fill in the money, convert to platform coins or platform points or simply correspond to the legal currency balance, and then enjoy better discounts and rewards. The platform also allows users to withdraw funds. The goal now is to add a bitcoin withdrawal channel, the specific functions are as follows:
1.1 Functional requirements
1) Allow users to recharge via Bitcoin, users transfer to Bitcoin, and the platform automatically converts to the legal currency balance or points supported by the platform.
2) Allow the user to withdraw the balance of the platform, convert the platform into the corresponding number of BTCs and transfer it to the user's bitcoin wallet.
1.2 Design considerations
1) How does the system not expose the private key when generating the bitcoin address for the user?
Using BIP32 Hierarchical deterministic key to create a hierarchical deterministic key, we can generate the bitcoin address of the child node through the extended public key of the parent node, so as a website to directly interact with the external network, you can basically do not worry about security issues, the parent node The extended public key cannot generate the private key of the child node, so the private key will not be exposed, but as far as possible, the extended public key here should not be exposed as a normal public key, or it should be properly saved for the following reasons:
Note: BIP32 has a normal key and a hardened key. Only when the parent node is a normal key can the public key be extended (in fact, a chain code is added) to generate the child node. Key and address, in addition to the special care, for the ordinary key node, once the hacker masters the private key of the child node and the extended public key of the parent node, the parent node's private key can be deduced, and the parent node will be pushed out. All child nodes.
[Refer to https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki ]
2) Each user will be assigned a bitcoin address. How to manage such a large number of bitcoin addresses effectively?
With the BIP44 protocol, all bitcoin addresses can be managed in a standardized manner. For example, according to BIP44, we can generate two primary accounts:
External account (assigned to the user): m/44'/0'/0'/0/address_index
Internal account (assigned to internal): m/44'/0'/1'/0/address_index
Through the parent node's extended key and index number, we can generate the bitcoin address for the user and the internal, and further bind the user ID and bitcoin address information (bitcoin address, number, creation date) in the database, we can achieve more The complex logic, such as recycling the bitcoin address that was not used for three months by cross-checking the recharge record.
3) How do I manage the replenishment of scattered bitcoins among the thousands of addresses assigned to users?
It can be transferred to the internal account in time. For example, when we detect that the user has successfully recharged, we can join the action of this step.
4) How to withdraw cash from users, such as whether to transfer from a central wallet?
I really didn't think of a better and more reasonable solution, so in my design, I really want to use a central wallet to make a rollout. Refer to the internal account m/44'/0'/1'/0/address_index mentioned in 2). For simplification, you can directly use a fixed account m/44'/0'/1'/0/0 as a "settlement reserve account". We need to monitor the status of this account in real time to avoid the situation that cannot be withdrawn. .
Note: Simple monitoring can be done with grafana btc exporter https://grafana.com/dashboards/6973
5) How do you design a hot and cold wallet in our design of this requirement?
The consideration of security is not a simple layer, but a multi-layer design. The corresponding security strategy is designed according to different risk levels. The general considerations are as follows:
i) The external account assigned to the user is basically relatively low . For individual users, the amount of recharge is relatively low, and according to 3) the bitcoin recharged to the external account will be transferred in time, so the external account should be a hot wallet.
Ii) The internal account has a higher security level . Because the internal account manages more bitcoin, you should increase the security level. Can you make a 100% cold wallet? Should not, because we still need to withdraw funds from the internal account to the user, the withdrawal first need to know the user withdrawal record, even if you do not directly connect to the database to access the internal system to obtain, and even if the offline signature transfer you need to know UTXO If it is a cold wallet with a physical network disconnection, it is impossible to know if it is not connected to other systems. We can only improve its security through internal network security protection, such as firewall port control security communication, etc. We can make him a semi-cold semi-cold wallet
Iii) As long as the wallet without physical isolation is not called cold wallet as mentioned in the above two points, in order to further improve the security of funds, we can store some bitcoin in the cold wallet, for example 60% in the cold Wallet, 40% placed on ii) semi-cold wallet.
Note: As for how the cold wallet interacts with the system, it is ignored in my demo. I see the information on the Internet, probably knowing two ways.
a. First, a more exotic design is to scan the QR code through several computer cameras. For example, the hot wallet generates the rawtransaction QR code, the cold wallet camera scans the QR code signature, generates the signedtransaction QR code, and the hot wallet scans again. Broadcast
b. Through BIP32 we know that we transfer an address, the private key of this address can not be calculated, in other words, it can not be seen in this world, so well, we do not need a machine storage Now, we can directly take an account that has not appeared in the private key as a cold wallet. Whenever the cold wallet is transferred, it will be spent, and the change will be put into another new cold wallet.
I am curious how the real exchange defines hot and cold wallets and interacts.
1) Recharge process
i) The user selects Bitcoin to recharge and enters 15000 RMB. The website automatically displays 0.5 BTC according to the current exchange rate. The user confirms and submits.
Ii) The website generates a Bitcoin recharge address (M/44'/0'/0'/0/address_index) and generates an order [insert into topup_order < uuid, userid, btcaddress, btcindex, requestamt, exchangerate, createdate, status >] ,
At the same time, the website also generates a QR code for receipt, format: bitcoin:<address>?amount=<value>&message=<message>
Iii) The user manually enters or scans the QR code from the exchange or his wallet for transfer
Iv) The scheduled task program will obtain the recharge request from the database, request the bitcoin node to detect the transaction related to the request address through the RPC, and once the updated user platform balance is detected and the bitcoin transaction information txid/vout/scriptPub[update topup_order<uuid, Userid, btcaddress, btcindex, requestamt, exchangerate, createdate, status, realamt, txid, vout, scriptpub >].
v) The scheduled task program creates rawtransaction based on realamt, txid, vout, scriptpub, and transfers bitcoin to internal account
2) Withdrawal process
i) The user chooses to convert the platform balance into Bitcoin cash withdrawal, enter 15000 RMB and provide personal Bitcoin address. The website program automatically displays 0.5 BTC according to the current exchange rate, and the user confirms and submits the withdrawal request.
Ii) The website verifies the user balance and Bitcoin address validity and creates a withdrawal record [insert into withdraw_order < uuid, userid, btcaddress, btcindex, balance, btcamt, exchangerate, createdate, status >]
Iii) The scheduled task program obtains the withdrawal request from the database, and transfers the bitcoin to the user bitcoin address in batches from the internal account.
1) Bitcoin core v0.17.1
2) Bx tool (libbitcoin)
Note: Note that the configuration of testnet or regtest needs to be changed.
3) Python library
Pip install python-bitcoinrpc
BTC-Fiat exchange rate api
BTC transaction fees api
1.5 Getting started
1.5.1 Creating a Key (Subject to the bip32 bip39 bip44 standard)
Note that if it is testnet or regtest, according to the configuration of the config file, if you use the bx tool like me, configure the description of 1.4;
In addition, testnet's cointype is 1, https://github.com/satoshilabs/slips/blob/master/slip-0044.md
Now start creating mnemonic mnemonics and root node master node with bx tool
The website program uses xpub(m/44'/1'/0'/0)[tpubDFCmqNxHDiBWw9e8XUEhkHqcw1i4drCe2mwwpR83eA2Arfmq8hJkUeVYY7hYaQWEo4HZDQ86FiRYj8Lr3e9UT8bYi7yLvbNbXgqyJeqLYii] to generate a user recharge address;
The timing task program uses xprv(m/44'/1'/0'/0)[tprv8iWjgxv35LVr3gcLdpa7LtBWMzC8UX1jTUMAXu5kDtDn2BX4WJVAJ9sgMzFjuoiWjhUdamEeB7sxPS6uzkmcEAAXNAevuaRWYQFMwX713mP] to transfer the centralized bitcoin to the internal account. To simplify the demo, use the fixed account address addr( m/44'/1'/ 1'/0/0)[muz1awk6YXQkP29dt1tdRpBTonmqAqwdst]).
1.5.2 Setting up the test environment
1) Use bitcoin testnet wallet https://play.google.com/store/apps/details?id=de.schildbach.wallet_test
2) Get test bitcoin
3) Allow bitcoin core
Testnet configuration ~/.bitcoin/bitcoin.conf
Bitcoind -testnet -printtoconsole/-daemon
Then import the internal account test address
Bitcoin-cli -testnet importprivkey cVHBtHK7kzze7yqF5En4Psbw2ZZdUEJ8jF4KAMXhLpuSwUf4fZAU "internal0" true
4) Testnet explorer
1.5.3 Website Program
You can create a simple web app using nodejs webpack
Reference bitcoinjs library, reference code:
Generate addresses for users using xpub(m/44'/1'/0'/0)
1.5.4 Scheduled Task Procedure
2) Transfer centralized users to recharge to internal accounts
Note: For withdrawals, from internal account to btc to user's personal address, I originally wanted to use signtransactionwithkey offline signature, but the problem is that this needs to know all utxo, which means that all utxo should be managed well, of course, by observing the wallet. The way to get utxo (has not tested yet), import pubkey to bitcoin core, rpc gets unspent transaction, but still need some strategy to use these utxo, such as using low output output each time, otherwise it may produce more and more Small amount of output, so in fact the demo is lazy, directly processed in the way of sendmany