{"id":4892,"date":"2018-03-28T07:00:44","date_gmt":"2018-03-28T14:00:44","guid":{"rendered":"https:\/\/www.couchbase.com\/blog\/?p=4892"},"modified":"2025-06-13T18:45:36","modified_gmt":"2025-06-14T01:45:36","slug":"developing-bitcoin-cryptocurrency-application-nodejs-nosql","status":"publish","type":"post","link":"https:\/\/www.couchbase.com\/blog\/developing-bitcoin-cryptocurrency-application-nodejs-nosql\/","title":{"rendered":"Developing a Bitcoin Cryptocurrency Application with Node.js and NoSQL"},"content":{"rendered":"<p>I&#8217;ve been following cryptocurrency-related subjects such as Bitcoin for a few months now and I&#8217;m very fascinated with everything that has been going on.<\/p>\n<p>As a web application developer, one topic that I&#8217;ve been particularly interested in learning more about is around cryptocurrency exchanges and how to make them. From the front, these applications seem to be tools for managing accounts, converting Bitcoin to a fiat currency like USD and back, and transferring Bitcoin to other people, but are they more?<\/p>\n<p>We&#8217;re going to look at some examples with Node.js and the NoSQL database, <a href=\"https:\/\/www.couchbase.com\" target=\"_blank\" rel=\"noopener noreferrer\">Couchbase<\/a>, that covers topics modeled around cryptocurrency exchanges.<\/p>\n<p><b>Updates on related topics:<\/b><\/p>\n<ul>\n<li><a href=\"https:\/\/www.couchbase.com\/blog\/couchbase-blockchain-nosql-database-synergy\/\">The Synergy of Blockchain and NoSQL Databases<\/a><\/li>\n<li><a href=\"https:\/\/www.couchbase.com\/blog\/couchbase-brings-distributed-multi-document-acid-transactions-to-nosql\/\">Couchbase Distributed Multi-Document ACID Transactions<\/a><\/li>\n<\/ul>\n<p><!--more--><\/p>\n<p><strong>Disclaimer:<\/strong> I am not a cryptocurrency expert, nor have I taken part in any development around financial services or exchanges. I am an enthusiast of the subject material and anything obtained from this article should be properly tested and used at your own risk.<\/p>\n<h2>The Take-Away<\/h2>\n<p>There are a few things that you will and won&#8217;t get from this particular article. For example, let&#8217;s start with the things you won&#8217;t get out of this article:<\/p>\n<ul>\n<li>We won&#8217;t configure any banking or credit card services to transfer fiat currencies such as USD.<\/li>\n<li>We won&#8217;t be broadcasting any signed transactions to the Bitcoin network, finalizing a transfer.<\/li>\n<\/ul>\n<p>That said, here are some things you can look forward to learning about in this article:<\/p>\n<ul>\n<li>We&#8217;ll create a\u00a0hierarchical deterministic (HD) wallet that can generate an unlimited amount of keys for a given seed, each representing a user wallet.<\/li>\n<li>We&#8217;ll create user accounts each with wallets based on the master seed.<\/li>\n<li>We&#8217;ll create transactions that represent deposits, withdrawals, and transfers of funds from the exchange, without actually working with a fiat currency.<\/li>\n<li>We&#8217;ll lookup balances from the Bitcoin network.<\/li>\n<li>We&#8217;ll create signed transactions to be broadcasted on the Bitcoin network.<\/li>\n<\/ul>\n<p>There are many things that we&#8217;ll see in this article that can be done way better. If you found something that could be improved, definitely share it in the comments. Like I said, I&#8217;m not an expert on the topic, just a fan.<\/p>\n<h2>The Project Requirements<\/h2>\n<p>There are a few requirements that must be met to be successful with this project:<\/p>\n<ul>\n<li>You must have Node.js 6+ installed and configured.<\/li>\n<li>You must have Couchbase 5.1+ installed and configured with a Bucket and RBAC profile ready to go.<\/li>\n<\/ul>\n<p>The main point is that I won&#8217;t be going through how to get Couchbase up and running. It isn&#8217;t a difficult process, but you&#8217;ll need a Bucket set up with an application account and an index for querying with N1QL.<\/p>\n<h2>Creating a Node.js Application with Dependencies<\/h2>\n<p>We&#8217;re going to create a new Node.js application and download the dependencies before we start adding any logic. Create a project directory somewhere on your computer and execute the following commands from a CLI within that directory:<\/p>\n<pre class=\"lang:default decode:true \">npm init -y\r\nnpm install couchbase --save\r\nnpm install express --save\r\nnpm install body-parser --save\r\nnpm install joi --save\r\nnpm install request request-promise --save\r\nnpm install uuid --save\r\nnpm install bitcore-lib --save\r\nnpm install bitcore-mnemonic --save<\/pre>\n<p>I know I could have done all of the dependency installations in a single line, but I wanted to make them clear to read. So what are we doing in the above commands?<\/p>\n<p>First, we&#8217;re initializing a new Node.js project by creating a\u00a0<strong>package.json<\/strong> file. Then we&#8217;re downloading our dependencies and adding them to the\u00a0<strong>package.json<\/strong> file via the <code>--save<\/code> flag.<\/p>\n<p>For this example we&#8217;ll be using Express Framework. The <code>express<\/code>, <code>body-parser<\/code>, and <code>joi<\/code> packages are all relevant towards accepting and validating request data. Because we&#8217;ll be communicating with public Bitcoin nodes, we will be using the <code>request<\/code> and <code>request-promise<\/code> promise wrapping package. The very popular <code>bitcore-lib<\/code> package will allow us to create wallets and sign transactions while the <code>bitcore-mnemonic<\/code> package will allow us to generate a seed that can be used for our HD wallet keys. Finally, <code>couchbase<\/code> and <code>uuid<\/code> will be used for working with our database.<\/p>\n<p>Now we probably want to better structure our project. Add the following directories and files within your project directory if they do not already exist:<\/p>\n<pre class=\"lang:default decode:true \">package.json\r\nconfig.json\r\napp.js\r\nroutes\r\n    account.js\r\n    transaction.js\r\n    utility.js\r\nclasses\r\n    helper.js<\/pre>\n<p>All of our API endpoints will be split into categories and placed in each appropriate routing file. We don&#8217;t have to do this, but it makes our project just a little bit cleaner. To remove a ton of Bitcoin and database logic out of our routes, we&#8217;ll be adding everything that isn&#8217;t data validation into our\u00a0<strong>classes\/helper.js<\/strong> file. The\u00a0<strong>config.json<\/strong> file will have all of our database information as well as our mnemonic seed. In a realistic scenario, this file should be treated like gold and receive as much protection as it could possibly receive. The\u00a0<strong>app.js<\/strong> file will have all of our configuration and bootstrapping logic towards connecting our routes, connecting to the database, etc.<\/p>\n<p>As a convenience, we&#8217;re going to add one more dependency to our project and set it up:<\/p>\n<pre class=\"lang:default decode:true \">npm install nodemon --save-dev<\/pre>\n<p>The <code>nodemon<\/code> package will allow us to hot-reload our project every time we change a file. It is not a requirement, but can save us some time as we&#8217;re building.<\/p>\n<p>Open the\u00a0<strong>package.json<\/strong> file and add the following script to make it happen:<\/p>\n<pre class=\"lang:default decode:true \">...\r\n\"scripts\": {\r\n    \"test\": \"echo \\\"Error: no test specified\\\" &amp;&amp; exit 1\",\r\n    \"start\": \".\/node_modules\/nodemon\/bin\/nodemon.js app.js\"\r\n},\r\n...<\/pre>\n<p>We can start the development process of our application at this point.<\/p>\n<h2>Developing the Database and Bitcoin Logic<\/h2>\n<p>When it comes to developing our application, before we start worrying about API endpoints, we want to create our database and Bitcoin related logic.<\/p>\n<p>We&#8217;re going to be spending our time in the project&#8217;s\u00a0<strong>classes\/helper.js<\/strong> file. Open it and include the following:<\/p>\n<pre class=\"lang:default decode:true \">const Couchbase = require(\"couchbase\");\r\nconst Request = require(\"request-promise\");\r\nconst UUID = require(\"uuid\");\r\nconst Bitcore = require(\"bitcore-lib\");\r\n\r\nclass Helper {\r\n\r\n    constructor(host, bucket, username, password, seed) {\r\n        this.cluster = new Couchbase.Cluster(\"couchbase:\/\/\" + host);\r\n        this.cluster.authenticate(username, password);\r\n        this.bucket = this.cluster.openBucket(bucket);\r\n        this.master = seed;\r\n    }\r\n\r\n    createKeyPair(account) { }\r\n\r\n    getWalletBalance(addresses) { }\r\n\r\n    getAddressBalance(address) { }\r\n\r\n    getAddressUtxo(address) { }\r\n\r\n    insert(data, id = UUID.v4()) { }\r\n\r\n    createAccount(data) { }\r\n\r\n    addAddress(account) { }\r\n\r\n    getAccountBalance(account) { }\r\n\r\n    getMasterAddresses() { }\r\n\r\n    getMasterKeyPairs() { }\r\n\r\n    getMasterAddressWithMinimum(addresses, amount) { }\r\n\r\n    getMasterChangeAddress() { }\r\n\r\n    getAddresses(account) { }\r\n\r\n    getPrivateKeyFromAddress(account, address) { }\r\n\r\n    createTransactionFromAccount(account, source, destination, amount) { }\r\n\r\n    createTransactionFromMaster(account, destination, amount) { }\r\n\r\n}\r\n\r\nmodule.exports = Helper;<\/pre>\n<p>We&#8217;re going to be passing this class around as a singleton for our application. In the <code>constructor<\/code> method, we are establishing a connection to our database cluster, opening a Bucket, and authenticating. The open Bucket will be used throughout this helper class.<\/p>\n<p>Let&#8217;s knock out the Bitcoin logic before the database logic.<\/p>\n<p>If you&#8217;re not familiar with HD wallets, they are essentially a wallet derived of a single seed. Using the seed you can derive children and those children can have children, and so on and so forth.<\/p>\n<pre class=\"lang:default decode:true \">createKeyPair(account) {\r\n    var account = this.master.deriveChild(account);\r\n    var key = account.deriveChild(Math.random() * 10000 + 1);\r\n    return { \"secret\": key.privateKey.toWIF().toString(), \"address\": key.privateKey.toAddress().toString() }\r\n}<\/pre>\n<p>The <code>master<\/code> variable in the <code>createKeyPair<\/code> function represents the top level seed key. Each user account will be a direct child of that key, hence we are deriving a child based on an <code>account<\/code> value. The <code>account<\/code> value is a person number and every account created will get an incremental number. However, we&#8217;re not going to generate account keys and call it a day. Instead, each account key will have 10,000 possible private and public keys in case they don&#8217;t want to use the same key more than once. Once we&#8217;ve generated a key at random, we return it.<\/p>\n<p>Similarly, we have a <code>getMasterChangeAddress<\/code> function like the following:<\/p>\n<pre class=\"lang:default decode:true \">getMasterChangeAddress() {\r\n    var account = this.master.deriveChild(0);\r\n    var key = account.deriveChild(Math.random() * 10 + 1);\r\n    return { \"secret\": key.privateKey.toWIF().toString(), \"address\": key.privateKey.toAddress().toString() }\r\n}<\/pre>\n<p>When we start creating accounts, they will start at one, leaving zero for the exchange or the web application, or whatever you want to call it. We are also allocating 10 possible addresses to this account. These addresses will do two possible things. The first is that they will hold Bitcoin to transfer to other accounts and the second is that they will receive remainder payments, otherwise known as the change. Remember, in a Bitcoin transaction, all unspent transaction output (UTXO) must be spent, even if it is less than the desired amount. This means that the desired amount gets sent to the destination and the remainder gets sent back into one of these 10 addresses.<\/p>\n<p>Are there other ways or better ways to do this? Absolutely, but this one will work for the example.<\/p>\n<p>To get a balance for any address we use or generate using the HD seed, we can use a public Bitcoin explorer:<\/p>\n<pre class=\"lang:default decode:true \">getAddressBalance(address) {\r\n    return Request(\"https:\/\/insight.bitpay.com\/api\/addr\/\" + address);\r\n}<\/pre>\n<p>The above function will take an address and get the balance in decimal format as well as satoshis. Going forward, the satoshi value is the only relevant value to us. If we have X number of addresses for a given account, we can get the total balance using a function like this:<\/p>\n<pre class=\"lang:default decode:true \">getWalletBalance(addresses) {\r\n    var promises = [];\r\n    for(var i = 0; i &lt; addresses.length; i++) {\r\n        promises.push(Request(\"https:\/\/insight.bitpay.com\/api\/addr\/\" + addresses[i]));\r\n    }\r\n    return Promise.all(promises).then(result =&gt; {\r\n        var balance = result.reduce((a, b) =&gt; a + JSON.parse(b).balanceSat, 0);\r\n        return new Promise((resolve, reject) =&gt; {\r\n            resolve({ \"balance\": balance });\r\n        });\r\n    });\r\n}<\/pre>\n<p>In the above <code>getWalletBalance<\/code> function we are making a request for each address and when they&#8217;ve all completed, we can add the balances and return them.<\/p>\n<p>It takes a little more than just an address balance to be able to transfer cryptocurrency. Instead we need to know the unspent transaction output (UTXO) for a given address. This can be found using the same API from BitPay:<\/p>\n<pre class=\"lang:default decode:true \">getAddressUtxo(address) {\r\n    return Request(\"https:\/\/insight.bitpay.com\/api\/addr\/\" + address + \"\/utxo\").then(utxo =&gt; {\r\n        return new Promise((resolve, reject) =&gt; {\r\n            if(JSON.parse(utxo).length == 0) {\r\n                reject({ \"message\": \"There are no unspent transactions available.\" });\r\n            }\r\n            resolve(JSON.parse(utxo));\r\n        });\r\n    });\r\n}<\/pre>\n<p>If there is no unspent transaction output, it means there is nothing we can transfer and we should throw an error instead. Having enough to transfer is a different story.<\/p>\n<p>For example, we could do something like this:<\/p>\n<pre class=\"lang:default decode:true \">getMasterAddressWithMinimum(addresses, amount) {\r\n    var promises = [];\r\n    for(var i = 0; i &lt; addresses.length; i++) {\r\n        promises.push(Request(\"https:\/\/insight.bitpay.com\/api\/addr\/\" + addresses[i]));\r\n    }\r\n    return Promise.all(promises).then(result =&gt; {\r\n        for(var i = 0; i &lt; result.length; i++) {\r\n            if(result[i].balanceSat &gt;= amount) {\r\n                return resolve({ \"address\": result[i].addrStr });\r\n            }\r\n        }\r\n        reject({ \"message\": \"Not enough funds in exchange\" });\r\n    });\r\n}<\/pre>\n<p>In the above function, we are taking a list of addresses and checking to see which one holds an amount greater than the threshold that we provide. If none of them have enough balance, we should probably relay that message.<\/p>\n<p>The final utility related function, is something we&#8217;ve kind of already seen:<\/p>\n<pre class=\"lang:default decode:true \">getMasterKeyPairs() {\r\n    var keypairs = [];\r\n    var key;\r\n    var account = this.master.deriveChild(0);\r\n    for(var i = 1; i &lt;= 10; i++) {\r\n        key = account.deriveChild(i);\r\n        keypairs.push({ \"secret\": key.privateKey.toWIF().toString(), \"address\": key.privateKey.toAddress().toString() });\r\n    }\r\n    return keypairs;\r\n}<\/pre>\n<p>The above function will get us all master keys, which will be useful for signing and checking value.<\/p>\n<p>Just to reiterate, I&#8217;m using a finite value to how many keys are generated. You may or may not want to do the same, it is up to you.<\/p>\n<p>Now let&#8217;s dive into some NoSQL logic for storing our application data.<\/p>\n<p>As of right now there is no data in our database. The first logic step might be to create some data. While it isn&#8217;t particularly difficult standalone, we can create a function like this:<\/p>\n<pre class=\"lang:default decode:true \">insert(data, id = UUID.v4()) {\r\n    return new Promise((resolve, reject) =&gt; {\r\n        this.bucket.insert(id, data, (error, result) =&gt; {\r\n            if(error) {\r\n                reject({ \"code\": error.code, \"message\": error.message });\r\n            }\r\n            data.id = id;\r\n            resolve(data);\r\n        });\r\n    });\r\n}<\/pre>\n<p>Essentially, we&#8217;re accepting an object and an id to be used as a document key. If a document key isn&#8217;t provided, we&#8217;ll automatically generate it. When all said and done, we&#8217;ll return what was created including the id in the response.<\/p>\n<p>So let&#8217;s say we want to create a user account. We can do the following:<\/p>\n<pre class=\"lang:default decode:true \">createAccount(data) {\r\n    return new Promise((resolve, reject) =&gt; {\r\n        this.bucket.counter(\"accounts::total\", 1, { \"initial\": 1 }, (error, result) =&gt; {\r\n            if(error) {\r\n                reject({ \"code\": error.code, \"message\": error.message });\r\n            }\r\n            data.account = result.value;\r\n            this.insert(data).then(result =&gt; {\r\n                resolve(result);\r\n            }, error =&gt; {\r\n                reject(error);\r\n            });\r\n        });\r\n    });\r\n}<\/pre>\n<p>Remember, accounts are driven by an auto incrementing numeric value for this example. We can create incrementing values by using a <code>counter<\/code> in Couchbase. If the counter doesn&#8217;t exist, we&#8217;ll initialize it at 1 and increment it every next call. Remember, 0 is reserved for application keys.<\/p>\n<p>After we get our counter value, we add it to the object that was passed and call our insert function, which in this case generates a unique id for us.<\/p>\n<p>We haven&#8217;t seen it yet because we don&#8217;t have any endpoints, but lets assume that when we create an account, it has no address information, only an account identifier. We might want to add an address for the user:<\/p>\n<pre class=\"lang:default decode:true \">addAddress(account) {\r\n    return new Promise((resolve, reject) =&gt; {\r\n        this.bucket.get(account, (error, result) =&gt; {\r\n            if(error) {\r\n                reject({ \"code\": error.code, \"message\": error.message });\r\n            }\r\n            var keypair = this.createKeyPair(result.value.account);\r\n            this.bucket.mutateIn(account).arrayAppend(\"addresses\", keypair, true).execute((error, result) =&gt; {\r\n                if(error) {\r\n                    reject({ \"code\": error.code, \"message\": error.message });\r\n                }\r\n                resolve({ \"address\": keypair.address });\r\n            });\r\n        });\r\n    });\r\n}<\/pre>\n<p>When adding an address, we first get the user by the document id. When the document is retrieved, we get the numeric account value and create a fresh keypair of our 10,000 options. Using a <a href=\"https:\/\/www.couchbase.com\/blog\/subdoc-explained\/\">sub-document<\/a> operation, we can add the keypair to the user document without ever having to download the document or manipulating it.<\/p>\n<p>Something very serious to note about what we&#8217;ve just done.<\/p>\n<p>I am storing the unencrypted private key and public address in the user document. This is a big no-no for production. Remember all those stories you read about where people got their keys stolen? In reality, we&#8217;d want to encrypt the data before inserting it. We can do that by using the Node.js crypto library, or if we&#8217;re using Couchbase Server 5.5, the Node.js SDK for Couchbase offers encryption. We won&#8217;t explore it here though.<\/p>\n<p>Okay, we&#8217;ve got account data and addresses in the database now. Let&#8217;s query for that data:<\/p>\n<pre class=\"lang:default decode:true \">getAddresses(account) {\r\n    var statement, params;\r\n    if(account) {\r\n        statement = \"SELECT VALUE addresses.address FROM \" + this.bucket._name + \" AS account USE KEYS $id UNNEST account.addresses as addresses\";\r\n        params = { \"id\": account };\r\n    } else {\r\n        statement = \"SELECT VALUE addresses.address FROM \" + this.bucket._name + \" AS account UNNEST account.addresses as addresses WHERE account.type = 'account'\";\r\n    }\r\n    var query = Couchbase.N1qlQuery.fromString(statement);\r\n    return new Promise((resolve, reject) =&gt; {\r\n        this.bucket.query(query, params, (error, result) =&gt; {\r\n            if(error) {\r\n                reject({ \"code\": error.code, \"message\": error.message });\r\n            }\r\n            resolve(result);\r\n        });\r\n    });\r\n}<\/pre>\n<p>The above <code>getAddresses<\/code> function can do one of two things. If an account was provided, we&#8217;ll use a N1QL query to get all addresses for that particular account. If no account was provided, we&#8217;ll get all addresses for every account in the database. In both scenarios, we&#8217;re only getting public addresses, nothing sensitive. Using a parameterized N1QL query, we can return the database results back to the client.<\/p>\n<p>Something to note in our query.<\/p>\n<p>We&#8217;re storing our addresses in an array in the user documents. Using an <code>UNNEST<\/code> operator, we can flatten those addresses and make the response more attractive.<\/p>\n<p>Now let&#8217;s say we have an address and we want to get the corresponding private key. We might do the following:<\/p>\n<pre class=\"lang:default decode:true \">getPrivateKeyFromAddress(account, address) {\r\n    var statement = \"SELECT VALUE keypairs.secret FROM \" + this.bucket._name + \" AS account USE KEYS $account UNNEST account.addresses AS keypairs WHERE keypairs.address = $address\";\r\n    var query = Couchbase.N1qlQuery.fromString(statement);\r\n    return new Promise((resolve, reject) =&gt; {\r\n        this.bucket.query(query, { \"account\": account, \"address\": address }, (error, result) =&gt; {\r\n            if(error) {\r\n                reject({ \"code\": error.code, \"message\": error.message });\r\n            }\r\n            resolve({ \"secret\": result[0] });\r\n        });\r\n    });\r\n}<\/pre>\n<p>Given a particular account, we create a query similar to what we saw previously. This time, after we <code>UNNEST<\/code>, we do a <code>WHERE<\/code> condition to give us results only for the matching address. If we wanted to we could have done an array operation instead. With Couchbase and N1QL, there are numerous ways to solve a problem.<\/p>\n<p>We&#8217;re going to change gears a bit here. Up until now we&#8217;ve done account oriented operations in our NoSQL database. Another important aspect is transactions. For example, maybe user X deposits some USD currency for BTC and user Y does a withdrawal. We need to store and query for that transaction information.<\/p>\n<p>The API endpoint functions will save the transaction data, but we can still query for it.<\/p>\n<pre class=\"lang:default decode:true \">getAccountBalance(account) {\r\n    var statement = \"SELECT SUM(tx.satoshis) AS balance FROM \" + this.bucket._name + \" AS tx WHERE tx.type = 'transaction' AND tx.account = $account\";\r\n    var query = Couchbase.N1qlQuery.fromString(statement);\r\n    return new Promise((resolve, reject) =&gt; {\r\n        this.bucket.query(query, { \"account\": account }, (error, result) =&gt; {\r\n            if(error) {\r\n                reject({ \"code\": error.code, \"message\": error.message });\r\n            }\r\n            resolve({ \"balance\": result[0].balance });\r\n        });\r\n    });\r\n}<\/pre>\n<p>Given an account, we want to get an account balance for a particular user.<\/p>\n<p>Wait a second, let&#8217;s take a step back because didn&#8217;t we already create some account balance functions? Technically we did, but those functions were for checking the wallet balance, not the account balance.<\/p>\n<p>This is where some of my experience turns into gray area. Every time you transfer Bitcoin, there is a fee involved, and sometimes it is quite expensive. When you make a deposit, it isn&#8217;t cost effective to transfer money into your wallet because it would be charged a miner fee. Then you would be charged to withdraw and even transfer again. You&#8217;ve already lost most of your Bitcoin at that point.<\/p>\n<p>Instead, I believe exchanges have a holding account similar to a stock exchange money market account. There is record of the money that you should have in your account, but it isn&#8217;t technically in a wallet. When you want transfer, you&#8217;re transferring from the application address, not your user address. When you withdraw, it is just being subtracted.<\/p>\n<p>Again, I don&#8217;t know if that is truly how it works, but that is how I&#8217;d do it in order to avoid fees everywhere.<\/p>\n<p>Going back to our <code>getAccountBalance<\/code> function. We&#8217;re taking a sum of every transaction. Deposits have a positive value while transfers and withdrawals have a negative value. Aggregating this information together should give you an accurate number, excluding your wallet balance. Later we&#8217;ll be getting an account with wallet balance.<\/p>\n<p>Given the little that we know about account balances, we can try to create a transaction from our wallet:<\/p>\n<pre class=\"lang:default decode:true \">createTransactionFromAccount(account, source, destination, amount) {\r\n    return new Promise((resolve, reject) =&gt; {\r\n        this.getAddressBalance(source).then(sourceAddress =&gt; {\r\n            if(sourceAddress.balanceSat &lt; amount) {\r\n                return reject({ \"message\": \"Not enough funds in account.\" });\r\n            }\r\n            this.getPrivateKeyFromAddress(account, source).then(keypair =&gt; {\r\n                this.getAddressUtxo(source).then(utxo =&gt; {\r\n                    var transaction = new Bitcore.Transaction();\r\n                    for(var i = 0; i &lt; utxo.length; i++) {\r\n                        transaction.from(utxo[i]);\r\n                    }\r\n                    transaction.to(destination, amount);\r\n                    this.addAddress(account).then(change =&gt; {\r\n                        transaction.change(change.address);\r\n                        transaction.sign(keypair.secret);\r\n                        resolve(transaction);\r\n                    }, error =&gt; reject(error));\r\n                }, error =&gt; reject(error));\r\n            }, error =&gt; reject(error));\r\n        }, error =&gt; reject(error));\r\n    });\r\n}<\/pre>\n<p>If provided a source address, destination address, and amount, we can create and sign a transaction to be later broadcasted on the Bitcoin network.<\/p>\n<p>First we get the balance for the source address in question. We need to make sure it has enough UTXO to meet the send amount expectation. Note that in this example, we&#8217;re doing single address transactions. If you wanted to get complicated, you could send from multiple addresses in a single transaction. We&#8217;re not going to do that here. If our single address has enough funds, we get the private key for it and the UTXO data. With the UTXO data we can create a Bitcoin transaction, apply the destination address and a change address, then sign the transaction using our private key. The response can be broadcasted.<\/p>\n<p>Similarly let&#8217;s say we wanted to transfer Bitcoin from our holding account:<\/p>\n<pre class=\"lang:default decode:true \">createTransactionFromMaster(account, destination, amount) {\r\n    return new Promise((resolve, reject) =&gt; {\r\n        this.getAccountBalance(account).then(accountBalance =&gt; {\r\n            if(accountBalance.balance &lt; amount) {\r\n                reject({ \"message\": \"Not enough funds in account.\" });\r\n            }\r\n            var mKeyPairs = this.getMasterKeyPairs();\r\n            var masterAddresses = mKeyPairs.map(a =&gt; a.address);\r\n            this.getMasterAddressWithMinimum(masterAddresses, amount).then(funds =&gt; {\r\n                this.getAddressUtxo(funds.address).then(utxo =&gt; {\r\n                    var transaction = new Bitcore.Transaction();\r\n                    for(var i = 0; i &lt; utxo.length; i++) {\r\n                        transaction.from(utxo[i]);\r\n                    }\r\n                    transaction.to(destination, amount);\r\n                    var change = helper.getMasterChangeAddress();\r\n                    transaction.change(change.address);\r\n                    for(var j = 0; j &lt; mKeyPairs.length; j ++) {\r\n                        if(mKeyPairs[j].address == funds.address) {\r\n                            transaction.sign(mKeyPairs[j].secret);\r\n                        }\r\n                    }\r\n                    var tx = {\r\n                        account: account,\r\n                        satoshis: (amount * -1),\r\n                        timestamp: (new Date()).getTime(),\r\n                        status: \"transfer\",\r\n                        type: \"transaction\"\r\n                    };\r\n                    this.insert(tx).then(result =&gt; {\r\n                        resolve(transaction);\r\n                    }, error =&gt; reject(error));\r\n                }, error =&gt; reject(error));\r\n            }, error =&gt; reject(error));\r\n        }, error =&gt; reject(error));\r\n    });\r\n}<\/pre>\n<p>We&#8217;re assuming that our exchange addresses have been loaded with an insane amount of Bitcoin to meet demand.<\/p>\n<p>The first step is to make sure we have funding in our holding account. We can execute that query that sums up each of our transactions to get a valid number. If we have enough, we can get all 10 of our master key pairs and the addresses. We need to check which address has enough funds to send. Remember, single address transactions here, when there could be more.<\/p>\n<p>If an address has enough funds, we get the UTXO data and start making a transaction. This time instead of our wallet as the source address, we use the wallet of the exchange. After we get a signed transaction, we want to create a transaction in our database to subtract the value that we&#8217;re transferring.<\/p>\n<p>Before we move onto the API endpoints, I want to re-iterate a few things:<\/p>\n<ul>\n<li>I&#8217;m assuming that popular exchanges have a holding account to avoid fees imposed on wallet addresses.<\/li>\n<li>We are using single address transactions in this example, rather than aggregating what we have.<\/li>\n<li>I&#8217;m not encrypting the key data in the account documents, when I should be.<\/li>\n<li>I&#8217;m not broadcasting any transactions, only creating them.<\/li>\n<\/ul>\n<p>Now let&#8217;s focus on our API endpoints, the simple part.<\/p>\n<h2>Designing RESTful API Endpoints with Express Framework<\/h2>\n<p>Remember, as we configured in the beginning, our endpoints will be split across three files which act as groupings. We&#8217;ll start with the smallest and simplest group of endpoints, which are more for utility than anything else.<\/p>\n<p>Open the project&#8217;s\u00a0<strong>routes\/utility.js<\/strong> file and include the following:<\/p>\n<pre class=\"lang:default decode:true \">const Bitcore = require(\"bitcore-lib\");\r\nconst Mnemonic = require(\"bitcore-mnemonic\");\r\n\r\nmodule.exports = (app) =&gt; {\r\n\r\n    app.get(\"\/mnemonic\", (request, response) =&gt; {\r\n        response.send({\r\n            \"mnemonic\": (new Mnemonic(Mnemonic.Words.ENGLISH)).toString()\r\n        });\r\n    });\r\n\r\n    app.get(\"\/balance\/value\", (request, response) =&gt; {\r\n        Request(\"https:\/\/api.coinmarketcap.com\/v1\/ticker\/bitcoin\/\").then(market =&gt; {\r\n            response.send({ \"value\": \"$\" + (JSON.parse(market)[0].price_usd * request.query.balance).toFixed(2) });\r\n        }, error =&gt; {\r\n            response.status(500).send(error);\r\n        });\r\n    });\r\n\r\n}<\/pre>\n<p>Here we have two endpoints, one for generating mnemonic seeds and the other for getting the fiat value of a Bitcoin balance. Neither are truly necessary, but on first launch, it might be nice to generate a seed value to later save in our config file.<\/p>\n<p>Now open the project&#8217;s\u00a0<strong>routes\/account.js<\/strong> file so we can handle account information:<\/p>\n<pre class=\"lang:default decode:true \">const Request = require(\"request-promise\");\r\nconst Joi = require(\"joi\");\r\nconst helper = require(\"..\/app\").helper;\r\n\r\nmodule.exports = (app) =&gt; {\r\n\r\n    app.post(\"\/account\", (request, response) =&gt; { });\r\n\r\n    app.put(\"\/account\/address\/:id\", (request, response) =&gt; { });\r\n\r\n    app.get(\"\/account\/addresses\/:id\", (request, response) =&gt; { });\r\n\r\n    app.get(\"\/addresses\", (request, response) =&gt; { });\r\n\r\n    app.get(\"\/account\/balance\/:id\", (request, response) =&gt; { });\r\n\r\n    app.get(\"\/address\/balance\/:id\", (request, response) =&gt; { });\r\n\r\n}<\/pre>\n<p>Notice that we&#8217;re pulling the helper class from the\u00a0<strong>app.js<\/strong> file that we haven&#8217;t started yet. Just go with it for now and it will make sense later, although it isn&#8217;t anything special.<\/p>\n<p>When it comes to creating accounts, we have the following:<\/p>\n<pre class=\"lang:default decode:true \">app.post(\"\/account\", (request, response) =&gt; {\r\n    var model = Joi.object().keys({\r\n        firstname: Joi.string().required(),\r\n        lastname: Joi.string().required(),\r\n        type: Joi.string().forbidden().default(\"account\")\r\n    });\r\n    Joi.validate(request.body, model, { stripUnknown: true }, (error, value) =&gt; {\r\n        if(error) {\r\n            return response.status(500).send(error);\r\n        }\r\n        helper.createAccount(value).then(result =&gt; {\r\n            response.send(value);\r\n        }, error =&gt; {\r\n            response.status(500).send(error);\r\n        });\r\n    });\r\n});<\/pre>\n<p>Using Joi we can validate the request body and throw errors if it isn&#8217;t correct. Assuming the request body is correct, we can call our <code>createAccount<\/code> function to save a new account in the database.<\/p>\n<p>With an account created, we can add some addresses:<\/p>\n<pre class=\"lang:default decode:true \">app.put(\"\/account\/address\/:id\", (request, response) =&gt; {\r\n    helper.addAddress(request.params.id).then(result =&gt; {\r\n        response.send(result);\r\n    }, error =&gt; {\r\n        return response.status(500).send(error);\r\n    });\r\n});<\/pre>\n<p>Using the account id that was passed, we can call our <code>addAddress<\/code> function to use a subdocument operation on our document.<\/p>\n<p>Not so bad right?<\/p>\n<p>To get all addresses for a particular account, we might have something like the following:<\/p>\n<pre class=\"lang:default decode:true \">app.get(\"\/account\/addresses\/:id\", (request, response) =&gt; {\r\n    helper.getAddresses(request.params.id).then(result =&gt; {\r\n        response.send(result);\r\n    }, error =&gt; {\r\n        response.status(500).send(error);\r\n    });\r\n});<\/pre>\n<p>Alternatively, if we don&#8217;t provide an id, we can get all addresses from all accounts using the following endpoint function:<\/p>\n<pre class=\"lang:default decode:true \">app.get(\"\/addresses\", (request, response) =&gt; {\r\n    helper.getAddresses().then(result =&gt; {\r\n        response.send(result);\r\n    }, error =&gt; {\r\n        response.status(500).send(error);\r\n    });\r\n});<\/pre>\n<p>Now for probably the trickiest endpoint function. Let&#8217;s say we want to get the balance of our account, which includes the holding account as well as each of our wallet addresses. We can do the following:<\/p>\n<pre class=\"lang:default decode:true \">app.get(\"\/account\/balance\/:id\", (request, response) =&gt; {\r\n    helper.getAddresses(request.params.id).then(addresses =&gt; helper.getWalletBalance(addresses)).then(balance =&gt; {\r\n        helper.getAccountBalance(request.params.id).then(result =&gt; {\r\n            response.send({ \"balance\": balance.balance + result.balance });\r\n        }, error =&gt; {\r\n            response.status(500).send({ \"code\": error.code, \"message\": error.message });\r\n        });\r\n    }, error =&gt; {\r\n        response.status(500).send({ \"code\": error.code, \"message\": error.message });\r\n    });\r\n});<\/pre>\n<p>The above will call both of our functions for obtaining balance, and add the results together to get one massive balance.<\/p>\n<p>The account endpoints weren&#8217;t particularly interesting. Creating transactions is a bit more exciting.<\/p>\n<p>Open the project&#8217;s\u00a0<strong>routes\/transaction.js<\/strong> file and include the following:<\/p>\n<pre class=\"lang:default decode:true \">const Request = require(\"request-promise\");\r\nconst Joi = require(\"joi\");\r\nconst Bitcore = require(\"bitcore-lib\");\r\nconst helper = require(\"..\/app\").helper;\r\n\r\nmodule.exports = (app) =&gt; {\r\n\r\n    app.post(\"\/withdraw\", (request, response) =&gt; { });\r\n\r\n    app.post(\"\/deposit\", (request, response) =&gt; { });\r\n\r\n    app.post(\"\/transfer\", (request, response) =&gt; { });\r\n\r\n}<\/pre>\n<p>We have three different types of transaction. We can deposit fiat currency for Bitcoin, withdraw Bitcoin for fiat currency, and transfer Bitcoin to new wallet addresses.<\/p>\n<p>Let&#8217;s take a look at the deposit endpoint:<\/p>\n<pre class=\"lang:default decode:true \">app.post(\"\/deposit\", (request, response) =&gt; {\r\n    var model = Joi.object().keys({\r\n        usd: Joi.number().required(),\r\n        id: Joi.string().required()\r\n    });\r\n    Joi.validate(request.body, model, { stripUnknown: true }, (error, value) =&gt; {\r\n        if(error) {\r\n            return response.status(500).send(error);\r\n        }\r\n        Request(\"https:\/\/api.coinmarketcap.com\/v1\/ticker\/bitcoin\/\").then(market =&gt; {\r\n            var btc = value.usd \/ JSON.parse(market)[0].price_usd;\r\n            var transaction = {\r\n                account: value.id,\r\n                usd: value.usd,\r\n                satoshis: Bitcore.Unit.fromBTC(btc).toSatoshis(),\r\n                timestamp: (new Date()).getTime(),\r\n                status: \"deposit\",\r\n                type: \"transaction\"\r\n            };\r\n            helper.insert(transaction).then(result =&gt; {\r\n                response.send(result);\r\n            }, error =&gt; {\r\n                response.status(500).send(error);\r\n            });\r\n        }, error =&gt; {\r\n            response.status(500).send(error);\r\n        });\r\n    });\r\n});<\/pre>\n<p>After we validate the input, we check the current value of Bitcoin in USD with CoinMarketCap. Using the data in the response, we can calculate how many Bitcoin we should get based on the USD amount deposited.<\/p>\n<p>After creating a database transaction, we can save it and since it is a positive number, it will come back as positive balance when querying.<\/p>\n<p>Now let&#8217;s say we want to withdraw money from our Bitcoin:<\/p>\n<pre class=\"lang:default decode:true \">app.post(\"\/withdraw\", (request, response) =&gt; {\r\n    var model = Joi.object().keys({\r\n        satoshis: Joi.number().required(),\r\n        id: Joi.string().required()\r\n    });\r\n    Joi.validate(request.body, model, { stripUnknown: true }, (error, value) =&gt; {\r\n        if(error) {\r\n            return response.status(500).send(error);\r\n        }\r\n        helper.getAccountBalance(value.id).then(result =&gt; {\r\n            if(result.balance == null || (result.balance - value.satoshis) &lt; 0) {\r\n                return response.status(500).send({ \"message\": \"There are not `\" + value.satoshis + \"` satoshis available for withdrawal\" });\r\n            }\r\n            Request(\"https:\/\/api.coinmarketcap.com\/v1\/ticker\/bitcoin\/\").then(market =&gt; {\r\n                var usd = (Bitcore.Unit.fromSatoshis(value.satoshis).toBTC() * JSON.parse(market)[0].price_usd).toFixed(2);\r\n                var transaction = {\r\n                    account: value.id,\r\n                    satoshis: (value.satoshis * -1),\r\n                    usd: parseFloat(usd),\r\n                    timestamp: (new Date()).getTime(),\r\n                    status: \"withdrawal\",\r\n                    type: \"transaction\"\r\n                };\r\n                helper.insert(transaction).then(result =&gt; {\r\n                    response.send(result);\r\n                }, error =&gt; {\r\n                    response.status(500).send(error);\r\n                });\r\n            }, error =&gt; {\r\n                response.status(500).send(error);\r\n            });\r\n        }, error =&gt; {\r\n            return response.status(500).send(error);\r\n        });\r\n    });\r\n});<\/pre>\n<p>Similar events are happening here. After validating the request body, we get our account balance and make sure the amount we&#8217;re withdrawing is less than or equal to our balance. If it is, we can do another conversion based on the current price from CoinMarketCap. We&#8217;ll create a transaction using a negative value and save it to the database.<\/p>\n<p>In both these instances we are relying on CoinMarketCap which has had negative controversy in the past. You may want to pick a different resource for conversions.<\/p>\n<p>Finally we have transfers:<\/p>\n<pre class=\"lang:default decode:true \">app.post(\"\/transfer\", (request, response) =&gt; {\r\n    var model = Joi.object().keys({\r\n        amount: Joi.number().required(),\r\n        sourceaddress: Joi.string().optional(),\r\n        destinationaddress: Joi.string().required(),\r\n        id: Joi.string().required()\r\n    });\r\n    Joi.validate(request.body, model, { stripUnknown: true }, (error, value) =&gt; {\r\n        if(error) {\r\n            return response.status(500).send(error);\r\n        }\r\n        if(value.sourceaddress) {\r\n            helper.createTransactionFromAccount(value.id, value.sourceaddress, value.destinationaddress, value.amount).then(result =&gt; {\r\n                response.send(result);\r\n            }, error =&gt; {\r\n                response.status(500).send(error);\r\n            });\r\n        } else {\r\n            helper.createTransactionFromMaster(value.id, value.destinationaddress, value.amount).then(result =&gt; {\r\n                response.send(result);\r\n            }, error =&gt; {\r\n                response.status(500).send(error);\r\n            });\r\n        }\r\n    });\r\n});<\/pre>\n<p>If the request contains a source address, we are going to transfer from our own wallet, otherwise we are going to transfer from the wallet the exchange manages.<\/p>\n<p>All of this is based on functions that we had previously created.<\/p>\n<p>With the endpoints out of the way, we can focus on bootstrapping our application and come to a conclusion.<\/p>\n<h2>Bootstrapping the Express Framework Application<\/h2>\n<p>Right now we have two files that remain untouched by the example. We haven&#8217;t added a configuration or driving logic to bootstrap our endpoints.<\/p>\n<p>Open the project&#8217;s\u00a0<strong>config.json<\/strong> file and include something like the following:<\/p>\n<pre class=\"lang:default decode:true \">{\r\n    \"mnemonic\": \"manage inspire agent october potato thought hospital trim shoulder round tired kangaroo\",\r\n    \"host\": \"localhost\",\r\n    \"bucket\": \"bitbase\",\r\n    \"username\": \"bitbase\",\r\n    \"password\": \"123456\"\r\n}<\/pre>\n<p>Remember this file is incredibly sensitive. Consider locking it down or even using a different approach. If the seed is exposed, every private key for all user accounts and the exchange account can be obtained with zero effort.<\/p>\n<p>Now open the project&#8217;s\u00a0<strong>app.js<\/strong> file and include the following:<\/p>\n<pre class=\"lang:default decode:true \">const Express = require(\"express\");\r\nconst BodyParser = require(\"body-parser\");\r\nconst Bitcore = require(\"bitcore-lib\");\r\nconst Mnemonic = require(\"bitcore-mnemonic\");\r\nconst Config = require(\".\/config\");\r\nconst Helper = require(\".\/classes\/helper\");\r\n\r\nvar app = Express();\r\n\r\napp.use(BodyParser.json());\r\napp.use(BodyParser.urlencoded({ extended: true }));\r\n\r\nvar mnemonic = new Mnemonic(Config.mnemonic);\r\nvar master = new Bitcore.HDPrivateKey(mnemonic.toHDPrivateKey());\r\n\r\nmodule.exports.helper = new Helper(Config.host, Config.bucket, Config.username, Config.password, master);\r\n\r\nrequire(\".\/routes\/account.js\")(app);\r\nrequire(\".\/routes\/transaction.js\")(app);\r\nrequire(\".\/routes\/utility.js\")(app);\r\n\r\nvar server = app.listen(3000, () =&gt; {\r\n    console.log(\"Listening at :\" + server.address().port + \"...\");\r\n});<\/pre>\n<p>What we&#8217;re doing is initializing Express, loading the configuration information, and linking up our routes. The <code>module.exports.helper<\/code> variable is our singleton that will be used in every other JavaScript file.<\/p>\n<h2>Conclusion<\/h2>\n<p>You just saw how to get started with building your own cryptocurrency exchange <a href=\"https:\/\/www.couchbase.com\/blog\/build-a-rest-api-with-node-js-express-and-couchbase\/\">using Node.js<\/a> and <a href=\"https:\/\/www.couchbase.com\" target=\"_blank\" rel=\"noopener noreferrer\">Couchbase<\/a> as the NoSQL database. We covered a lot, from generating HD wallets to creating endpoints with complex database logic.<\/p>\n<p>I cannot stress this enough though. I am a cryptocurrency enthusiast and have no true experience in the financial space. The things I shared should work, but can be done a whole lot better. Don&#8217;t forget to encrypt your keys and keep your seed safe. Test your work and know what you&#8217;re getting yourself into.<\/p>\n<p>If you&#8217;d like to download this project, check it out on <a href=\"https:\/\/github.com\/couchbaselabs\/couchbase-exchange\" target=\"_blank\" rel=\"noopener noreferrer\">GitHub<\/a>. If you&#8217;d like to share insight, experience, ect., on the topic, please share it in the comments. The community can work towards creating something great!<\/p>\n<p>If you&#8217;re a fan of Golang, I created a similar project in a <a href=\"https:\/\/www.thepolyglotdeveloper.com\/2018\/03\/create-bitcoin-hardware-wallet-golang-raspberry-pi-zero\/\" target=\"_blank\" rel=\"noopener noreferrer\">previous tutorial<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I&#8217;ve been following cryptocurrency-related subjects such as Bitcoin for a few months now and I&#8217;m very fascinated with everything that has been going on. As a web application developer, one topic that I&#8217;ve been particularly interested in learning more about [&hellip;]<\/p>\n","protected":false},"author":63,"featured_media":13873,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[1815,1816,1822,1812],"tags":[2190,1725],"ppma_author":[9032],"class_list":["post-4892","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-best-practices-and-tutorials","category-couchbase-server","category-node-js","category-n1ql-query","tag-cryptocurrency","tag-nosql-database"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v25.7.1 (Yoast SEO v25.7) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Bitcoin Cryptocurrency Application with Node.js + NoSQL<\/title>\n<meta name=\"description\" content=\"Read this Couchbase post to see best practice examples of how to develop Bitcoin Cryptocurrency Applications using Node.js and the NoSQL database.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.couchbase.com\/blog\/developing-bitcoin-cryptocurrency-application-nodejs-nosql\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Developing a Bitcoin Cryptocurrency Application with Node.js and NoSQL\" \/>\n<meta property=\"og:description\" content=\"Read this Couchbase post to see best practice examples of how to develop Bitcoin Cryptocurrency Applications using Node.js and the NoSQL database.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.couchbase.com\/blog\/developing-bitcoin-cryptocurrency-application-nodejs-nosql\/\" \/>\n<meta property=\"og:site_name\" content=\"The Couchbase Blog\" \/>\n<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/thepolyglotdeveloper\" \/>\n<meta property=\"article:published_time\" content=\"2018-03-28T14:00:44+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-06-14T01:45:36+00:00\" \/>\n<meta name=\"author\" content=\"Nic Raboy, Developer Advocate, Couchbase\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@nraboy\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Nic Raboy, Developer Advocate, Couchbase\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"16 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/developing-bitcoin-cryptocurrency-application-nodejs-nosql\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/developing-bitcoin-cryptocurrency-application-nodejs-nosql\/\"},\"author\":{\"name\":\"Nic Raboy, Developer Advocate, Couchbase\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/bb545ebe83bb2d12f91095811d0a72e1\"},\"headline\":\"Developing a Bitcoin Cryptocurrency Application with Node.js and NoSQL\",\"datePublished\":\"2018-03-28T14:00:44+00:00\",\"dateModified\":\"2025-06-14T01:45:36+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/developing-bitcoin-cryptocurrency-application-nodejs-nosql\/\"},\"wordCount\":3718,\"commentCount\":3,\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/developing-bitcoin-cryptocurrency-application-nodejs-nosql\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"keywords\":[\"cryptocurrency\",\"NoSQL Database\"],\"articleSection\":[\"Best Practices and Tutorials\",\"Couchbase Server\",\"Node.js\",\"SQL++ \/ N1QL Query\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/developing-bitcoin-cryptocurrency-application-nodejs-nosql\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/developing-bitcoin-cryptocurrency-application-nodejs-nosql\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/developing-bitcoin-cryptocurrency-application-nodejs-nosql\/\",\"name\":\"Bitcoin Cryptocurrency Application with Node.js + NoSQL\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/developing-bitcoin-cryptocurrency-application-nodejs-nosql\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/developing-bitcoin-cryptocurrency-application-nodejs-nosql\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"datePublished\":\"2018-03-28T14:00:44+00:00\",\"dateModified\":\"2025-06-14T01:45:36+00:00\",\"description\":\"Read this Couchbase post to see best practice examples of how to develop Bitcoin Cryptocurrency Applications using Node.js and the NoSQL database.\",\"breadcrumb\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/developing-bitcoin-cryptocurrency-application-nodejs-nosql\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/developing-bitcoin-cryptocurrency-application-nodejs-nosql\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/developing-bitcoin-cryptocurrency-application-nodejs-nosql\/#primaryimage\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"width\":1800,\"height\":630},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/developing-bitcoin-cryptocurrency-application-nodejs-nosql\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.couchbase.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Developing a Bitcoin Cryptocurrency Application with Node.js and NoSQL\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\",\"url\":\"https:\/\/www.couchbase.com\/blog\/\",\"name\":\"The Couchbase Blog\",\"description\":\"Couchbase, the NoSQL Database\",\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.couchbase.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\",\"name\":\"The Couchbase Blog\",\"url\":\"https:\/\/www.couchbase.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png\",\"width\":218,\"height\":34,\"caption\":\"The Couchbase Blog\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/bb545ebe83bb2d12f91095811d0a72e1\",\"name\":\"Nic Raboy, Developer Advocate, Couchbase\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/8863514d8bed0cf6080f23db40e00354\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/bedeb68368d4681aca4c74fe5f697f0c423b80d498ec50fd915ba018b72c101f?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/bedeb68368d4681aca4c74fe5f697f0c423b80d498ec50fd915ba018b72c101f?s=96&d=mm&r=g\",\"caption\":\"Nic Raboy, Developer Advocate, Couchbase\"},\"description\":\"Nic Raboy is an advocate of modern web and mobile development technologies. He has experience in Java, JavaScript, Golang and a variety of frameworks such as Angular, NativeScript, and Apache Cordova. Nic writes about his development experiences related to making web and mobile development easier to understand.\",\"sameAs\":[\"https:\/\/www.thepolyglotdeveloper.com\",\"https:\/\/www.facebook.com\/thepolyglotdeveloper\",\"https:\/\/x.com\/nraboy\"],\"url\":\"https:\/\/www.couchbase.com\/blog\/author\/nic-raboy-2\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Bitcoin Cryptocurrency Application with Node.js + NoSQL","description":"Read this Couchbase post to see best practice examples of how to develop Bitcoin Cryptocurrency Applications using Node.js and the NoSQL database.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.couchbase.com\/blog\/developing-bitcoin-cryptocurrency-application-nodejs-nosql\/","og_locale":"en_US","og_type":"article","og_title":"Developing a Bitcoin Cryptocurrency Application with Node.js and NoSQL","og_description":"Read this Couchbase post to see best practice examples of how to develop Bitcoin Cryptocurrency Applications using Node.js and the NoSQL database.","og_url":"https:\/\/www.couchbase.com\/blog\/developing-bitcoin-cryptocurrency-application-nodejs-nosql\/","og_site_name":"The Couchbase Blog","article_author":"https:\/\/www.facebook.com\/thepolyglotdeveloper","article_published_time":"2018-03-28T14:00:44+00:00","article_modified_time":"2025-06-14T01:45:36+00:00","author":"Nic Raboy, Developer Advocate, Couchbase","twitter_card":"summary_large_image","twitter_creator":"@nraboy","twitter_misc":{"Written by":"Nic Raboy, Developer Advocate, Couchbase","Est. reading time":"16 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.couchbase.com\/blog\/developing-bitcoin-cryptocurrency-application-nodejs-nosql\/#article","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/developing-bitcoin-cryptocurrency-application-nodejs-nosql\/"},"author":{"name":"Nic Raboy, Developer Advocate, Couchbase","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/bb545ebe83bb2d12f91095811d0a72e1"},"headline":"Developing a Bitcoin Cryptocurrency Application with Node.js and NoSQL","datePublished":"2018-03-28T14:00:44+00:00","dateModified":"2025-06-14T01:45:36+00:00","mainEntityOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/developing-bitcoin-cryptocurrency-application-nodejs-nosql\/"},"wordCount":3718,"commentCount":3,"publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/developing-bitcoin-cryptocurrency-application-nodejs-nosql\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","keywords":["cryptocurrency","NoSQL Database"],"articleSection":["Best Practices and Tutorials","Couchbase Server","Node.js","SQL++ \/ N1QL Query"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.couchbase.com\/blog\/developing-bitcoin-cryptocurrency-application-nodejs-nosql\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.couchbase.com\/blog\/developing-bitcoin-cryptocurrency-application-nodejs-nosql\/","url":"https:\/\/www.couchbase.com\/blog\/developing-bitcoin-cryptocurrency-application-nodejs-nosql\/","name":"Bitcoin Cryptocurrency Application with Node.js + NoSQL","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/developing-bitcoin-cryptocurrency-application-nodejs-nosql\/#primaryimage"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/developing-bitcoin-cryptocurrency-application-nodejs-nosql\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","datePublished":"2018-03-28T14:00:44+00:00","dateModified":"2025-06-14T01:45:36+00:00","description":"Read this Couchbase post to see best practice examples of how to develop Bitcoin Cryptocurrency Applications using Node.js and the NoSQL database.","breadcrumb":{"@id":"https:\/\/www.couchbase.com\/blog\/developing-bitcoin-cryptocurrency-application-nodejs-nosql\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.couchbase.com\/blog\/developing-bitcoin-cryptocurrency-application-nodejs-nosql\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.couchbase.com\/blog\/developing-bitcoin-cryptocurrency-application-nodejs-nosql\/#primaryimage","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","width":1800,"height":630},{"@type":"BreadcrumbList","@id":"https:\/\/www.couchbase.com\/blog\/developing-bitcoin-cryptocurrency-application-nodejs-nosql\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.couchbase.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Developing a Bitcoin Cryptocurrency Application with Node.js and NoSQL"}]},{"@type":"WebSite","@id":"https:\/\/www.couchbase.com\/blog\/#website","url":"https:\/\/www.couchbase.com\/blog\/","name":"The Couchbase Blog","description":"Couchbase, the NoSQL Database","publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.couchbase.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.couchbase.com\/blog\/#organization","name":"The Couchbase Blog","url":"https:\/\/www.couchbase.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png","width":218,"height":34,"caption":"The Couchbase Blog"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/bb545ebe83bb2d12f91095811d0a72e1","name":"Nic Raboy, Developer Advocate, Couchbase","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/8863514d8bed0cf6080f23db40e00354","url":"https:\/\/secure.gravatar.com\/avatar\/bedeb68368d4681aca4c74fe5f697f0c423b80d498ec50fd915ba018b72c101f?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/bedeb68368d4681aca4c74fe5f697f0c423b80d498ec50fd915ba018b72c101f?s=96&d=mm&r=g","caption":"Nic Raboy, Developer Advocate, Couchbase"},"description":"Nic Raboy is an advocate of modern web and mobile development technologies. He has experience in Java, JavaScript, Golang and a variety of frameworks such as Angular, NativeScript, and Apache Cordova. Nic writes about his development experiences related to making web and mobile development easier to understand.","sameAs":["https:\/\/www.thepolyglotdeveloper.com","https:\/\/www.facebook.com\/thepolyglotdeveloper","https:\/\/x.com\/nraboy"],"url":"https:\/\/www.couchbase.com\/blog\/author\/nic-raboy-2\/"}]}},"authors":[{"term_id":9032,"user_id":63,"is_guest":0,"slug":"nic-raboy-2","display_name":"Nic Raboy, Developer Advocate, Couchbase","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/bedeb68368d4681aca4c74fe5f697f0c423b80d498ec50fd915ba018b72c101f?s=96&d=mm&r=g","author_category":"","last_name":"Raboy","first_name":"Nic","job_title":"","user_url":"https:\/\/www.thepolyglotdeveloper.com","description":"Nic Raboy is an advocate of modern web and mobile development technologies. He has experience in Java, JavaScript, Golang and a variety of frameworks such as Angular, NativeScript, and Apache Cordova. Nic writes about his development experiences related to making web and mobile development easier to understand."}],"_links":{"self":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts\/4892","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/users\/63"}],"replies":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/comments?post=4892"}],"version-history":[{"count":0,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts\/4892\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/media\/13873"}],"wp:attachment":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/media?parent=4892"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/categories?post=4892"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/tags?post=4892"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/ppma_author?post=4892"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}