├── views
├── qrtest.html
├── index.ejs
├── signup.ejs
├── profile.ejs
├── login.ejs
├── withdraw.ejs
└── deposit.ejs
├── config
├── database.js
├── bchconfig.js
├── ethereum.js
└── passport.js
├── .gitattributes
├── README.md
├── package.json
├── scripts
├── create_bchhdprivatekey.js
└── create_database.js
├── server.js
├── .gitignore
├── service
├── keystorebch.js
├── keystoreeth.js
├── db_service.js
└── bitcoincashrpc.js
└── app
├── routes.js
├── eth_transactions.js
└── bch_transactions.js
/views/qrtest.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/config/database.js:
--------------------------------------------------------------------------------
1 | // config/database.js
2 | module.exports = {
3 | 'connection': {
4 | 'host': 'localhost',
5 | 'user': 'root',
6 | 'password': '@x6iyLxk_2vH'
7 | },
8 | 'database': 'my_schema',
9 | 'users_table': 'users',
10 | 'ethereum_transaction':'eth_transaction',
11 | 'bch_transaction':'bch_transaction',
12 | "eth_withdraw_log":'eth_withdraw_log',
13 | "bch_withdraw_log":'bch_withdraw_log'
14 | };
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
4 | # Custom for Visual Studio
5 | *.cs diff=csharp
6 | *.sln merge=union
7 | *.csproj merge=union
8 | *.vbproj merge=union
9 | *.fsproj merge=union
10 | *.dbproj merge=union
11 |
12 | # Standard to msysgit
13 | *.doc diff=astextplain
14 | *.DOC diff=astextplain
15 | *.docx diff=astextplain
16 | *.DOCX diff=astextplain
17 | *.dot diff=astextplain
18 | *.DOT diff=astextplain
19 | *.pdf diff=astextplain
20 | *.PDF diff=astextplain
21 | *.rtf diff=astextplain
22 | *.RTF diff=astextplain
23 |
--------------------------------------------------------------------------------
/config/bchconfig.js:
--------------------------------------------------------------------------------
1 | // configurations for BCH deposit service
2 | var bitcorecash = require('bitcoincashjs');
3 | Networks = bitcorecash.Networks;
4 | Networks.enableRegtest();
5 |
6 | module.exports = {
7 | 'network': Networks.testnet,
8 | 'host': 'localhost',
9 | 'username': 'admin',
10 | 'password':'password',
11 | 'port': 8332,
12 | 'minStartBlock': 0, // When scan the block, the starting point
13 | 'minConfirmation':20,
14 | "coinsPerBCH":1000,
15 | 'withdrawSourceHDPath': ['m/0\'/1\'/0\''],//The address associate with this HDpath is mvpVLHH3UmACHJ1JV6tcneZFB5pqpvVs9j.
16 | 'minTxFee':0.001
17 | };
--------------------------------------------------------------------------------
/config/ethereum.js:
--------------------------------------------------------------------------------
1 | // configurations for Ethereum deposit service
2 | module.exports = {
3 | 'host': 'http://localhost:8545', //Ip address and port of the ethereum node service
4 | 'minMinedRequirement' : 20, //a transaction will be deposited only after N mined blocks.
5 | 'minStartBlock': 44984, // When scan the block, the starting point
6 | 'WeisPerCoin': 1000000000000000,
7 | 'ethDepositCheckInterval': 10000, // In milliseconds
8 | 'keyStorePassword':'0.8487677677962937',
9 | 'withdrawSourceAccount': '0xafdf17bcb4b9a99ab2fdf30b6f0d62b59ea42bdd'
10 | //withdrawsouce in Jeremy's regtest network is: mvpVLHH3UmACHJ1JV6tcneZFB5pqpvVs9j
11 | };
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Complete Guide to Coin and Cryptocurrecny Exchange Demo
2 |
3 | This is an onging project.
4 |
5 | Current version database is ported to MySQL
6 |
7 | We will be using Passport to authenticate users locally,
8 |
9 | ## Instructions
10 |
11 | If you would like to download the code and try it for yourself:
12 |
13 | 1. Clone the repo: `git clone git@github.com:JeremywangCN/coin-cryptocurrency-exchange.git`
14 | 1. Install packages: `npm install`
15 | 1. Edit the database configuration: `config/database.js`
16 | 1. Edit the ethereum configuration: 'config/ethereum.js'
17 | 1. Create the database schema: `node scripts/create_database.js`
18 | 1. Create a BCH HDkey for demo: `node scripts/create_bchhdprivatekey.js`
19 | 1. Launch: `node server.js`
20 | 1. Visit in your browser at: `http://localhost:8080`
21 |
22 | Licence: 1
23 |
--------------------------------------------------------------------------------
/views/index.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Coins and Cryptocurrency Exchange
6 |
7 |
8 |
11 |
12 |
13 |
14 |
15 |
Coins and Cryptocurrency Exchange
16 |
17 |
Login or Register with:
18 |
19 |
Local Login
20 |
Local Signup
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "node-authentication",
3 | "main": "server.js",
4 | "scripts": {
5 | "start": "node ./server"
6 | },
7 | "dependencies": {
8 | "axios": "^0.18.0",
9 | "bchaddrjs": "^0.2.1",
10 | "bcrypt-nodejs": "0.0.3",
11 | "npm-address-translator": "^1.0.4",
12 | "qr-image": "^3.2.0",
13 | "bitcoincashjs": "^0.1.10",
14 | "bitcore-lib": "^0.15.0",
15 | "body-parser": "^1.13.1",
16 | "connect-flash": "^0.1.1",
17 | "cookie-parser": "^1.3.5",
18 | "ejs": "^2.3.2",
19 | "eth-lightwallet": "^3.0.1",
20 | "express": "^4.13.0",
21 | "express-session": "^1.11.3",
22 | "hooked-web3-provider": "^1.0.0",
23 | "morgan": "^1.6.0",
24 | "mysql": "^2.7.0",
25 | "passport": "^0.2.2",
26 | "passport-local": "^1.0.0",
27 | "qrcode": "^1.2.0",
28 | "web3": "^0.16.0"
29 | },
30 | "repository": {
31 | "type": "git",
32 | "url": "git://github.com/JeremywangCN/coin-cryptocurrency-exchange.git"
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/scripts/create_bchhdprivatekey.js:
--------------------------------------------------------------------------------
1 | // This script creates a BIP 32 HD Private Key and save as a file to the server.
2 |
3 | var bitcorecash = require('bitcoincashjs');
4 | var HDPrivateKey = bitcorecash.HDPrivateKey;
5 |
6 | var hdPrivateKey = new HDPrivateKey();
7 | var hdPublicKey = hdPrivateKey.hdPublicKey;
8 | var publickeyString = hdPublicKey.toString();
9 | var privatekeyString = hdPrivateKey.toString();
10 |
11 | const fs = require('fs');
12 | fs.writeFile('./keystorebchprivate.txt', privatekeyString, function(err){
13 | // throws an error, you could also catch it here
14 | if (err) throw err;
15 |
16 | // success case, the file was saved
17 | console.log('BCH Private key '+ hdPrivateKey.toString()+'was saved to keystorebch.txt!');
18 |
19 | });
20 | fs.writeFile('./keystorebchpublic.txt', publickeyString, function(err){
21 | // throws an error, you could also catch it here
22 | if (err) throw err;
23 |
24 | // success case, the file was saved
25 | console.log('BCH Public key '+ publickeyString+'was saved to keystorebch.txt!');
26 |
27 | });
28 |
29 |
--------------------------------------------------------------------------------
/views/signup.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Node Authentication
6 |
7 |
8 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
Signup
18 |
19 |
20 | <% if (message.length > 0) { %>
21 |
<%= message %>
22 | <% } %>
23 |
24 |
25 |
37 |
38 |
39 |
40 |
Already have an account? Login
41 |
Or go home.
42 |
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/views/profile.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Coins and Cryptocurrency Exchange
6 |
7 |
8 |
9 |
12 |
13 |
14 |
15 |
16 |
20 |
21 |
22 |
23 |
24 |
<%= user.username %>
25 |
26 |
27 | ID: <%= user.id %>
28 | Coin: <%= user.coin %>
29 | Ethereum (GWei): <%= user.eth_value %>
30 | Bicoin Cash(Satoshi): <%= user.bch_value %>
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
41 |
44 |
47 |
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/views/login.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Node Authentication
6 |
7 |
8 |
11 |
12 |
13 |
14 |
15 |
Login
16 |
17 |
18 | <% if (message.length > 0) { %>
19 |
<%= message %>
20 | <% } %>
21 |
22 |
23 |
39 |
40 |
41 |
42 |
Need an account? Signup
43 |
Or go home.
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/server.js:
--------------------------------------------------------------------------------
1 | // server.js
2 |
3 | // set up ======================================================================
4 | // get all the tools we need
5 | var express = require('express');
6 | var session = require('express-session');
7 | var cookieParser = require('cookie-parser');
8 | var bodyParser = require('body-parser');
9 | var morgan = require('morgan');
10 | var app = express();
11 | var port = process.env.PORT || 8080;
12 | var passport = require('passport');
13 | var flash = require('connect-flash');
14 | var ethConfig = require('./config/ethereum');
15 |
16 | app.use(express.static('public'));
17 | // Initiate Ethereum Keystore and Eth Web3 instance. Start to check node for new unrecorded transactions.
18 | var keystore = require('./service/keystoreeth');
19 | var Eth = require('./app/eth_transactions');
20 | keystore.init(function (ifSucceed,ksi) {
21 | if(ifSucceed){
22 | Eth.init();
23 | }
24 | });
25 |
26 | // Init BCH HD Public key and wallet accounts
27 | var BCH = require('./app/bch_transactions');
28 | var bchKeyUtils= require('./service/keystorebch');
29 | bchKeyUtils.init(function (err) {
30 | if(err);
31 | else
32 | BCH.updateUnspentTx();
33 | });
34 |
35 | BCH.initRecipientAddresses();
36 |
37 | setInterval(function () {
38 | Eth.checkBlockChainForMinedTxService();
39 | BCH.checkBlockChainForDepositTx();
40 | BCH.updateSubmittedWithdrawTxs();
41 | },ethConfig.ethDepositCheckInterval);
42 |
43 | // configuration ===============================================================
44 | // connect to our database
45 |
46 | require('./config/passport')(passport); // pass passport for configuration
47 |
48 |
49 | // set up our express application
50 | app.use(morgan('dev')); // log every request to the console
51 | app.use(cookieParser()); // read cookies (needed for auth)
52 | app.use(bodyParser.urlencoded({
53 | extended: true
54 | }));
55 | app.use(bodyParser.json());
56 |
57 | app.set('view engine', 'ejs'); // set up ejs for templating
58 |
59 | // required for passport
60 | app.use(session({
61 | secret: 'vidyapathaisalwaysrunning',
62 | resave: true,
63 | saveUninitialized: true
64 | } )); // session secret
65 | app.use(passport.initialize());
66 | app.use(passport.session()); // persistent login sessions
67 | app.use(flash()); // use connect-flash for flash messages stored in session
68 |
69 |
70 |
71 | // routes ======================================================================
72 | require('./app/routes.js')(app, passport); // load our routes and pass in our app and fully configured passport
73 |
74 | // launch ======================================================================
75 | app.listen(port);
76 | console.log('The magic happens on port ' + port);
--------------------------------------------------------------------------------
/scripts/create_database.js:
--------------------------------------------------------------------------------
1 |
2 | var mysql = require('mysql');
3 | var dbconfig = require('../config/database');
4 |
5 | var connection = mysql.createConnection(dbconfig.connection);
6 |
7 | connection.query('CREATE DATABASE ' + dbconfig.database);
8 |
9 | connection.query('\
10 | CREATE TABLE `' + dbconfig.database + '`.`' + dbconfig.users_table + '` ( \
11 | `id` INT UNSIGNED NOT NULL AUTO_INCREMENT, \
12 | `username` VARCHAR(20) NOT NULL, \
13 | `coin` INT DEFAULT 0, \
14 | `eth_address` VARCHAR(50),\
15 | `bch_address` VARCHAR(50),\
16 | `password` CHAR(60) NOT NULL, \
17 | PRIMARY KEY (`id`), \
18 | UNIQUE INDEX `id_UNIQUE` (`id` ASC), \
19 | UNIQUE INDEX `username_UNIQUE` (`username` ASC) \
20 | )');
21 |
22 |
23 | connection.query('\
24 | CREATE TABLE `' + dbconfig.database + '`.`' + dbconfig.ethereum_transaction + '` ( \
25 | `txhash` VARCHAR(100), \
26 | `to_address` VARCHAR(50) NOT NULL, \
27 | `to_user_id` VARCHAR(50) NOT NULL, \
28 | `value` BIGINT DEFAULT 0, \
29 | `blocknumber` INT,\
30 | `timestamp` TIMESTAMP, \
31 | PRIMARY KEY (`txhash`), \
32 | INDEX `to_user_id` (`to_user_id` ASC) \
33 | )');
34 |
35 |
36 | connection.query("CREATE TABLE `" + dbconfig.database + '`.`' + dbconfig.eth_withdraw_log + "` ( \
37 | `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,\
38 | `tx_status` INT DEFAULT 0 ,\
39 | `tx_hash` VARCHAR(100), \
40 | `from_address` VARCHAR(50) NOT NULL, \
41 | `to_address` VARCHAR(50) NOT NULL, \
42 | `to_user_id` VARCHAR(50) NOT NULL, \
43 | `eth_value` BIGINT DEFAULT 0, \
44 | `coin_value` INT DEFAULT 0, \
45 | `block_number` INT,\
46 | `timestamp` TIMESTAMP, \
47 | PRIMARY KEY (`id`))");
48 |
49 |
50 | connection.query('\
51 | CREATE TABLE `' + dbconfig.database + '`.`' + dbconfig.bch_transaction + '` ( \
52 | `txhash` VARCHAR(100), \
53 | `to_address` VARCHAR(50) NOT NULL, \
54 | `to_user_id` VARCHAR(50) NOT NULL, \
55 | `value` BIGINT DEFAULT 0, \
56 | `blocknumber` INT,\
57 | `timestamp` TIMESTAMP, \
58 | PRIMARY KEY (`txhash`), \
59 | INDEX `to_user_id` (`to_user_id` ASC) \
60 | )');
61 |
62 |
63 | connection.query("CREATE TABLE `" + dbconfig.database + '`.`' + dbconfig.bch_withdraw_log + "` ( \
64 | `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,\
65 | `tx_status` INT DEFAULT 0 ,\
66 | `tx_hash` VARCHAR(100), \
67 | `from_address` VARCHAR(50) NOT NULL, \
68 | `to_address` VARCHAR(50) NOT NULL, \
69 | `to_user_id` VARCHAR(50) NOT NULL, \
70 | `bch_value` BIGINT DEFAULT 0, \
71 | `coin_value` INT DEFAULT 0, \
72 | `block_number` INT,\
73 | `timestamp` TIMESTAMP, \
74 | PRIMARY KEY (`id`))");
75 |
76 | console.log('Success: Database Created!');
77 |
78 | connection.end();
79 |
--------------------------------------------------------------------------------
/views/withdraw.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Coins and Cryptocurrency Exchange
7 |
8 |
9 |
10 |
11 |
14 |
15 |
16 |
17 |
18 |
24 |
25 |
26 |
27 |
28 |
29 |
30 | ID: <%= user.id %>
31 | Username: <%= user.username %>
32 | Coin: <%= user.coin %>
33 | Ethereum: <%= user.eth_amount %>
34 | Bitcoin Cash: <%= user.bch_amount %>
35 |
36 |
37 |
38 |
45 |
46 |
47 |
48 |
49 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
115 |
116 |
117 |
118 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | #################
2 | ## Eclipse
3 | #################
4 |
5 | *.pydevproject
6 | .project
7 | .metadata
8 | bin/
9 | tmp/
10 | *.tmp
11 | *.bak
12 | *.swp
13 | *~.nib
14 | local.properties
15 | .classpath
16 | .settings/
17 | .loadpath
18 |
19 | # External tool builders
20 | .externalToolBuilders/
21 |
22 | # Locally stored "Eclipse launch configurations"
23 | *.launch
24 |
25 | # CDT-specific
26 | .cproject
27 |
28 | # PDT-specific
29 | .buildpath
30 |
31 |
32 | #################
33 | ## Visual Studio
34 | #################
35 |
36 | ## Ignore Visual Studio temporary files, build results, and
37 | ## files generated by popular Visual Studio add-ons.
38 |
39 | # User-specific files
40 | *.suo
41 | *.user
42 | *.sln.docstates
43 |
44 | # Build results
45 |
46 | [Dd]ebug/
47 | [Rr]elease/
48 | x64/
49 | build/
50 | [Bb]in/
51 | [Oo]bj/
52 |
53 | # MSTest test Results
54 | [Tt]est[Rr]esult*/
55 | [Bb]uild[Ll]og.*
56 |
57 | *_i.c
58 | *_p.c
59 | *.ilk
60 | *.meta
61 | *.obj
62 | *.pch
63 | *.pdb
64 | *.pgc
65 | *.pgd
66 | *.rsp
67 | *.sbr
68 | *.tlb
69 | *.tli
70 | *.tlh
71 | *.tmp
72 | *.tmp_proj
73 | *.log
74 | *.vspscc
75 | *.vssscc
76 | .builds
77 | *.pidb
78 | *.log
79 | *.scc
80 |
81 | # Visual C++ cache files
82 | ipch/
83 | *.aps
84 | *.ncb
85 | *.opensdf
86 | *.sdf
87 | *.cachefile
88 |
89 | # Visual Studio profiler
90 | *.psess
91 | *.vsp
92 | *.vspx
93 |
94 | # Guidance Automation Toolkit
95 | *.gpState
96 |
97 | # ReSharper is a .NET coding add-in
98 | _ReSharper*/
99 | *.[Rr]e[Ss]harper
100 |
101 | # TeamCity is a build add-in
102 | _TeamCity*
103 |
104 | # DotCover is a Code Coverage Tool
105 | *.dotCover
106 |
107 | # NCrunch
108 | *.ncrunch*
109 | .*crunch*.local.xml
110 |
111 | # Installshield output folder
112 | [Ee]xpress/
113 |
114 | # DocProject is a documentation generator add-in
115 | DocProject/buildhelp/
116 | DocProject/Help/*.HxT
117 | DocProject/Help/*.HxC
118 | DocProject/Help/*.hhc
119 | DocProject/Help/*.hhk
120 | DocProject/Help/*.hhp
121 | DocProject/Help/Html2
122 | DocProject/Help/html
123 |
124 | # Click-Once directory
125 | publish/
126 |
127 | # Publish Web Output
128 | *.Publish.xml
129 | *.pubxml
130 |
131 | # NuGet Packages Directory
132 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line
133 | #packages/
134 |
135 | # Windows Azure Build Output
136 | csx
137 | *.build.csdef
138 |
139 | # Windows Store app package directory
140 | AppPackages/
141 |
142 | # Others
143 | sql/
144 | *.Cache
145 | ClientBin/
146 | [Ss]tyle[Cc]op.*
147 | ~$*
148 | *~
149 | *.dbmdl
150 | *.[Pp]ublish.xml
151 | *.pfx
152 | *.publishsettings
153 |
154 | # RIA/Silverlight projects
155 | Generated_Code/
156 |
157 | # Backup & report files from converting an old project file to a newer
158 | # Visual Studio version. Backup files are not needed, because we have git ;-)
159 | _UpgradeReport_Files/
160 | Backup*/
161 | UpgradeLog*.XML
162 | UpgradeLog*.htm
163 |
164 | # SQL Server files
165 | App_Data/*.mdf
166 | App_Data/*.ldf
167 |
168 | #############
169 | ## Windows detritus
170 | #############
171 |
172 | # Windows image file caches
173 | Thumbs.db
174 | ehthumbs.db
175 |
176 | # Folder config file
177 | Desktop.ini
178 |
179 | # Recycle Bin used on file shares
180 | $RECYCLE.BIN/
181 |
182 | # Mac crap
183 | .DS_Store
184 |
185 |
186 | #############
187 | ## Python
188 | #############
189 |
190 | *.py[co]
191 |
192 | # Packages
193 | *.egg
194 | *.egg-info
195 | dist/
196 | build/
197 | eggs/
198 | parts/
199 | var/
200 | sdist/
201 | develop-eggs/
202 | .installed.cfg
203 |
204 | # Installer logs
205 | pip-log.txt
206 |
207 | # Unit test / coverage reports
208 | .coverage
209 | .tox
210 |
211 | #Translations
212 | *.mo
213 |
214 | #Mr Developer
215 | .mr.developer.cfg
216 |
217 | ######
218 | # Idea
219 | ######
220 | .idea/
221 |
222 | ##############
223 | # node modules
224 | ##############
225 | node_modules/
226 |
--------------------------------------------------------------------------------
/service/keystorebch.js:
--------------------------------------------------------------------------------
1 | var BCHConfig = require('./../config/bchconfig')//Bitcoin Cash Configurations
2 |
3 | const fs = require('fs');//File system
4 |
5 | var DBService = require('./../service/db_service');//Mysql Database Services
6 |
7 | // RPC connection to the bitcoin cash node
8 | var BCHRpc = require("./../service/bitcoincashrpc");
9 | var BCHRpcConnect = new BCHRpc(BCHConfig.host, BCHConfig.username, BCHConfig.password, BCHConfig.port, 3000);
10 |
11 | //Nodejs bitcoin cash modules
12 | var BCHCashCore = require("bitcoincashjs");
13 | var HDPublicKey = BCHCashCore.HDPublicKey;
14 | var HDPrivateKey = BCHCashCore.HDPrivateKey;
15 | var Address = BCHCashCore.Address;
16 |
17 |
18 | var hdPublicKey;
19 | var hdPrivateKey;
20 |
21 | // withdrawSource array includes each withdraw source account's private key and address. The address is Base58check format.
22 | var withdrawSource=[];
23 |
24 | function initBCHPublicKey(callback) {
25 | fs.readFile('keystorebchpublic.txt', 'utf8', function(err, data) {
26 | if (err) {
27 | console.log(err);
28 |
29 | }
30 | else{
31 | hdPublicKey = new HDPublicKey(data);
32 | return callback;
33 | }
34 | }
35 |
36 | );
37 |
38 | };
39 |
40 | function initBCHPrivateKey(callback) {
41 | fs.readFile('keystorebchprivate.txt', 'utf8', function(err, data) {
42 | if (err) {
43 | return callback(err);
44 |
45 | }
46 | else{
47 | hdPrivateKey = new HDPrivateKey(data);
48 | return callback(null,hdPrivateKey);
49 | }
50 | }
51 |
52 | );
53 |
54 | };
55 |
56 |
57 | //Add addresses in withdrawSource array into bitcoin cash node with account "withdraw source". Make it possisble to check unspent transactions from nodejs.
58 | function addWithdrawSourceAddrToWallet(callback) {
59 |
60 | if(withdrawSource.length===0)
61 | setWithdrawSource();
62 | var BCC = require("./../service/bitcoincashrpc");
63 | var BCHRrcClient = new BCC(BCHConfig.host, BCHConfig.username, BCHConfig.password, BCHConfig.port, 3000);//Bitcoin Cash RPC Connection
64 | var p;
65 | for(var i=0;i{
69 | return callback(null, i);
70 | });
71 | };
72 |
73 |
74 | //set up withdrawSource Array
75 | function setWithdrawSource() {
76 | var hdPath = BCHConfig.withdrawSourceHDPath;
77 | for (var i=0; i< hdPath.length; i++){
78 | var derivedPrivateKey = hdPrivateKey.derive(hdPath[i]);
79 | var derivedAddressBase58Check = new Address(derivedPrivateKey.publicKey, BCHConfig.network,'pubkeyhash');
80 | withdrawSource.push({derivedPrivateKey:derivedPrivateKey,address: derivedAddressBase58Check.toString()});
81 | }
82 | };
83 |
84 | function updateUserToAddress(username) {
85 |
86 | var derivedByArgument = hdPublicKey.derive("m/0/0");
87 | DBService.getUserByUsername(username,function (err, users) {
88 | if(err)
89 | {
90 | console.log(err);
91 | return;
92 | }else{
93 | var userid = users[0].id;
94 | var derivedAddressBase58Check = new Address(derivedByArgument.derive(userid).publicKey, BCHConfig.network,'pubkeyhash');
95 | var BASE58CHECK = BCHCashCore.encoding.Base58Check;
96 | var derivedAddressHex ="0x"+BASE58CHECK.decode(derivedAddressBase58Check.toString()).toString('hex').slice(2);
97 |
98 | var updateList ={bch_address:derivedAddressHex};
99 | DBService.updateUsersById(userid,updateList,function (err2,data2) {
100 | if(err2){
101 | console.log(err);
102 | return;
103 | }
104 | else{
105 | console.log("The new username "+ username+", BCH Hex address is "+ derivedAddressHex+". BCH Base58check address is "+derivedAddressBase58Check.toString());
106 | var p = Promise.resolve(BCHRpcConnect.importaddress(derivedAddressBase58Check.toString(),username,false));
107 | p.then(info=>{
108 | console.log("Import the address to the node wallet!")
109 | });
110 | }
111 | });
112 | }
113 | });
114 | };
115 |
116 | module.exports ={
117 | init:function(callback){
118 | initBCHPublicKey();
119 | initBCHPrivateKey(function (err, privateKey) {
120 | if(err)
121 | return (err);
122 | else {
123 | setWithdrawSource();
124 | addWithdrawSourceAddrToWallet(function (err, amount) {
125 | if (err)
126 | return callback(err);
127 | else{
128 | return callback(null);
129 | }
130 | });
131 | }
132 |
133 | });
134 | },
135 | updateUserToAddress:updateUserToAddress,
136 | withdrawSource:withdrawSource,
137 | hdPrivateKey:hdPrivateKey,
138 | setWithdrawSource:setWithdrawSource,
139 | }
140 |
--------------------------------------------------------------------------------
/service/keystoreeth.js:
--------------------------------------------------------------------------------
1 | var dbconfig = require('./../config/database');
2 | var ethconfig = require('./../config/ethereum');
3 | const DBSERVICE = require('./../service/db_service');
4 | const fs = require('fs');
5 |
6 | var ks ;
7 |
8 | function setksintance(ksi) {
9 | ks = ksi;
10 | console.log('The key store instance is good...'+ks);
11 | };
12 |
13 | function getKeyStore() {
14 | return ks;
15 | };
16 |
17 | function initKeystore(callback) {
18 | const fs = require('fs');
19 | ks = fs.readFile('keystore.txt', 'utf8', function(err, data) {
20 | if (err) {
21 | console.log(err);
22 | var lightwallet = require('eth-lightwallet');
23 | var seed = lightwallet.keystore.generateRandomSeed();
24 | var password = Math.random().toString();
25 | console.log('The seed is '+seed);
26 | console.log('The password is '+password);
27 |
28 | lightwallet.keystore.createVault({
29 | password: password,
30 | seedPhrase: seed,
31 | hdPathString: "m/0'/0'/0'"
32 | }, function (err, ks) {
33 |
34 | if(err){
35 | console.log(err);
36 | return callback(false);
37 | }else{
38 |
39 | ks.keyFromPassword(password, function (err, pwDerivedKey) {
40 | if(err)
41 | {
42 | console.log('Error keystore instance from password!');
43 | return callback(false);
44 | }
45 | else
46 | {
47 | var serialized = ks.serialize();
48 |
49 | fs.writeFile('keystore.txt', serialized, function(err){
50 | // throws an error, you could also catch it here
51 | if (err) throw err;
52 |
53 | // success case, the file was saved
54 | console.log('Keystore saved!');
55 | return callback(true,ks);
56 |
57 |
58 | });
59 |
60 | }
61 |
62 | });
63 |
64 | }
65 |
66 | });
67 | }
68 | else{
69 | var deserialize = data;
70 | var lightwallet = require('eth-lightwallet');
71 | var keystoreinstance = lightwallet.keystore.deserialize(deserialize);
72 | console.log("Load keystore from local file.");
73 |
74 | keystoreinstance.keyFromPassword(ethconfig.keyStorePassword, function (err, pwDerivedKey) {
75 | if(err)
76 | {
77 | console.log(err);
78 | }else{
79 | keystoreinstance.passwordProvider = function (callback) {
80 | callback(null, ethconfig.keyStorePassword);
81 | };
82 | }
83 | });
84 | return callback(true,keystoreinstance);
85 |
86 | }
87 | }
88 |
89 | );
90 |
91 | };
92 |
93 | function updateUserToAddress(username) {
94 |
95 | ks.keyFromPassword(ethconfig.keyStorePassword, function (err, pwDerivedKey) {
96 | if(err)
97 | {
98 | return console(err);
99 | }
100 | else
101 | {
102 | DBSERVICE.getUserByUsername(username,function (err,data) {
103 | if(err) {
104 | console.log(err);
105 | return;
106 | }
107 | if(ks.getAddresses().length
2 |
3 |
4 |
5 |
6 | Coins and Cryptocurrency Exchange
7 |
8 |
9 |
10 |
13 |
14 |
15 |
16 |
17 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
Ethereum
35 |
Address: <%= user.eth_address %>
36 |
Balance (GWeis): <%= user.eth_amount %>
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
Bitcoin Cash
49 |
Address: <%= user.bch_address %>
50 |
Balance (Satoshi): <%= user.bch_amount %>
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
192 |
193 |
194 |
195 |
196 |
197 |
--------------------------------------------------------------------------------
/app/routes.js:
--------------------------------------------------------------------------------
1 | // app/routes.js
2 | module.exports = function(app, passport) {
3 | app.use(function(req, res, next){
4 |
5 | next();
6 | });
7 |
8 | // =====================================
9 | // HOME PAGE (with login links) ========
10 | // =====================================
11 | app.get('/', function(req, res) {
12 | res.render('index.ejs'); // load the index.ejs file
13 | });
14 |
15 | // =====================================
16 | // LOGIN ===============================
17 | // =====================================
18 | // show the login form
19 | app.get('/login', function(req, res) {
20 |
21 | // render the page and pass in any flash data if it exists
22 | res.render('login.ejs', { message: req.flash('loginMessage') });
23 | });
24 |
25 | // process the login form
26 | app.post('/login', passport.authenticate('local-login', {
27 | successRedirect : '/profile', // redirect to the secure profile section
28 | failureRedirect : '/login', // redirect back to the signup page if there is an error
29 | failureFlash : true // allow flash messages
30 | }),
31 | function(req, res) {
32 | console.log("hello");
33 |
34 | if (req.body.remember) {
35 | req.session.cookie.maxAge = 1000 * 60 * 3;
36 | } else {
37 | req.session.cookie.expires = false;
38 | }
39 | res.redirect('/');
40 | });
41 |
42 | // =====================================
43 | // SIGNUP ==============================
44 | // =====================================
45 | // show the signup form
46 | app.get('/signup', function(req, res) {
47 | // render the page and pass in any flash data if it exists
48 | res.render('signup.ejs', { message: req.flash('signupMessage') });
49 | });
50 |
51 | // process the signup form
52 | app.post('/signup', passport.authenticate('local-signup', {
53 | successRedirect : '/profile', // redirect to the secure profile section
54 | failureRedirect : '/signup', // redirect back to the signup page if there is an error
55 | failureFlash : true // allow flash messages
56 | }));
57 |
58 | // =====================================
59 | // PROFILE SECTION =========================
60 | // =====================================
61 | // we will want this protected so you have to be logged in to visit
62 | // we will use route middleware to verify this (the isLoggedIn function)
63 | app.get('/profile', isLoggedIn, function(req, res) {
64 | console.log(req.session.id)
65 | let user = req.user;
66 | let DBService = require('./../service/db_service');
67 | let ETHTransaction = require('./eth_transactions');
68 | let BCHTransaction = require('./bch_transactions');
69 |
70 | DBService.getUserByUsername(user.username,function (err,data) {
71 | if(err) {
72 | console.log(err);
73 | user.eth_value = -1;
74 | }
75 | else
76 | ETHTransaction.getETHBalanceByUserId(data[0].id,function (err,ethData) {
77 | if(!err){
78 | user.eth_value = ethData;
79 | BCHTransaction.getBCHBalanceByUserId(this.userId,function (err,bchData) {
80 | if(!err){
81 | user.bch_value = bchData;
82 | }
83 | res.render('profile.ejs', {user : user});
84 | })
85 | }
86 | else
87 | res.render('profile.ejs', {
88 | user : user // get the user out of session and pass to template
89 | });
90 | }.bind({userId:data[0].id}))
91 | })
92 | });
93 |
94 | // =====================================
95 | // LOGOUT ==============================
96 | // =====================================
97 | app.get('/logout', function(req, res) {
98 | req.logout();
99 | res.redirect('/');
100 | });
101 |
102 |
103 | //Leo 绘制eth转账二维码界面
104 | app.get('/deposit', isLoggedIn,function(req, res) {
105 | // render the page and pass in any flash data if it exist
106 | var QRCode = require('qrcode');
107 | const DBService =require('./../service/db_service');
108 | let ETHTransaction = require('./eth_transactions');
109 | let BCHTransaction = require('./bch_transactions');
110 | DBService.getUserByUsername(req.user.username,function (err, rows) {
111 | if (err){
112 | console.log(err);
113 | // return done(false);
114 | }
115 | if (rows.length==0){
116 | console.log("Cannot find this user name in DB!");
117 | // return done(false);
118 | }
119 | QRCode.toDataURL(rows[0].eth_address, function (err, url) {
120 | let eth_url = url;
121 | QRCode.toDataURL(this.row.bch_address,function (err1,url1) {
122 | let bch_url = url1;
123 | let user = this.req.user;
124 | user.eth_address = this.row.eth_address;
125 | user.bch_address = this.row.bch_address;
126 | ETHTransaction.getETHBalanceByUserId(this.row.id,function (err,ethData) {
127 | user.eth_amount=ethData;
128 | BCHTransaction.getBCHBalanceByUserId(this.row.id,function (err,bchData) {
129 | user.bch_amount=bchData;
130 | this.res.render('deposit.ejs', { user: user, imgUrlEth: eth_url,imgUrlBCH:bch_url});
131 | }.bind({row:this.row,res:res,req:req,user:user}))
132 | }.bind({row:this.row,res:res,req:req,user:user}));
133 | }.bind({row: rows[0],res:res,req:req}))
134 | }.bind({row: rows[0],res:res,req:req}))
135 | });
136 | });
137 |
138 | //Leo eth转出接口
139 | app.post('/ethwithdraw',isLoggedIn,function(req, res){
140 | let Eth = require('./eth_transactions');
141 | Eth.withdrawETH(req.user.username,req.body.ethAddress,req.body.ethAmount,function (err,data) {
142 | if(err) console.log(err);
143 | else{
144 | // res.render('withdraw.ejs', { user: req.user,msg: "Coin was withdrawn as Ethereum. The transaction ID is "+data});
145 | res.redirect('/withdraw?eth_tx='+data,);
146 |
147 | }
148 | });
149 |
150 | });
151 | app.post('/bchwithdraw',isLoggedIn,function(req, res){
152 | console.log(req.user);
153 | let Bch = require('./bch_transactions');
154 | Bch.withdrawBCH(req.user.username,req.body.bchAddress,req.body.bchAmount,function (err,data) {
155 | if(err) console.log(err);
156 | else{
157 | // res.render('withdraw.ejs', { user: req.user,msg: "Coin was withdrawn as Bitcoin Cash. The transaction ID is "+data});
158 | res.redirect('/withdraw?bch_tx='+data,);
159 | }
160 | });
161 |
162 | });
163 | app.get('/withdraw',isLoggedIn,function(req, res){
164 | const DBService =require('./../service/db_service');
165 | let ETHTransaction = require('./eth_transactions');
166 | let BCHTransaction = require('./bch_transactions');
167 | console.log(req.body);
168 | ETHTransaction.getETHBalanceByUserId(req.user.id,function (err,ethData) {
169 | this.req.user.eth_amount=ethData;
170 | BCHTransaction.getBCHBalanceByUserId(this.req.user.id,function (err,bchData) {
171 | this.req.user.bch_amount=bchData;
172 | res.render('withdraw.ejs', { user: req.user});
173 | }.bind({res:res,req:req}))
174 | }.bind({res:res,req:req}));
175 |
176 | });
177 |
178 | app.get('/ajaxdeposit',isLoggedIn,function (req,res) {
179 | const ETHTX= require('./eth_transactions');
180 | ETHTX.getUnconfirmedDepositTxByUsername(req.user.username,function (err,data) {
181 | if(err) console.log(err);
182 | res.send(data);
183 | })
184 | });
185 |
186 | app.get('/ajaxbchdeposit',isLoggedIn,function (req,res) {
187 | const BCHTX= require('./bch_transactions');
188 | BCHTX.getUnconfirmedDepositTxByUsername(req.user.username,function (err,data) {
189 | if(err) console.log(err);
190 | res.send(data);
191 | })
192 | });
193 |
194 | app.get('/ajaxethbalance',isLoggedIn,function (req,res) {
195 | const ETHTX= require('./eth_transactions');
196 | ETHTX.getETHBalanceByUsername(req.user.username,function (err,data) {
197 | if(err) console.log(err);
198 | res.send({'ethBalance':data});
199 | })
200 | });
201 |
202 | app.get('/ajaxbchbalance',isLoggedIn,function (req,res) {
203 | const BCHTX= require('./bch_transactions');
204 | BCHTX.getBCHBalanceByUserId(req.user.id,function (err,data) {
205 | if(err) console.log(err);
206 | res.send({'bchBalance':data});
207 | })
208 | });
209 |
210 | app.get('/ajaxcoinbalance',isLoggedIn,function (req,res) {
211 | const DBService = require('./../service/db_service');
212 | DBService.getUserByUsername(req.user.username,function (err,data) {
213 | if(err) console.log(err);
214 | res.send({'coinBalance':data[0].coin});
215 | })
216 | });
217 |
218 | app.get('/ajaxethtx',isLoggedIn,function (req,res) {
219 | const ETHTX= require('./eth_transactions');
220 | let returnTx=ETHTX.getETHTransactionByTxHash(req.query.eth_tx);
221 | res.send(returnTx);
222 | });
223 |
224 | app.get('/ajaxbchtx',isLoggedIn,function (req,res) {
225 | const BCHTX= require('./bch_transactions');
226 | BCHTX.getBCHTransactionByTxHash(req.query.bch_tx,function (err,data) {
227 | res.send(data);
228 | });
229 | });
230 | };
231 |
232 | // route middleware to make sure
233 | function isLoggedIn(req, res, next) {
234 |
235 | // if user is authenticated in the session, carry on
236 | if (req.isAuthenticated())
237 | return next();
238 |
239 | // if they aren't redirect them to the home page
240 | res.redirect('/');
241 | }
242 |
--------------------------------------------------------------------------------
/app/eth_transactions.js:
--------------------------------------------------------------------------------
1 | //Import modules
2 | const Web3 = require("web3");
3 | const KS = require('./../service/keystoreeth');
4 | const HookedWeb3Provider = require("hooked-web3-provider");
5 | const ETHCONFIG = require('./../config/ethereum');
6 | const DBSERVICE = require('./../service/db_service');
7 |
8 |
9 | // System variables
10 | var web3;
11 | var latestCheckedBlock;
12 | var recipientAddresses;
13 | var unconfirmedDepositTxs;
14 |
15 | const withdrawLogStatus ={
16 | CREATED: 0,
17 | SUBMITTED: 2,
18 | MINED: 4
19 | };
20 |
21 | function initWeb3() {
22 | let ks = KS.getKeyStore();
23 | let provider = new HookedWeb3Provider({
24 | host: ETHCONFIG.host,
25 | transaction_signer: ks
26 | });
27 | web3 = new Web3(provider);
28 | console.log("The web3 instance was initiated successfully. It is "+web3);
29 | }
30 |
31 | function initLatestCheckedBlock() {
32 | DBSERVICE.getLatestETHCheckedBlock(function (err,data) {
33 | if(err) latestCheckedBlock = ETHCONFIG.minStartBlock;
34 | else {
35 | latestCheckedBlock= Math.max(data,ETHCONFIG.minStartBlock);
36 | }
37 | console.log("The latest checked block was initiated successfully. It is "+latestCheckedBlock);
38 | })
39 | }
40 |
41 |
42 | function initRecipientAddresses() {
43 | DBSERVICE.getAllUsers(function (err,data) {
44 | if(!err){
45 | let addressArray = [];
46 | for(let i=0;i=latestMinedBlock-ETHCONFIG.minMinedRequirement){
68 | console.log('The lasted checked block is '+ latestMinedBlock+'. No new mined blocks........');
69 | }
70 | else
71 | checkDepositTxs(recipientAddresses,latestCheckedBlock+1,latestMinedBlock-ETHCONFIG.minMinedRequirement);
72 | }
73 | checkSubmittedWithdrawTxs();
74 | unconfirmedDepositTxs =getUnconfirmedDepositTx(recipientAddresses);
75 | }
76 |
77 | function checkDepositTxs(myaccounts, startBlockNumber, endBlockNumber) {
78 | if(typeof myaccounts ==='undefined') return;
79 |
80 | if((startBlockNumber = 0) {
94 | DBSERVICE.getUserByEthAddress(transaction.to,function (err,users) {
95 | if(err) {
96 | console.log(err);
97 | return;
98 | }
99 | let depositCoinNumber = this.transaction.value/ETHCONFIG.WeisPerCoin;
100 | let currentCoinNumber = users[0].coin;
101 | let username = users[0].username;
102 | DBSERVICE.updateCoinByUsername(depositCoinNumber+currentCoinNumber,username,function (err,data) {
103 | if(err) {
104 | console.log(err);
105 | return;
106 | }
107 | DBSERVICE.addETHDepositTransaction(this.transaction.hash,this.transaction.to,this.user.id,this.transaction.value/1000000000,this.transaction.blockNumber,function (err,data) {
108 | if(err) {
109 | console.log(err);
110 | return;
111 | }
112 | console.log(" Find a new ETH deposit transaction. TX is "+transaction.hash+". The recipient user id is "+this.user.id);
113 | }.bind({transaction:transaction,user:this.user}));
114 |
115 | }.bind({transaction:transaction,user:users[0]}));
116 |
117 | }.bind({transaction:transaction}));
118 | }
119 | });
120 | if(i>latestCheckedBlock)
121 | latestCheckedBlock=i;
122 | }
123 | }
124 | }
125 |
126 |
127 | function getUnconfirmedDepositTx(addressArray) {
128 |
129 | let latestMinedBlock = web3.eth.getBlock('latest').number;
130 | let startBlock = latestMinedBlock- ETHCONFIG.minMinedRequirement;
131 | let unconfirmedDepositTxs = [];
132 | for(let i= startBlock;i<=latestMinedBlock;i++){
133 | let block = web3.eth.getBlock(i, true);
134 | block.transactions.forEach(function (tx) {
135 | if(addressArray.indexOf(tx.to)>=0)
136 | {
137 | let returnTx ={'blockHash':tx.blockHash,'eth_address':tx.to,'confirmations':latestMinedBlock-tx.blockNumber,'need':20}
138 | unconfirmedDepositTxs.push(returnTx)
139 | }
140 | });
141 | }
142 | return unconfirmedDepositTxs;
143 | }
144 |
145 | function getUnconfirmedDepositTxByUsername(username,callback) {
146 | DBSERVICE.getUserByUsername(username,function (err,data) {
147 | if(err) return callback(err);
148 | let latestMinedBlock = web3.eth.getBlock('latest').number;
149 | let startBlock = latestMinedBlock- ETHCONFIG.minMinedRequirement;
150 | let eth_address= data[0].eth_address;
151 | let unconfirmedTx = [];
152 | for(let i= 0;i1){
17 | return done("More than one users with this username "+username+" were found!");
18 | }
19 | return done(null, rows);
20 | });
21 | }
22 |
23 | function getUserByUseId(userId,done) {
24 | connection.query("SELECT * FROM "+DBCONFIG.database+ "."+ DBCONFIG.users_table +" where id='"+userId+"'", function(err, rows){
25 | if (err){
26 | return done(err);
27 | }
28 | else if(rows.length==0){
29 | return done("No users with this user id "+userId+" were found!");
30 | }
31 | else if(rows.length>1){
32 | return done("More than one users with this id "+userId+" were found!");
33 | }
34 | return done(null, rows);
35 | });
36 | }
37 |
38 | function getUserByEthAddress(eth_address,done) {
39 | connection.query("SELECT * FROM "+DBCONFIG.database+ "."+ DBCONFIG.users_table +" where eth_address='"+eth_address+"'", function(err, rows){
40 | if (err){
41 | return done(err);
42 | }
43 | else if(rows.length==0){
44 | return done("No users with this eth_address "+eth_address+" were found!");
45 | }
46 | else if(rows.length>1){
47 | return done("More than one users with this eth_address "+eth_address+" were found!");
48 | }
49 | return done(null, rows);
50 | });
51 | }
52 |
53 |
54 | function getAllUsers(done) {
55 | connection.query("SELECT * FROM "+DBCONFIG.database+ ".users", function(err, rows){
56 | if (err){
57 | return done(err);
58 | }
59 | if (rows.length===0){
60 | return done("No Users are found in Mysql database!");
61 | }
62 | return done(null, rows);
63 | });
64 | }
65 |
66 | function updateCoinByUsername(coin,username,done) {
67 |
68 | connection.query("UPDATE "+DBCONFIG.database+".users SET coin = ? WHERE username = ?",[coin, username], function(err, rows){
69 | if (err){
70 | return done(err);
71 | }
72 | return done(null,rows);
73 | });
74 | }
75 |
76 | function addBCHDepositTransaction(txhash,to_address,to_user_id,value,blocknumber,done) {
77 |
78 | let insertQuery = "INSERT INTO "+DBCONFIG.database+".bch_transaction ( txhash, to_address, to_user_id, value, blocknumber )" +
79 | " values ('"+txhash+"','"+to_address+"',"+to_user_id+","+value+","+blocknumber+")";
80 |
81 | connection.query(insertQuery, function (err, rows) {
82 | if(err)
83 | return done(err);
84 | else{
85 | return done(null, rows);
86 | }
87 | });
88 | }
89 |
90 |
91 | function addETHDepositTransaction(txhash,to_address,to_user_id,value,blocknumber,done) {
92 |
93 | let insertQuery = "INSERT INTO "+DBCONFIG.database+".eth_transaction ( txhash, to_address, to_user_id, value, blocknumber )" +
94 | " values ('"+txhash+"','"+to_address+"',"+to_user_id+","+value+","+blocknumber+")";
95 | connection.query(insertQuery, function (err, rows) {
96 | if(err){
97 | return done(err);
98 | }
99 | else{
100 | return done(null, rows);
101 | }
102 | });
103 | }
104 |
105 |
106 | function getBCHDepositTransactionByTxId(txid, done) {
107 | connection.query("SELECT * FROM "+DBCONFIG.database+ "."+DBCONFIG.bch_transaction+ " where txhash = '" +txid+"'", function(err, rows){
108 | if (err){
109 | return done(err);
110 | }
111 | return done(null, rows);
112 | });
113 | }
114 |
115 | function addBCHWithdrawLog(userid, toAddress, coinAmount,status,done) {
116 |
117 | let from_address = BCHCONFIG.withdrawSourceAccount;
118 | let to_address = toAddress;
119 | let to_userId = userid;
120 | let coin_value= coinAmount;
121 | let bch_value = 100000000*coinAmount /BCHCONFIG.coinsPerBCH;
122 | let tx_status = status;
123 |
124 | let insertQuery = "INSERT INTO "+DBCONFIG.database+"."+ DBCONFIG.bch_withdraw_log+"( from_address, to_address, to_user_id, coin_value, bch_value, tx_status)" +
125 | " values ('"+from_address+"','"+to_address+"',"+to_userId+","+coin_value+","+bch_value+","+tx_status+")";
126 |
127 | connection.query(insertQuery,function (err, result) {
128 | if(err){
129 | return done(err);
130 | }else{
131 | let withdrawLog = {
132 | id:result.insertId,
133 | from_address: from_address,
134 | to_address:to_address,
135 | to_userId: to_userId,
136 | coin_value: coin_value,
137 | bch_value: bch_value,
138 | tx_status: tx_status
139 | };
140 | return done(null,withdrawLog );
141 | }
142 | })
143 |
144 | }
145 |
146 |
147 |
148 | function addETHWithdrawLog(userid, toAddress, coinAmount,status,done) {
149 |
150 | let from_address = ETHCONFIG.withdrawSourceAccount;
151 | let to_address = toAddress;
152 | let to_userId = userid;
153 | let coin_value = coinAmount;
154 | let eth_value = coinAmount*ETHCONFIG.WeisPerCoin/1000000000;
155 | let tx_status = status;
156 |
157 | let insertQuery = "INSERT INTO "+DBCONFIG.database+"."+ DBCONFIG.eth_withdraw_log+"( from_address, to_address, to_user_id, coin_value, eth_value, tx_status)" +
158 | " values ('"+from_address+"','"+to_address+"',"+to_userId+","+coin_value+","+eth_value+","+tx_status+")";
159 |
160 | connection.query(insertQuery,function (err, result) {
161 | if(err){
162 | return done(err);
163 | }else{
164 | let withdrawLog = {
165 | id:result.insertId,
166 | from_address: from_address,
167 | to_address:to_address,
168 | to_userId: to_userId,
169 | coin_value: coin_value,
170 | eth_value: eth_value,
171 | tx_status: tx_status
172 | };
173 | return done(null,withdrawLog );
174 | }
175 | })
176 |
177 | }
178 |
179 | function updateBCHWithdrawLogById(id,list,done) {
180 | let keys = Object.keys(list);
181 | let values = Object.values(list);
182 | let setString = 'set ';
183 | for(let i=0; i {
328 | return response.data.result;
329 | })
330 | .catch(err => {
331 | console.log('failed in setaccount', err);
332 | return err.message;
333 | });
334 | }
335 |
336 |
337 | async importaddress(...params) {
338 | /*if (!this.isValidAddress(...params)) {
339 | console.log('failed valid check');
340 | return 'invalid address given';
341 | }*/
342 |
343 | let req = await this.performMethod('importaddress', ...params);
344 |
345 | return axios(req)
346 | .then(response => {
347 | return response.data.result;
348 | })
349 | .catch(err => {
350 | console.log('failed in importaddress', err);
351 | return err.message;
352 | });
353 | }
354 |
355 | /**
356 | * @param {String} account bitcoind account to send from
357 | * @param {String} address bitcoin address to send to
358 | * @param {Number} Amount number of bitcoin to send
359 | * @return {String} Tx returns the transaction ID
360 | */
361 | async sendFrom(...params) {
362 | if (!this.isValidAddress(params[1])) {
363 | console.log('failed valid check');
364 | return 'invalid address given';
365 | }
366 |
367 | let req = await this.performMethod('sendFrom', ...params);
368 |
369 | return axios(req)
370 | .then(response => {
371 | return response.data.result;
372 | })
373 | .catch(err => {
374 | console.log('failed in sendFrom', err);
375 | return err.message;
376 | });
377 | }
378 |
379 | /**
380 | * @param {String} accountName name of account you want the address for
381 | * @return {String} address returns the address
382 | */
383 | async getAccountAddress(...params) {
384 | let req = await this.performMethod('getAccountAddress', ...params);
385 |
386 | return axios(req)
387 | .then(response => {
388 | return response.data.result;
389 | })
390 | .catch(err => {
391 | console.log('failed in getAccountAddress', err);
392 | return err.message;
393 | });
394 | }
395 | /**
396 | * @param {String} blockhash
397 | * @return {obj} data returns the block info
398 | */
399 | async getBlock(...params) {
400 | if (!this.isValidAddress(...params)) {
401 | console.log('failed valid check');
402 | return 'invalid address given';
403 | }
404 |
405 | let req = await this.performMethod('getBlock', ...params);
406 |
407 | return axios(req)
408 | .then(response => {
409 | return response.data.result;
410 | })
411 | .catch(err => {
412 | console.log('failed in getBlock', err);
413 | return err.message;
414 | });
415 | }
416 |
417 | /**
418 | * @param {String} transaction_id
419 | * @param {Number} vout use 1
420 | * @return {obj} data returns the tx info
421 | */
422 | async getTxOut(...params) {
423 | if (!this.isValidAddress(...params)) {
424 | console.log('failed valid check');
425 | return 'invalid address given';
426 | }
427 |
428 | let req = await this.performMethod('getTxOut', ...params);
429 |
430 | return axios(req)
431 | .then(response => {
432 | return response.data.result;
433 | })
434 | .catch(err => {
435 | console.log('failed in getTxOut', err);
436 | return err.message;
437 | });
438 | }
439 |
440 | isValidAddress(...x) {
441 | console.log("Valid address "+x);
442 | const test = '[13CH][a-km-zA-HJ-NP-Z0-9]{30,33}';
443 | const cashRegEx = /^((?:bitcoincash):)?(?:[023456789acdefghjklmnpqrstuvwxyz]){42}$/gi;
444 | let testRegEx = new RegExp(test, 'i');
445 |
446 | if (testRegEx.test(x)) {
447 | return testRegEx.test(x);
448 | } else {
449 | return cashRegEx.test(x);
450 | }
451 | }
452 |
453 | translateAddress(address) {
454 | let test = '[13CH][a-km-zA-HJ-NP-Z0-9]{30,33}';
455 | let testRegEx = new RegExp(test, 'i');
456 | if (testRegEx.test(address)) {
457 | let translated = translate.translateAddress(address);
458 | if (translated.origCoin == 'BTC') {
459 | return translated.origAddress;
460 | } else {
461 | return translated.resultAddress;
462 | }
463 | }
464 | }
465 | }
466 |
467 | module.exports = BitcoinCashRPC;
468 |
--------------------------------------------------------------------------------
/app/bch_transactions.js:
--------------------------------------------------------------------------------
1 | //Import modules
2 | const MYSQL = require('mysql');
3 | const BCC = require("./../service/bitcoincashrpc");
4 | const BCHCONFIG = require('./../config/bchconfig');
5 | const BCHADDR = require('bchaddrjs');
6 | const DBSERVICE = require('./../service/db_service');
7 | const BCHkeyStore = require('./../service/keystorebch');
8 |
9 |
10 | // System variables
11 | const BCHRPCCLIENT = new BCC(BCHCONFIG.host, BCHCONFIG.username, BCHCONFIG.password, BCHCONFIG.port, 30000);//Bitcoin Cash RPC Connection
12 |
13 | //All the unspent transactions that belong to the withdraw source account.
14 | var unspentTxs =[];
15 |
16 | const withdrawLogStatus ={
17 | CREATED: 0,
18 | SUBMITTED: 2,
19 | MINED: 4
20 | };
21 |
22 | function addRecipientAddresses(addressArray,callback) {
23 | const bitcorecash = require('bitcoincashjs');
24 | const BASE58CHECK = bitcorecash.encoding.Base58Check;
25 | let count =0;
26 | for(let i=0;i=BCHCONFIG.minConfirmation)&& (this.transaction.category ==='receive')&&this.transaction.account===this.user.username)
82 | {
83 | let coinsDeposit = this.transaction.amount*BCHCONFIG.coinsPerBCH;
84 | let coinBalance = this.user.coin;
85 | var coinBalanceNew = coinBalance + coinsDeposit;
86 | console.log('coinBalanceNew is'+coinBalanceNew);
87 | console.log('username is'+this.user.username);
88 |
89 | DBSERVICE.updateCoinByUsername(coinBalanceNew,this.user.username,function (err3, rows3) {
90 | if(err3)
91 | console.log(err3);
92 | else{
93 | let bch_value_satoshi =this.transaction.amount*100000000;
94 |
95 | DBSERVICE.addBCHDepositTransaction(this.transaction.txid,this.transaction.
96 | address,this.user.id,bch_value_satoshi,blockAcount-this.transaction.confirmations,
97 | function (err4, rows4) {
98 | if(err4)
99 | console.log(err4);
100 | else{
101 | console.log("Found a new BCH deposit transaction and updated all the records accordingly!");
102 | console.log("Txid is "+this.transaction.txid);
103 | }
104 | }.bind({transaction: this.transaction,user:this.user}));
105 |
106 | }
107 | }.bind({transaction: this.transaction,user:this.user}));
108 | }
109 | }
110 | else
111 | console.log("The transaction "+this.transaction.txid+" has already been handled by the system.");
112 | }.bind({transaction: transactions[j],user:this.user}));
113 | }
114 | }.bind({user:data[i]}));
115 | }
116 | }
117 | });
118 | });
119 |
120 | }
121 | };
122 |
123 | /*
124 | This function will subtract a certain amount of Coin and send User BCH instead.
125 | username: who asks to withdraw BCH.
126 | toAddress: The address that the user input to receive BCH for this request. It is legacy format.
127 | coinAmount: Coin to subtract from the user's account
128 | For example:
129 | withdrawBCH('8','mhREfUGuqNTpQSuPVG234kt6T9hzVYkD8Y',5000000);
130 | */
131 | function withdrawBCH(username, toAddress, coinAmount,callback) {
132 | DBSERVICE.getUserByUsername(username, function (err1, data1) {
133 | if (err1) {
134 | return callback(err1);
135 | }
136 | else {
137 | var newCoinValue = data1[0].coin - coinAmount;
138 | var user = data1[0];
139 | user.coin = newCoinValue;
140 | if (newCoinValue < 0) {
141 | return callback("The user " + username + " does not have enough coins to withdraw!");
142 | }
143 | DBSERVICE.updateCoinByUsername(newCoinValue, username, function (err2, data2) {
144 | if (err2) {
145 | return callback(err2);
146 | } else {
147 | DBSERVICE.addBCHWithdrawLog(this.user.id, toAddress, coinAmount, withdrawLogStatus.CREATED, function (err3, data3) {
148 | if (err3)
149 | return callback(err3);
150 | else {
151 | sendTxToNode(data3, function (err4, data4) {
152 | if (err4)
153 | return callback(err4);
154 | else {
155 | DBSERVICE.updateBCHWithdrawLogById(this.withdrawLog.id, {
156 | tx_hash: data4,
157 | tx_status: withdrawLogStatus.SUBMITTED
158 | }, function (err5, data5) {
159 | if (err5)
160 | return callback(err5);
161 | else {
162 | return callback(null,data4);
163 | }
164 | });
165 | }
166 | }.bind({withdrawLog: data3}));
167 | }
168 | });
169 | }
170 | }.bind({user: data1[0]}));
171 | }
172 | });
173 | }
174 | function sendTxToNode(withdrawLog, done) {
175 | var bch = require('bitcoincashjs');
176 | var bchkey = require('./../service/keystorebch');
177 | updateUnspentTx();
178 | var bch_value_bch = withdrawLog.coin_value / BCHCONFIG.coinsPerBCH;
179 | var bch_value_satoshi = 100000000*withdrawLog.coin_value / BCHCONFIG.coinsPerBCH;
180 | var withdrawUTXO =chooseUnspentTxForWithdraw(bch_value_bch);
181 | if(withdrawUTXO.err){
182 | return done(withdrawUTXO.err);
183 | }else{
184 | //The current rpc interface only accepts legacy address format, not Bitcoin cash format. We have to convert the address format before we spend these UTXOs.
185 | //bchaddrjs does not accept bchreg prefix, convert bchreg into regtest if it is necessary.
186 | for(var i=0; i{
200 | return done(null,info);
201 | });
202 | }
203 | };
204 |
205 | function updateUnspentTx(){
206 |
207 | var BCHKeyStore = require('./../service/keystorebch');
208 | if(BCHKeyStore.withdrawSource.length===0)
209 | BCHKeyStore.setWithdrawSource();
210 | var addresses =[];
211 | for (var i=0; i{
216 | unspentTxs = info;
217 | console.log("Retrieve unspent transaction list for withdraw source.")
218 | });
219 |
220 | };
221 |
222 | function chooseUnspentTxForWithdraw(withdrawAmount) {
223 | var withdrawFrom = [];
224 | for(var i=0; iwithdrawAmount+BCHCONFIG.minTxFee) {
235 | withdrawFrom = withdrawFrom.slice(0,j+1);
236 | return({err:null,UTXOs:withdrawFrom});
237 | }
238 | }
239 | return ({err:"The account balance is insufficient."});
240 | };
241 |
242 | function updateSubmittedWithdrawTxs() {
243 | let promise = Promise.resolve(BCHRPCCLIENT.getBlockCount());
244 | promise.then(function (blockAccount) {
245 | DBSERVICE.getBCHWithdrawLogByStatus(withdrawLogStatus.SUBMITTED,function (err,rows) {
246 | if(err)
247 | console.log(err);
248 | else{
249 | for(var i=0;i=BCHCONFIG.minConfirmation)
254 | DBSERVICE.updateBCHWithdrawLogById(this.row.id,{tx_status:withdrawLogStatus.MINED,block_number:blockAccount-info.confirmations},function (err,date) {
255 | if(err)
256 | console.log(err);
257 | else{
258 | console.log("Tx id "+this.row.tx_hash+" has been mined successfully!");
259 | }
260 | }.bind({row:this.row}))
261 | }.bind({row:rows[i]}));
262 |
263 | }
264 | }
265 | });
266 | });
267 | }
268 |
269 | function getBCHBalanceByUserId(userId,done) {
270 | DBSERVICE.getBCHDepositeTxsByUserId(userId,function (err,data) {
271 | if(err)
272 | {
273 | return done(err);
274 | }
275 | let totalWithdraw =0;
276 | for(let i=0;i