UNPKG

@abcpros/bitcore-wallet-service

Version:
1,171 lines 90.6 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __generator = (this && this.__generator) || function (thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (_) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ExpressApp = void 0; var express_1 = __importDefault(require("express")); var lodash_1 = __importDefault(require("lodash")); require("source-map-support/register"); var logger_1 = require("./logger"); var clienterror_1 = require("./errors/clienterror"); var middleware_1 = require("./middleware"); var server_1 = require("./server"); var stats_1 = require("./stats"); var bodyParser = require('body-parser'); var compression = require('compression'); var config = require('../config'); var RateLimit = require('express-rate-limit'); var Common = require('./common'); var rp = require('request-promise-native'); var Defaults = Common.Defaults; var TelegramBot = require('node-telegram-bot-api'); var GoogleTokenStrategy = require('passport-google-id-token'); var passport = require('passport'); var listAccount = require('../../../../accounts.json'); var node_cron_1 = __importDefault(require("node-cron")); var ExpressApp = (function () { function ExpressApp() { this.app = express_1.default(); } ExpressApp.prototype.start = function (opts, cb) { var _this = this; opts = opts || {}; this.app.use(compression()); this.app.use(function (req, res, next) { res.setHeader('Access-Control-Allow-Origin', '*'); res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, DELETE'); res.setHeader('Access-Control-Allow-Headers', 'x-signature,x-identity,x-session,x-client-version,x-wallet-id,X-Requested-With,Content-Type,Authorization'); res.setHeader('x-service-version', server_1.WalletService.getServiceVersion()); next(); }); this.app.use(require('body-parser').urlencoded({ extended: true })); this.app.use(require('express-session')({ secret: 'keyboard cat', resave: true, saveUninitialized: true })); this.app.use(passport.initialize()); this.app.use(passport.session()); passport.serializeUser(function (user, done) { done(null, user); }); passport.use(new GoogleTokenStrategy({ clientID: '287411092309-vovtceqbolmrn2krv8knpt0ovpa4u4ta.apps.googleusercontent.com' }, function (parsedToken, googleId, done) { return done(null, parsedToken.payload.email); })); var allowCORS = function (req, res, next) { if ('OPTIONS' == req.method) { res.sendStatus(200); res.end(); return; } next(); }; this.app.use(allowCORS); this.app.enable('trust proxy'); this.app.use(function (req, res, next) { req.on('abort', function () { logger_1.logger.warn('Request aborted by the client'); }); next(); }); var POST_LIMIT = 1024 * 100; this.app.use(bodyParser.json({ limit: POST_LIMIT })); this.app.use(function (req, res, next) { if (config.maintenanceOpts.maintenanceMode === true) { var errorCode = 503; var errorMessage = 'BWS down for maintenance'; res.status(503).send({ code: errorCode, message: errorMessage }); } else { next(); } }); if (opts.disableLogs) { logger_1.transport.level = 'error'; } else { this.app.use(middleware_1.LogMiddleware()); } var router = express_1.default.Router(); var returnError = function (err, res, req) { if (err instanceof clienterror_1.ClientError) { var status_1 = err.code == 'NOT_AUTHORIZED' ? 401 : 400; if (!opts.disableLogs) logger_1.logger.info('Client Err: ' + status_1 + ' ' + req.url + ' ' + JSON.stringify(err)); var clientError = { code: err.code, message: err.message }; if (err.messageData) clientError.messageData = err.messageData; res .status(status_1) .json(clientError) .end(); } else { var code = 500, message = void 0; if (err && ((err.code && lodash_1.default.isNumber(err.code)) || (err.statusCode && lodash_1.default.isNumber(err.statusCode)))) { code = err.code || err.statusCode; message = err.message || err.body; } var m = message || err.message || err.toString(); if (!opts.disableLogs) logger_1.logger.error(req.url + ' :' + code + ':' + m); res .status(code || 500) .json({ error: m }) .end(); } }; var logDeprecated = function (req) { logger_1.logger.warn('DEPRECATED', req.method, req.url, '(' + req.header('x-client-version') + ')'); }; var getCredentials = function (req) { var identity = req.header('x-identity'); if (!identity) return; return { copayerId: identity, signature: req.header('x-signature'), session: req.header('x-session') }; }; var getServer = function (req, res) { var opts = { clientVersion: req.header('x-client-version'), userAgent: req.header('user-agent') }; return server_1.WalletService.getInstance(opts); }; var getServerWithAuth = function (req, res, opts, cb) { if (lodash_1.default.isFunction(opts)) { cb = opts; opts = {}; } opts = opts || {}; var credentials = getCredentials(req); if (!credentials) return returnError(new clienterror_1.ClientError({ code: 'NOT_AUTHORIZED' }), res, req); var auth = { copayerId: credentials.copayerId, message: req.method.toLowerCase() + '|' + req.url + '|' + JSON.stringify(req.body), signature: credentials.signature, clientVersion: req.header('x-client-version'), userAgent: req.header('user-agent'), walletId: req.header('x-wallet-id'), session: undefined }; if (opts.allowSession) { auth.session = credentials.session; } server_1.WalletService.getInstanceWithAuth(auth, function (err, server) { if (err) return returnError(err, res, req); if (opts.onlySupportStaff && !server.copayerIsSupportStaff) { return returnError(new clienterror_1.ClientError({ code: 'NOT_AUTHORIZED' }), res, req); } if (server.copayerIsSupportStaff) { req.isSupportStaff = true; } if (opts.onlyMarketingStaff && !server.copayerIsMarketingStaff) { return returnError(new clienterror_1.ClientError({ code: 'NOT_AUTHORIZED' }), res, req); } req.walletId = server.walletId; req.copayerId = server.copayerId; return cb(server); }); }; var createWalletLimiter; if (Defaults.RateLimit.createWallet && !opts.ignoreRateLimiter) { logger_1.logger.info('', 'Limiting wallet creation per IP: %d req/h', ((Defaults.RateLimit.createWallet.max / Defaults.RateLimit.createWallet.windowMs) * 60 * 60 * 1000).toFixed(2)); createWalletLimiter = new RateLimit(Defaults.RateLimit.createWallet); } else { createWalletLimiter = function (req, res, next) { next(); }; } var ONE_MINUTE = 60; function SetPublicCache(res, seconds) { res.setHeader('Cache-Control', "public, max-age=" + seconds + ", stale-if-error=" + 10 * seconds); } router.get('/latest-version', function (req, res) { return __awaiter(_this, void 0, void 0, function () { var options, server_2; var _this = this; return __generator(this, function (_a) { SetPublicCache(res, 10 * ONE_MINUTE); try { res.setHeader('User-Agent', 'copay'); options = { uri: 'https://api.github.com/repos/bitpay/wallet/releases/latest', headers: { 'User-Agent': 'Copay' }, json: true }; try { server_2 = getServer(req, res); } catch (ex) { return [2, returnError(ex, res, req)]; } server_2.storage.checkAndUseGlobalCache('latest-copay-version', Defaults.COPAY_VERSION_CACHE_DURATION, function (err, version) { return __awaiter(_this, void 0, void 0, function () { var htmlString_1, err_1; return __generator(this, function (_a) { switch (_a.label) { case 0: if (err) { res.send(err); } if (!version) return [3, 1]; res.json({ version: version }); return [3, 4]; case 1: _a.trys.push([1, 3, , 4]); return [4, rp(options)]; case 2: htmlString_1 = _a.sent(); if (htmlString_1['tag_name']) { server_2.storage.storeGlobalCache('latest-copay-version', htmlString_1['tag_name'], function (err) { res.json({ version: htmlString_1['tag_name'] }); }); } return [3, 4]; case 3: err_1 = _a.sent(); res.send(err_1); return [3, 4]; case 4: return [2]; } }); }); }); } catch (err) { res.send(err); } return [2]; }); }); }); router.post('/v1/wallets/', createWalletLimiter, function (req, res) { logDeprecated(req); return returnError(new clienterror_1.ClientError('BIP45 wallet creation no longer supported'), res, req); }); router.post('/v2/wallets/', createWalletLimiter, function (req, res) { var server; try { server = getServer(req, res); } catch (ex) { return returnError(ex, res, req); } server.createWallet(req.body, function (err, walletId) { if (err) return returnError(err, res, req); res.json({ walletId: walletId }); }); }); router.put('/v1/copayers/:id/', function (req, res) { req.body.copayerId = req.params['id']; var server; try { server = getServer(req, res); } catch (ex) { return returnError(ex, res, req); } server.addAccess(req.body, function (err, result) { if (err) return returnError(err, res, req); res.json(result); }); }); router.post('/v1/wallets/:id/copayers/', function (req, res) { logDeprecated(req); return returnError(new clienterror_1.ClientError('BIP45 wallet creation no longer supported'), res, req); }); router.post('/v2/wallets/:id/copayers/', function (req, res) { req.body.walletId = req.params['id']; var server; try { server = getServer(req, res); } catch (ex) { return returnError(ex, res, req); } server.joinWallet(req.body, function (err, result) { if (err) return returnError(err, res, req); res.json(result); }); }); router.get('/v1/wallets/', function (req, res) { logDeprecated(req); getServerWithAuth(req, res, function (server) { server.getStatus({ includeExtendedInfo: true }, function (err, status) { if (err) return returnError(err, res, req); res.json(status); }); }); }); router.get('/v2/wallets/', function (req, res) { getServerWithAuth(req, res, function (server) { var opts = { includeExtendedInfo: false, twoStep: false }; if (req.query.includeExtendedInfo == '1') opts.includeExtendedInfo = true; if (req.query.twoStep == '1') opts.twoStep = true; server.getStatus(opts, function (err, status) { if (err) return returnError(err, res, req); res.json(status); }); }); }); router.get('/v3/wallets/', function (req, res) { getServerWithAuth(req, res, function (server) { var opts = { includeExtendedInfo: false, twoStep: false, includeServerMessages: false, tokenAddress: req.query.tokenAddress, multisigContractAddress: req.query.multisigContractAddress, network: req.query.network }; if (req.query.includeExtendedInfo == '1') opts.includeExtendedInfo = true; if (req.query.twoStep == '1') opts.twoStep = true; if (req.query.serverMessageArray == '1') opts.includeServerMessages = true; server.getStatus(opts, function (err, status) { if (err) return returnError(err, res, req); res.json(status); }); }); }); router.get('/v1/wallets/:identifier/', function (req, res) { getServerWithAuth(req, res, { onlySupportStaff: true }, function (server) { var opts = { identifier: req.params['identifier'], walletCheck: req.params['walletCheck'] }; server.getWalletFromIdentifier(opts, function (err, wallet) { if (err) return returnError(err, res, req); if (!wallet) return res.end(); server.walletId = wallet.id; var opts = { includeExtendedInfo: false }; if (req.query.includeExtendedInfo == '1') opts.includeExtendedInfo = true; server.getStatus(opts, function (err, status) { if (err) return returnError(err, res, req); res.json(status); }); }); }); }); router.get('/v1/preferences/', function (req, res) { getServerWithAuth(req, res, function (server) { server.getPreferences({}, function (err, preferences) { if (err) return returnError(err, res, req); res.json(preferences); }); }); }); router.put('/v1/preferences', function (req, res) { getServerWithAuth(req, res, function (server) { server.savePreferences(req.body, function (err, result) { if (err) return returnError(err, res, req); res.json(result); }); }); }); router.get('/v1/txproposals/', function (req, res) { getServerWithAuth(req, res, function (server) { server.getPendingTxs({ noCashAddr: true }, function (err, pendings) { if (err) return returnError(err, res, req); res.json(pendings); }); }); }); router.get('/v2/txproposals/', function (req, res) { getServerWithAuth(req, res, function (server) { server.getPendingTxs({}, function (err, pendings) { if (err) return returnError(err, res, req); res.json(pendings); }); }); }); router.post('/v1/txproposals/', function (req, res) { var Errors = require('./errors/errordefinitions'); var err = Errors.UPGRADE_NEEDED; return returnError(err, res, req); }); router.post('/v2/txproposals/', function (req, res) { getServerWithAuth(req, res, function (server) { req.body.noCashAddr = true; req.body.txpVersion = 3; server.createTx(req.body, function (err, txp) { if (err) return returnError(err, res, req); res.json(txp); }); }); }); router.post('/v3/txproposals/', function (req, res) { getServerWithAuth(req, res, function (server) { req.body.txpVersion = 3; server.createTx(req.body, function (err, txp) { if (err) return returnError(err, res, req); res.json(txp); }); }); }); router.post('/v1/advertisements/', function (req, res) { getServerWithAuth(req, res, { onlyMarketingStaff: true }, function (server) { server.createAdvert(req.body, function (err, advert) { if (err) { return returnError(err, res, req); } if (advert) res.json(advert); }); }); }); router.get('/v1/advertisements/', function (req, res) { var server; var testing = req.query.testing; try { server = getServer(req, res); } catch (ex) { return returnError(ex, res, req); } if (testing) { server.getTestingAdverts(req.body, function (err, ads) { if (err) returnError(err, res, req); res.json(ads); }); } else { SetPublicCache(res, 5 * ONE_MINUTE); server.getAdverts(req.body, function (err, ads) { if (err) returnError(err, res, req); res.json(ads); }); } }); router.get('/v1/advertisements/:adId/', function (req, res) { var server; try { server = getServer(req, res); } catch (ex) { return returnError(ex, res, req); } var opts = { adId: req.params['adId'] }; if (req.params['adId']) { server.getAdvert(opts, function (err, ad) { if (err) returnError(err, res, req); res.json(ad); }); } }); router.get('/v1/advertisements/country/:country', function (req, res) { var server; var country = req.params['country']; var opts = { country: country }; try { server = getServer(req, res); } catch (ex) { return returnError(ex, res, req); } server.getAdvertsByCountry(opts, function (err, ads) { if (err) returnError(err, res, req); res.json(ads); }); }); router.post('/v1/advertisements/:adId/activate', function (req, res) { var opts = { adId: req.params['adId'] }; getServerWithAuth(req, res, { onlyMarketingStaff: true }, function (server) { if (req.params['adId']) { server.activateAdvert(opts, function (err, ad) { if (err) returnError(err, res, req); res.json({ advertisementId: opts.adId, message: 'advert activated' }); }); } }); }); router.post('/v1/advertisements/:adId/deactivate', function (req, res) { var opts = { adId: req.params['adId'] }; getServerWithAuth(req, res, { onlyMarketingStaff: true }, function (server) { if (req.params['adId']) { server.deactivateAdvert(opts, function (err, ad) { if (err) returnError(err, res, req); res.json({ advertisementId: opts.adId, message: 'advert deactivated' }); }); } }); }); router.delete('/v1/advertisements/:adId/', function (req, res) { getServerWithAuth(req, res, { onlyMarketingStaff: true }, function (server) { req.body.adId = req.params['adId']; server.removeAdvert(req.body, function (err, removedAd) { if (err) returnError(err, res, req); if (removedAd) { res.json(removedAd); } }); }); }); router.post('/v1/addresses/', function (req, res) { logDeprecated(req); getServerWithAuth(req, res, function (server) { server.createAddress({ ignoreMaxGap: true }, function (err, address) { if (err) return returnError(err, res, req); res.json(address); }); }); }); router.post('/v2/addresses/', function (req, res) { logDeprecated(req); getServerWithAuth(req, res, function (server) { server.createAddress({ ignoreMaxGap: true }, function (err, address) { if (err) return returnError(err, res, req); res.json(address); }); }); }); router.post('/v3/addresses/', function (req, res) { getServerWithAuth(req, res, function (server) { var opts = req.body; opts = opts || {}; opts.noCashAddr = true; server.createAddress(opts, function (err, address) { if (err) return returnError(err, res, req); res.json(address); }); }); }); router.post('/v4/addresses/', function (req, res) { getServerWithAuth(req, res, function (server) { server.createAddress(req.body, function (err, address) { if (err) return returnError(err, res, req); res.json(address); }); }); }); router.get('/v1/addresses/', function (req, res) { getServerWithAuth(req, res, function (server) { var opts = {}; if (req.query.limit) opts.limit = +req.query.limit; opts.reverse = req.query.reverse == '1'; server.getMainAddresses(opts, function (err, addresses) { if (err) return returnError(err, res, req); res.json(addresses); }); }); }); router.get('/v2/remaining/', function (req, res) { var opts = {}; if (req.query.network) opts.network = req.query.network; var server; try { server = getServer(req, res); } catch (ex) { return returnError(ex, res, req); } server.getRemainingInfo(opts, function (err, balance) { if (err) return returnError(err, res, req); res.json(balance); }); }); router.get('/v1/balance/', function (req, res) { getServerWithAuth(req, res, function (server) { var opts = {}; if (req.query.coin) opts.coin = req.query.coin; if (req.query.twoStep == '1') opts.twoStep = true; if (req.query.tokenAddress) opts.tokenAddress = req.query.tokenAddress; if (req.query.multisigContractAddress) opts.multisigContractAddress = req.query.multisigContractAddress; server.getBalance(opts, function (err, balance) { if (err) return returnError(err, res, req); res.json(balance); }); }); }); var estimateFeeLimiter; if (Defaults.RateLimit.estimateFee && !opts.ignoreRateLimiter) { logger_1.logger.info('', 'Limiting estimate fee per IP: %d req/h', ((Defaults.RateLimit.estimateFee.max / Defaults.RateLimit.estimateFee.windowMs) * 60 * 60 * 1000).toFixed(2)); estimateFeeLimiter = new RateLimit(Defaults.RateLimit.estimateFee); } else { estimateFeeLimiter = function (req, res, next) { next(); }; } router.get('/v1/feelevels/', estimateFeeLimiter, function (req, res) { SetPublicCache(res, 1 * ONE_MINUTE); logDeprecated(req); var opts = {}; if (req.query.network) opts.network = req.query.network; var server; try { server = getServer(req, res); } catch (ex) { return returnError(ex, res, req); } server.getFeeLevels(opts, function (err, feeLevels) { if (err) return returnError(err, res, req); lodash_1.default.each(feeLevels, function (feeLevel) { feeLevel.feePerKB = feeLevel.feePerKb; delete feeLevel.feePerKb; }); res.json(feeLevels); }); }); router.get('/v2/feelevels/', function (req, res) { var opts = {}; SetPublicCache(res, 1 * ONE_MINUTE); if (req.query.coin) opts.coin = req.query.coin; if (req.query.network) opts.network = req.query.network; var server; try { server = getServer(req, res); } catch (ex) { return returnError(ex, res, req); } server.getFeeLevels(opts, function (err, feeLevels) { if (err) return returnError(err, res, req); res.json(feeLevels); }); }); router.post('/v3/estimateGas/', function (req, res) { getServerWithAuth(req, res, function (server) { return __awaiter(_this, void 0, void 0, function () { var gasLimit, err_2; return __generator(this, function (_a) { switch (_a.label) { case 0: _a.trys.push([0, 2, , 3]); return [4, server.estimateGas(req.body)]; case 1: gasLimit = _a.sent(); res.json(gasLimit); return [3, 3]; case 2: err_2 = _a.sent(); returnError(err_2, res, req); return [3, 3]; case 3: return [2]; } }); }); }); }); router.post('/v1/ethmultisig/', function (req, res) { getServerWithAuth(req, res, function (server) { return __awaiter(_this, void 0, void 0, function () { var multisigContractInstantiationInfo, err_3; return __generator(this, function (_a) { switch (_a.label) { case 0: _a.trys.push([0, 2, , 3]); return [4, server.getMultisigContractInstantiationInfo(req.body)]; case 1: multisigContractInstantiationInfo = _a.sent(); res.json(multisigContractInstantiationInfo); return [3, 3]; case 2: err_3 = _a.sent(); returnError(err_3, res, req); return [3, 3]; case 3: return [2]; } }); }); }); }); router.post('/v1/ethmultisig/info', function (req, res) { getServerWithAuth(req, res, function (server) { return __awaiter(_this, void 0, void 0, function () { var multisigContractInfo, err_4; return __generator(this, function (_a) { switch (_a.label) { case 0: _a.trys.push([0, 2, , 3]); return [4, server.getMultisigContractInfo(req.body)]; case 1: multisigContractInfo = _a.sent(); res.json(multisigContractInfo); return [3, 3]; case 2: err_4 = _a.sent(); returnError(err_4, res, req); return [3, 3]; case 3: return [2]; } }); }); }); }); router.post('/v1/token/info', function (req, res) { getServerWithAuth(req, res, function (server) { return __awaiter(_this, void 0, void 0, function () { var tokenContractInfo, err_5; return __generator(this, function (_a) { switch (_a.label) { case 0: _a.trys.push([0, 2, , 3]); return [4, server.getTokenContractInfo(req.body)]; case 1: tokenContractInfo = _a.sent(); res.json(tokenContractInfo); return [3, 3]; case 2: err_5 = _a.sent(); returnError(err_5, res, req); return [3, 3]; case 3: return [2]; } }); }); }); }); router.get('/v1/sendmaxinfo/', function (req, res) { getServerWithAuth(req, res, function (server) { var q = req.query; var opts = {}; if (q.feePerKb) opts.feePerKb = +q.feePerKb; if (q.feeLevel) opts.feeLevel = q.feeLevel; if (q.excludeUnconfirmedUtxos == '1') opts.excludeUnconfirmedUtxos = true; if (q.returnInputs == '1') opts.returnInputs = true; server.getSendMaxInfo(opts, function (err, info) { if (err) return returnError(err, res, req); res.json(info); }); }); }); router.get('/v1/utxos/', function (req, res) { var opts = {}; var addresses = req.query.addresses; if (addresses && lodash_1.default.isString(addresses)) opts.addresses = req.query.addresses.split(','); getServerWithAuth(req, res, function (server) { server.getUtxos(opts, function (err, utxos) { if (err) return returnError(err, res, req); res.json(utxos); }); }); }); router.get('/v1/tokens/', function (req, res) { getServerWithAuth(req, res, function (server) { server.getTokens(opts, function (err, groupToken) { if (err) return returnError(err, res, req); res.json(groupToken); }); }); }); router.get('/v1/utxosToken/', function (req, res) { getServerWithAuth(req, res, function (server) { server.getUtxosToken(opts, function (err, groupToken) { if (err) return returnError(err, res, req); res.json(groupToken); }); }); }); router.get('/v1/txDetail/', function (req, res) { var txId = req.query.txId; getServerWithAuth(req, res, function (server) { server.getTxDetail(txId, function (err, coins) { if (err) return returnError(err, res, req); res.json(coins); }); }); }); router.get('/v1/txcoins/', function (req, res) { var txId = req.query.txId; getServerWithAuth(req, res, function (server) { server.getCoinsForTx({ txId: txId }, function (err, coins) { if (err) return returnError(err, res, req); res.json(coins); }); }); }); router.post('/v1/broadcast_raw/', function (req, res) { getServerWithAuth(req, res, function (server) { server.broadcastRawTx(req.body, function (err, txid) { if (err) return returnError(err, res, req); res.json(txid); res.end(); }); }); }); router.post('/v1/txproposals/:id/signatures/', function (req, res) { getServerWithAuth(req, res, function (server) { req.body.maxTxpVersion = 3; req.body.txProposalId = req.params['id']; server.signTx(req.body, function (err, txp) { if (err) return returnError(err, res, req); res.json(txp); res.end(); }); }); }); router.post('/v2/txproposals/:id/signatures/', function (req, res) { getServerWithAuth(req, res, function (server) { req.body.txProposalId = req.params['id']; req.body.maxTxpVersion = 3; req.body.supportBchSchnorr = true; server.signTx(req.body, function (err, txp) { if (err) return returnError(err, res, req); res.json(txp); res.end(); }); }); }); router.post('/v1/txproposals/:id/publish/', function (req, res) { getServerWithAuth(req, res, function (server) { req.body.txProposalId = req.params['id']; req.body.noCashAddr = true; server.publishTx(req.body, function (err, txp) { if (err) return returnError(err, res, req); res.json(txp); res.end(); }); }); }); router.post('/v2/txproposals/:id/publish/', function (req, res) { getServerWithAuth(req, res, function (server) { req.body.txProposalId = req.params['id']; server.publishTx(req.body, function (err, txp) { if (err) return returnError(err, res, req); res.json(txp); res.end(); }); }); }); router.post('/v1/txproposals/:id/broadcast/', function (req, res) { getServerWithAuth(req, res, function (server) { req.body.txProposalId = req.params['id']; server.broadcastTx(req.body, function (err, txp) { if (err) return returnError(err, res, req); res.json(txp); res.end(); }); }); }); router.post('/v1/txproposals/:id/rejections', function (req, res) { getServerWithAuth(req, res, function (server) { req.body.txProposalId = req.params['id']; server.rejectTx(req.body, function (err, txp) { if (err) return returnError(err, res, req); res.json(txp); res.end(); }); }); }); router.delete('/v1/txproposals/:id/', function (req, res) { getServerWithAuth(req, res, function (server) { req.body.txProposalId = req.params['id']; server.removePendingTx(req.body, function (err) { if (err) return returnError(err, res, req); res.json({ success: true }); res.end(); }); }); }); router.get('/v1/txproposals/:id/', function (req, res) { getServerWithAuth(req, res, function (server) { req.body.txProposalId = req.params['id']; server.getTx(req.body, function (err, tx) { if (err) return returnError(err, res, req); res.json(tx); res.end(); }); }); }); router.get('/v2/txhistory/', function (req, res) { getServerWithAuth(req, res, function (server) { var opts = {}; if (req.query.skip) opts.skip = +req.query.skip; if (req.query.limit) opts.limit = +req.query.limit; if (req.query.tokenAddress) opts.tokenAddress = req.query.tokenAddress; if (req.query.multisigContractAddress) opts.multisigContractAddress = req.query.multisigContractAddress; if (req.query.includeExtendedInfo == '1') opts.includeExtendedInfo = true; opts.includeImmatureStatus = true; server.getTxHistory(opts, function (err, txs) { if (err) return returnError(err, res, req); res.json(txs); res.end(); }); }); }); router.get('/v1/txhistory/', function (req, res) { getServerWithAuth(req, res, function (server) { var opts = {}; if (req.query.skip) opts.skip = +req.query.skip; if (req.query.limit) opts.limit = +req.query.limit; if (req.query.tokenAddress) opts.tokenAddress = req.query.tokenAddress; if (req.query.multisigContractAddress) opts.multisigContractAddress = req.query.multisigContractAddress; if (req.query.includeExtendedInfo == '1') opts.includeExtendedInfo = true; server.getTxHistory(opts, function (err, txs) { if (err) return returnError(err, res, req); res.json(txs); res.end(); }); }); }); router.post('/v1/addresses/scan/', function (req, res) { getServerWithAuth(req, res, function (server) { server.startScan(req.body, function (err, started) { if (err) return returnError(err, res, req); res.json(started); res.end(); }); }); }); router.get('/v1/stats/', function (req, res) { SetPublicCache(res, 1 * ONE_MINUTE); var opts = {}; if (req.query.network) opts.network = req.query.network; if (req.query.coin) opts.coin = req.query.coin; if (req.query.from) opts.from = req.query.from; if (req.query.to) opts.to = req.query.to; var stats = new stats_1.Stats(opts); stats.run(function (err, data) { if (err) return returnError(err, res, req); res.json(data); res.end(); }); }); router.get('/v1/version/', function (req, res) { SetPublicCache(res, 1 * ONE_MINUTE); res.json({ serviceVersion: server_1.WalletService.getServiceVersion() }); res.end(); }); router.post('/v1/login/', function (req, res) { getServerWithAuth(req, res, function (server) { server.login({}, function (err, session) { if (err) return returnError(err, res, req); res.json(session); }); }); }); router.post('/v1/logout/', function (req, res) { getServerWithAuth(req, res, function (server) { server.logout({}, function (err) { if (err) return returnError(err, res, req); res.end(); }); }); }); router.get('/v1/notifications/', function (req, res) { getServerWithAuth(req, res, { allowSession: true }, function (server) { var timeSpan = req.query.timeSpan ? Math.min(+req.query.timeSpan || 0, Defaults.MAX_NOTIFICATIONS_TIMESPAN) : Defaults.NOTIFICATIONS_TIMESPAN; var opts = { minTs: +Date.now() - timeSpan * 1000, notificationId: req.query.notificationId }; server.getNotifications(opts, function (err, notifications) { if (err) return returnError(err, res, req); res.json(notifications); }); }); }); router.get('/v1/txnotes/:txid', function (req, res) { getServerWithAuth(req, res, function (server) { var opts = { txid: req.params['txid'] }; server.getTxNote(opts, function (err, note) { if (err) return returnError(err, res, req); res.json(note); }); }); }); router.put('/v1/txnotes/:txid/', function (req, res) { req.body.txid = req.params['txid']; getServerWithAuth(req, res, function (server) { server.editTxNote(req.body, function (err, note) { if (err) return returnError(err, res, req); res.json(note); }); }); }); router.get('/v1/txnotes/', function (req, res) { getServerWithAuth(req, res, function (server) { var opts = {}; if (req.query.minTs && lodash_1.default.isNumber(+req.query.minTs)) { opts.minTs = +req.query.minTs; } server.getTxNotes(opts, function (err, notes) { if (err) return returnError(err, res, req); res.json(notes); }); }); }); router.get('/v1/nonce/:address', function (req, res) { getServerWithAuth(req, res, function (server) { return __awaiter(_this, void 0, void 0, function () { var opts, nonce, err_6; return __generator(this, function (_a) { switch (_a.label) { case 0: opts = { coin: req.query.coin || 'eth', network: req.query.network || 'livenet', address: req.params['address'] }; _a.label = 1; case 1: _a.trys.push([1, 3, , 4]); return [4, server.getNonce(opts)]; case 2: nonce = _a.sent(); res.json(nonce); return [3, 4]; case