UNPKG

bitcore-wallet-service

Version:
2,235 lines 86.9 kB
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ExpressApp = void 0;
const async = __importStar(require("async"));
const cors_1 = __importDefault(require("cors"));
const express_1 = __importDefault(require("express"));
const lodash_1 = __importDefault(require("lodash"));
const path_1 = __importDefault(require("path"));
require("source-map-support/register");
const config_1 = __importDefault(require("../config"));
const common_1 = require("./common");
const clienterror_1 = require("./errors/clienterror");
const errordefinitions_1 = require("./errors/errordefinitions");
const logger_1 = require("./logger");
const middleware_1 = require("./middleware");
const server_1 = require("./server");
const stats_1 = require("./stats");
const compression = require('compression');
const RateLimit = require('express-rate-limit');
const rp = require('request-promise-native');
const Defaults = common_1.Common.Defaults;
class ExpressApp {
    constructor() {
        this.app = (0, express_1.default)();
    }
    start(opts, cb) {
        opts = opts || {};
        this.app.use(compression());
        this.app.use((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-identities,x-session,x-client-version,x-wallet-id,X-Requested-With,Content-Type,Authorization');
            res.setHeader('x-service-version', server_1.WalletService.getServiceVersion());
            next();
        });
        const allowCORS = (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((req, res, next) => {
            req.on('abort', () => {
                logger_1.logger.warn('Request aborted by the client');
            });
            next();
        });
        const POST_LIMIT = 1024 * 100;
        const POST_LIMIT_LARGE = 2 * 1024 * 1024;
        this.app.use((req, res, next) => {
            if (req.path.includes('/txproposals')) {
                return express_1.default.json({ limit: POST_LIMIT_LARGE })(req, res, next);
            }
            else {
                return express_1.default.json({ limit: POST_LIMIT })(req, res, next);
            }
        });
        this.app.use((req, res, next) => {
            if (config_1.default.maintenanceOpts.maintenanceMode === true) {
                let errorCode = 503;
                let 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((0, middleware_1.LogMiddleware)());
        }
        const router = express_1.default.Router();
        const returnError = (err, res, req) => {
            if (res.headersSent) {
                return;
            }
            if (err instanceof clienterror_1.ClientError) {
                const status = err.code == 'NOT_AUTHORIZED' ? 401 : 400;
                if (!opts.disableLogs)
                    logger_1.logger.info('Client Err: ' + status + ' ' + req.url + ' ' + JSON.stringify(err));
                const clientError = {
                    code: err.code,
                    message: err.message
                };
                if (err.messageData)
                    clientError.messageData = err.messageData;
                res
                    .status(status)
                    .json(clientError)
                    .end();
            }
            else {
                let code = 500, message;
                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;
                }
                const m = message || err.toString();
                if (!opts.disableLogs)
                    logger_1.logger.error(req.url + ' :' + code + ':' + m);
                res
                    .status(code || 500)
                    .json({
                    error: m
                })
                    .end();
            }
        };
        const logDeprecated = req => {
            logger_1.logger.warn('DEPRECATED', req.method, req.url, '(' + req.header('x-client-version') + ')');
        };
        const getCredentials = req => {
            const identity = req.header('x-identity');
            if (!identity)
                return;
            return {
                copayerId: identity,
                signature: req.header('x-signature'),
                session: req.header('x-session')
            };
        };
        const getServer = (req, res) => {
            const opts = {
                clientVersion: req.header('x-client-version'),
                userAgent: req.header('user-agent')
            };
            return server_1.WalletService.getInstance(opts);
        };
        const getServerWithAuth = (req, res, opts, cb) => {
            if (lodash_1.default.isFunction(opts)) {
                cb = opts;
                opts = {};
            }
            opts = opts || {};
            const credentials = getCredentials(req);
            if (!credentials)
                return returnError(new clienterror_1.ClientError({
                    code: 'NOT_AUTHORIZED'
                }), res, req);
            const 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, (err, server) => {
                opts = opts;
                if (err) {
                    if (opts.silentFailure) {
                        return cb(null, err);
                    }
                    else {
                        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);
            });
        };
        const getServerWithMultiAuth = (req, res, opts = {}) => {
            const identities = req.headers['x-identities'] ? req.headers['x-identities'].split(',') : false;
            const signature = req.headers['x-signature'];
            if (!identities || !signature) {
                throw new clienterror_1.ClientError({ code: 'NOT_AUTHORIZED' });
            }
            if (!Array.isArray(identities)) {
                throw new clienterror_1.ClientError({ code: 'NOT_AUTHORIZED' });
            }
            return identities.map(id => new Promise((resolve, reject) => getServerWithAuth(Object.assign(req, {
                headers: {
                    ...req.headers,
                    'x-identity': id
                }
            }), res, opts, (server, err) => (err ? reject(err) : resolve(server)))));
        };
        let createWalletLimiter;
        if (Defaults.RateLimit.createWallet && !opts.ignoreRateLimiter) {
            logger_1.logger.info('Limiting wallet creation per IP: %o req/h', ((Defaults.RateLimit.createWallet.max / Defaults.RateLimit.createWallet.windowMs) * 60 * 60 * 1000).toFixed(2));
            createWalletLimiter = new RateLimit(Defaults.RateLimit.createWallet);
        }
        else {
            createWalletLimiter = (req, res, next) => {
                next();
            };
        }
        const ONE_MINUTE = 60;
        function SetPublicCache(res, seconds) {
            res.setHeader('Cache-Control', `public, max-age=${seconds}, stale-if-error=${10 * seconds}`);
        }
        router.get('/latest-version', async (req, res) => {
            SetPublicCache(res, 10 * ONE_MINUTE);
            try {
                res.setHeader('User-Agent', 'copay');
                var options = {
                    uri: 'https://api.github.com/repos/bitpay/wallet/releases/latest',
                    headers: {
                        'User-Agent': 'Copay'
                    },
                    json: true
                };
                let server;
                try {
                    server = getServer(req, res);
                }
                catch (ex) {
                    return returnError(ex, res, req);
                }
                server.storage.checkAndUseGlobalCache('latest-copay-version', Defaults.COPAY_VERSION_CACHE_DURATION, async (err, version) => {
                    if (err) {
                        res.send(err);
                    }
                    if (version) {
                        res.json({ version });
                    }
                    else {
                        try {
                            const htmlString = await rp(options);
                            if (htmlString['tag_name']) {
                                server.storage.storeGlobalCache('latest-copay-version', htmlString['tag_name'], err => {
                                    res.json({ version: htmlString['tag_name'] });
                                });
                            }
                        }
                        catch (err) {
                            res.send(err);
                        }
                    }
                });
            }
            catch (err) {
                res.send(err);
            }
        });
        router.post('/v1/wallets/', createWalletLimiter, (req, res) => {
            logDeprecated(req);
            return returnError(new clienterror_1.ClientError('BIP45 wallet creation no longer supported'), res, req);
        });
        router.post('/v2/wallets/', createWalletLimiter, (req, res) => {
            let server;
            try {
                server = getServer(req, res);
            }
            catch (ex) {
                return returnError(ex, res, req);
            }
            server.createWallet(req.body, (err, walletId) => {
                if (err)
                    return returnError(err, res, req);
                res.json({
                    walletId
                });
            });
        });
        router.put('/v1/copayers/:id/', (req, res) => {
            req.body.copayerId = req.params['id'];
            let server;
            try {
                server = getServer(req, res);
            }
            catch (ex) {
                return returnError(ex, res, req);
            }
            server.addAccess(req.body, (err, result) => {
                if (err)
                    return returnError(err, res, req);
                res.json(result);
            });
        });
        router.post('/v1/wallets/:id/copayers/', (req, res) => {
            logDeprecated(req);
            return returnError(new clienterror_1.ClientError('BIP45 wallet creation no longer supported'), res, req);
        });
        router.post('/v2/wallets/:id/copayers/', (req, res) => {
            req.body.walletId = req.params['id'];
            let server;
            try {
                server = getServer(req, res);
            }
            catch (ex) {
                return returnError(ex, res, req);
            }
            server.joinWallet(req.body, (err, result) => {
                if (err)
                    return returnError(err, res, req);
                res.json(result);
            });
        });
        router.get('/v1/wallets/', (req, res) => {
            logDeprecated(req);
            getServerWithAuth(req, res, server => {
                server.getStatus({
                    includeExtendedInfo: true
                }, (err, status) => {
                    if (err)
                        return returnError(err, res, req);
                    res.json(status);
                });
            });
        });
        router.get('/v2/wallets/', (req, res) => {
            getServerWithAuth(req, res, server => {
                const opts = { includeExtendedInfo: false, twoStep: false };
                if (req.query.includeExtendedInfo == '1')
                    opts.includeExtendedInfo = true;
                if (req.query.twoStep == '1')
                    opts.twoStep = true;
                server.getStatus(opts, (err, status) => {
                    if (err)
                        return returnError(err, res, req);
                    res.json(status);
                });
            });
        });
        router.get('/v3/wallets/', (req, res) => {
            getServerWithAuth(req, res, server => {
                const 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, (err, status) => {
                    if (err)
                        return returnError(err, res, req);
                    res.json(status);
                });
            });
        });
        router.get('/v1/wallets/all/', async (req, res) => {
            let responses;
            const buildOpts = (req, copayerId) => {
                const getParam = (param, returnArray = false) => {
                    const value = req.query[`${copayerId}:${param}`] || req.query[copayerId]?.[param];
                    if (returnArray) {
                        return Array.isArray(value) ? value : value ? [value] : null;
                    }
                    return value ? value : null;
                };
                const opts = {
                    includeExtendedInfo: req.query.includeExtendedInfo == '1',
                    twoStep: req.query.twoStep == '1',
                    silentFailure: req.query.silentFailure == '1',
                    includeServerMessages: req.query.serverMessageArray == '1',
                    tokenAddresses: getParam('tokenAddress', true),
                    multisigContractAddress: getParam('multisigContractAddress'),
                    network: getParam('network')
                };
                return opts;
            };
            try {
                responses = await Promise.all(getServerWithMultiAuth(req, res, { silentFailure: req.query.silentFailure == '1' }).map(promise => promise.then((server) => new Promise(resolve => {
                    let options = buildOpts(req, server.copayerId);
                    if (options.tokenAddresses) {
                        options.tokenAddresses.unshift(null);
                        return async.concat(options.tokenAddresses, (tokenAddress, cb) => {
                            let optsClone = JSON.parse(JSON.stringify(options));
                            optsClone.tokenAddresses = null;
                            optsClone.tokenAddress = tokenAddress;
                            return server.getStatus(optsClone, (err, status) => {
                                let result = {
                                    walletId: server.walletId,
                                    tokenAddress: optsClone.tokenAddress,
                                    success: true,
                                    ...(err ? { success: false, message: err.message } : {}),
                                    status
                                };
                                if (err && err.message)
                                    logger_1.logger.error(`An error occurred retrieving wallet status - id: ${server.walletId} - token address: ${optsClone.tokenAddress} - err: ${err.message}`);
                                cb(null, result);
                            });
                        }, (err, result) => {
                            return resolve(result);
                        });
                    }
                    else {
                        return server.getStatus(options, (err, status) => {
                            return resolve([
                                {
                                    walletId: server.walletId,
                                    tokenAddress: null,
                                    success: true,
                                    ...(err ? { success: false, message: err.message } : {}),
                                    status
                                }
                            ]);
                        });
                    }
                }), ({ message }) => Promise.resolve({ success: false, error: message }))));
            }
            catch (err) {
                return returnError(err, res, req);
            }
            return res.json(lodash_1.default.flatten(responses));
        });
        router.get('/v1/wallets/:identifier/', (req, res) => {
            getServerWithAuth(req, res, {
                onlySupportStaff: true
            }, server => {
                const opts = {
                    identifier: req.params['identifier'],
                    walletCheck: ['1', 'true'].includes(req.query['walletCheck'])
                };
                server.getWalletFromIdentifier(opts, (err, wallet) => {
                    if (err)
                        return returnError(err, res, req);
                    if (!wallet)
                        return res.end();
                    server.walletId = wallet.id;
                    const opts = { includeExtendedInfo: false };
                    if (req.query.includeExtendedInfo == '1')
                        opts.includeExtendedInfo = true;
                    server.getStatus(opts, (err, status) => {
                        if (err)
                            return returnError(err, res, req);
                        res.json(status);
                    });
                });
            });
        });
        router.get('/v1/preferences/', (req, res) => {
            getServerWithAuth(req, res, server => {
                server.getPreferences({}, (err, preferences) => {
                    if (err)
                        return returnError(err, res, req);
                    res.json(preferences);
                });
            });
        });
        router.put('/v1/preferences', (req, res) => {
            getServerWithAuth(req, res, server => {
                server.savePreferences(req.body, (err, result) => {
                    if (err)
                        return returnError(err, res, req);
                    res.json(result);
                });
            });
        });
        router.get('/v1/txproposals/', (req, res) => {
            getServerWithAuth(req, res, server => {
                server.getPendingTxs({ noCashAddr: true }, (err, pendings) => {
                    if (err)
                        return returnError(err, res, req);
                    res.json(pendings);
                });
            });
        });
        router.get('/v2/txproposals/', (req, res) => {
            getServerWithAuth(req, res, server => {
                server.getPendingTxs({}, (err, pendings) => {
                    if (err)
                        return returnError(err, res, req);
                    res.json(pendings);
                });
            });
        });
        router.post('/v1/txproposals/', (req, res) => {
            const err = errordefinitions_1.Errors.UPGRADE_NEEDED;
            return returnError(err, res, req);
        });
        router.post('/v2/txproposals/', (req, res) => {
            getServerWithAuth(req, res, server => {
                req.body.noCashAddr = true;
                req.body.txpVersion = 3;
                server.createTx(req.body, (err, txp) => {
                    if (err)
                        return returnError(err, res, req);
                    res.json(txp);
                });
            });
        });
        router.post('/v3/txproposals/', (req, res) => {
            getServerWithAuth(req, res, server => {
                req.body.txpVersion = 3;
                server.createTx(req.body, (err, txp) => {
                    if (err)
                        return returnError(err, res, req);
                    res.json(txp);
                });
            });
        });
        router.post('/v1/advertisements/', (req, res) => {
            getServerWithAuth(req, res, {
                onlyMarketingStaff: true
            }, server => {
                server.createAdvert(req.body, (err, advert) => {
                    if (err) {
                        return returnError(err, res, req);
                    }
                    if (advert)
                        res.json(advert);
                });
            });
        });
        router.get('/v1/advertisements/', (req, res) => {
            let server;
            let testing = req.query.testing;
            try {
                server = getServer(req, res);
            }
            catch (ex) {
                return returnError(ex, res, req);
            }
            if (testing) {
                server.getTestingAdverts(req.body, (err, ads) => {
                    if (err)
                        returnError(err, res, req);
                    res.json(ads);
                });
            }
            else {
                SetPublicCache(res, 5 * ONE_MINUTE);
                server.getAdverts(req.body, (err, ads) => {
                    if (err)
                        returnError(err, res, req);
                    res.json(ads);
                });
            }
        });
        router.get('/v1/advertisements/:adId/', (req, res) => {
            let server;
            try {
                server = getServer(req, res);
            }
            catch (ex) {
                return returnError(ex, res, req);
            }
            let opts = { adId: req.params['adId'] };
            if (req.params['adId']) {
                server.getAdvert(opts, (err, ad) => {
                    if (err)
                        returnError(err, res, req);
                    res.json(ad);
                });
            }
        });
        router.get('/v1/advertisements/country/:country', (req, res) => {
            let server;
            let country = req.params['country'];
            let opts = { country };
            try {
                server = getServer(req, res);
            }
            catch (ex) {
                return returnError(ex, res, req);
            }
            server.getAdvertsByCountry(opts, (err, ads) => {
                if (err)
                    returnError(err, res, req);
                res.json(ads);
            });
        });
        router.post('/v1/advertisements/:adId/activate', (req, res) => {
            let opts = { adId: req.params['adId'] };
            getServerWithAuth(req, res, {
                onlyMarketingStaff: true
            }, server => {
                if (req.params['adId']) {
                    server.activateAdvert(opts, (err, ad) => {
                        if (err)
                            returnError(err, res, req);
                        res.json({ advertisementId: opts.adId, message: 'advert activated' });
                    });
                }
            });
        });
        router.post('/v1/advertisements/:adId/deactivate', (req, res) => {
            let opts = { adId: req.params['adId'] };
            getServerWithAuth(req, res, {
                onlyMarketingStaff: true
            }, server => {
                if (req.params['adId']) {
                    server.deactivateAdvert(opts, (err, ad) => {
                        if (err)
                            returnError(err, res, req);
                        res.json({ advertisementId: opts.adId, message: 'advert deactivated' });
                    });
                }
            });
        });
        router.delete('/v1/advertisements/:adId/', (req, res) => {
            getServerWithAuth(req, res, {
                onlyMarketingStaff: true
            }, server => {
                req.body.adId = req.params['adId'];
                server.removeAdvert(req.body, (err, removedAd) => {
                    if (err)
                        returnError(err, res, req);
                    if (removedAd) {
                        res.json(removedAd);
                    }
                });
            });
        });
        router.post('/v1/addresses/', (req, res) => {
            logDeprecated(req);
            getServerWithAuth(req, res, server => {
                server.createAddress({
                    ignoreMaxGap: true
                }, (err, address) => {
                    if (err)
                        return returnError(err, res, req);
                    res.json(address);
                });
            });
        });
        router.post('/v2/addresses/', (req, res) => {
            logDeprecated(req);
            getServerWithAuth(req, res, server => {
                server.createAddress({
                    ignoreMaxGap: true
                }, (err, address) => {
                    if (err)
                        return returnError(err, res, req);
                    res.json(address);
                });
            });
        });
        router.post('/v3/addresses/', (req, res) => {
            getServerWithAuth(req, res, server => {
                let opts = req.body;
                opts = opts || {};
                opts.noCashAddr = true;
                server.createAddress(opts, (err, address) => {
                    if (err)
                        return returnError(err, res, req);
                    res.json(address);
                });
            });
        });
        router.post('/v4/addresses/', (req, res) => {
            getServerWithAuth(req, res, server => {
                server.createAddress(req.body, (err, address) => {
                    if (err)
                        return returnError(err, res, req);
                    res.json(address);
                });
            });
        });
        router.get('/v1/addresses/', (req, res) => {
            getServerWithAuth(req, res, server => {
                const opts = {};
                if (req.query.limit)
                    opts.limit = +req.query.limit;
                if (req.query.skip)
                    opts.skip = +req.query.skip;
                opts.reverse = req.query.reverse == '1';
                server.getMainAddresses(opts, (err, addresses) => {
                    if (err)
                        return returnError(err, res, req);
                    res.json(addresses);
                });
            });
        });
        router.get('/v1/balance/', (req, res) => {
            getServerWithAuth(req, res, server => {
                const 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, (err, balance) => {
                    if (err)
                        return returnError(err, res, req);
                    res.json(balance);
                });
            });
        });
        let estimateFeeLimiter;
        if (Defaults.RateLimit.estimateFee && !opts.ignoreRateLimiter) {
            logger_1.logger.info('Limiting estimate fee per IP: %o req/h', ((Defaults.RateLimit.estimateFee.max / Defaults.RateLimit.estimateFee.windowMs) * 60 * 60 * 1000).toFixed(2));
            estimateFeeLimiter = new RateLimit(Defaults.RateLimit.estimateFee);
        }
        else {
            estimateFeeLimiter = (req, res, next) => {
                next();
            };
        }
        router.get('/v1/feelevels/', estimateFeeLimiter, (req, res) => {
            SetPublicCache(res, 1 * ONE_MINUTE);
            logDeprecated(req);
            const opts = {};
            if (req.query.network)
                opts.network = req.query.network;
            let server;
            try {
                server = getServer(req, res);
            }
            catch (ex) {
                return returnError(ex, res, req);
            }
            server.getFeeLevels(opts, (err, feeLevels) => {
                if (err)
                    return returnError(err, res, req);
                lodash_1.default.each(feeLevels, feeLevel => {
                    feeLevel.feePerKB = feeLevel.feePerKb;
                    delete feeLevel.feePerKb;
                });
                res.json(feeLevels);
            });
        });
        router.get('/v2/feelevels/', (req, res) => {
            const opts = {};
            SetPublicCache(res, 1 * ONE_MINUTE);
            if (req.query.coin)
                opts.coin = req.query.coin;
            if (req.query.chain || req.query.coin)
                opts.chain = (req.query.chain || req.query.coin);
            if (req.query.network)
                opts.network = req.query.network;
            let server;
            try {
                server = getServer(req, res);
            }
            catch (ex) {
                return returnError(ex, res, req);
            }
            server.getFeeLevels(opts, (err, feeLevels) => {
                if (err)
                    return returnError(err, res, req);
                res.json(feeLevels);
            });
        });
        router.post('/v3/estimateGas/', (req, res) => {
            getServerWithAuth(req, res, async (server) => {
                try {
                    const gasLimit = await server.estimateGas(req.body);
                    res.json(gasLimit);
                }
                catch (err) {
                    returnError(err, res, req);
                }
            });
        });
        router.post('/v1/ethmultisig/', (req, res) => {
            getServerWithAuth(req, res, async (server) => {
                try {
                    const multisigContractInstantiationInfo = await server.getMultisigContractInstantiationInfo(req.body);
                    res.json(multisigContractInstantiationInfo);
                }
                catch (err) {
                    returnError(err, res, req);
                }
            });
        });
        router.post('/v1/ethmultisig/info', (req, res) => {
            getServerWithAuth(req, res, async (server) => {
                try {
                    const multisigContractInfo = await server.getMultisigContractInfo(req.body);
                    res.json(multisigContractInfo);
                }
                catch (err) {
                    returnError(err, res, req);
                }
            });
        });
        router.post('/v1/multisig/', (req, res) => {
            getServerWithAuth(req, res, async (server) => {
                try {
                    const multisigContractInstantiationInfo = await server.getMultisigContractInstantiationInfo(req.body);
                    res.json(multisigContractInstantiationInfo);
                }
                catch (err) {
                    returnError(err, res, req);
                }
            });
        });
        router.post('/v1/multisig/info', (req, res) => {
            getServerWithAuth(req, res, async (server) => {
                try {
                    const multisigContractInfo = await server.getMultisigContractInfo(req.body);
                    res.json(multisigContractInfo);
                }
                catch (err) {
                    returnError(err, res, req);
                }
            });
        });
        router.post('/v1/token/info', (req, res) => {
            getServerWithAuth(req, res, async (server) => {
                try {
                    const tokenContractInfo = await server.getTokenContractInfo(req.body);
                    res.json(tokenContractInfo);
                }
                catch (err) {
                    returnError(err, res, req);
                }
            });
        });
        router.get('/v1/sendmaxinfo/', (req, res) => {
            getServerWithAuth(req, res, server => {
                const q = req.query;
                const opts = {};
                if (q.feePerKb)
                    opts.feePerKb = +q.feePerKb;
                if (q.feeLevel)
                    opts.feeLevel = Number(q.feeLevel);
                if (q.excludeUnconfirmedUtxos == '1')
                    opts.excludeUnconfirmedUtxos = true;
                if (q.returnInputs == '1')
                    opts.returnInputs = true;
                server.getSendMaxInfo(opts, (err, info) => {
                    if (err)
                        return returnError(err, res, req);
                    res.json(info);
                });
            });
        });
        router.get('/v1/utxos/', (req, res) => {
            const opts = {};
            const addresses = req.query.addresses;
            if (addresses && lodash_1.default.isString(addresses))
                opts.addresses = req.query.addresses.split(',');
            getServerWithAuth(req, res, server => {
                server.getUtxos(opts, (err, utxos) => {
                    if (err)
                        return returnError(err, res, req);
                    res.json(utxos);
                });
            });
        });
        router.get('/v1/txcoins/', (req, res) => {
            const txId = req.query.txId;
            getServerWithAuth(req, res, server => {
                server.getCoinsForTx({ txId }, (err, coins) => {
                    if (err)
                        return returnError(err, res, req);
                    res.json(coins);
                });
            });
        });
        router.post('/v1/broadcast_raw/', (req, res) => {
            getServerWithAuth(req, res, server => {
                server.broadcastRawTx(req.body, (err, txid) => {
                    if (err)
                        return returnError(err, res, req);
                    res.json(txid);
                    res.end();
                });
            });
        });
        router.post('/v1/txproposals/:id/signatures/', (req, res) => {
            getServerWithAuth(req, res, server => {
                req.body.maxTxpVersion = 3;
                req.body.txProposalId = req.params['id'];
                server.signTx(req.body, (err, txp) => {
                    if (err)
                        return returnError(err, res, req);
                    res.json(txp);
                    res.end();
                });
            });
        });
        router.post('/v2/txproposals/:id/signatures/', (req, res) => {
            getServerWithAuth(req, res, server => {
                req.body.txProposalId = req.params['id'];
                req.body.maxTxpVersion = 3;
                req.body.supportBchSchnorr = true;
                server.signTx(req.body, (err, txp) => {
                    if (err)
                        return returnError(err, res, req);
                    res.json(txp);
                    res.end();
                });
            });
        });
        router.post('/v1/txproposals/:id/publish/', (req, res) => {
            getServerWithAuth(req, res, server => {
                req.body.txProposalId = req.params['id'];
                req.body.noCashAddr = true;
                server.publishTx(req.body, (err, txp) => {
                    if (err)
                        return returnError(err, res, req);
                    res.json(txp);
                    res.end();
                });
            });
        });
        router.post('/v2/txproposals/:id/publish/', (req, res) => {
            getServerWithAuth(req, res, server => {
                req.body.txProposalId = req.params['id'];
                server.publishTx(req.body, (err, txp) => {
                    if (err)
                        return returnError(err, res, req);
                    res.json(txp);
                    res.end();
                });
            });
        });
        router.post('/v1/txproposals/:id/broadcast/', (req, res) => {
            getServerWithAuth(req, res, server => {
                req.body.txProposalId = req.params['id'];
                server.broadcastTx(req.body, (err, txp) => {
                    if (err)
                        return returnError(err, res, req);
                    res.json(txp);
                    res.end();
                });
            });
        });
        router.post('/v1/txproposals/:id/rejections', (req, res) => {
            getServerWithAuth(req, res, server => {
                req.body.txProposalId = req.params['id'];
                server.rejectTx(req.body, (err, txp) => {
                    if (err)
                        return returnError(err, res, req);
                    res.json(txp);
                    res.end();
                });
            });
        });
        router.delete('/v1/txproposals/:id/', (req, res) => {
            getServerWithAuth(req, res, server => {
                req.body.txProposalId = req.params['id'];
                server.removePendingTx(req.body, err => {
                    if (err)
                        return returnError(err, res, req);
                    res.json({
                        success: true
                    });
                    res.end();
                });
            });
        });
        router.get('/v1/txproposals/:id/', (req, res) => {
            getServerWithAuth(req, res, server => {
                req.body.txProposalId = req.params['id'];
                server.getTx(req.body, (err, tx) => {
                    if (err)
                        return returnError(err, res, req);
                    res.json(tx);
                    res.end();
                });
            });
        });
        router.get('/v1/txproposalsbyhash/:id/', (req, res) => {
            getServerWithAuth(req, res, server => {
                req.body.txid = req.params['id'];
                server.getTxByHash(req.body, (err, tx) => {
                    if (err)
                        return returnError(err, res, req);
                    res.json(tx);
                    res.end();
                });
            });
        });
        router.get('/v1/txhistory/', (req, res) => {
            getServerWithAuth(req, res, server => {
                const 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, (err, txs) => {
                    if (err)
                        return returnError(err, res, req);
                    res.json(txs);
                    res.end();
                });
            });
        });
        router.post('/v1/addresses/scan/', (req, res) => {
            getServerWithAuth(req, res, server => {
                req.body = req.body || {};
                req.body.startIdx = server.copayerIsSupportStaff ? Number(req.body.startIdx) : null;
                server.startScan(req.body, (err, started) => {
                    if (err)
                        return returnError(err, res, req);
                    res.json(started);
                    res.end();
                });
            });
        });
        router.get('/v1/stats/', (req, res) => {
            SetPublicCache(res, 1 * ONE_MINUTE);
            const 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;
            const stats = new stats_1.Stats(opts);
            stats.run((err, data) => {
                if (err)
                    return returnError(err, res, req);
                res.json(data);
                res.end();
            });
        });
        router.get('/v1/version/', (req, res) => {
            SetPublicCache(res, 1 * ONE_MINUTE);
            res.json({
                serviceVersion: server_1.WalletService.getServiceVersion()
            });
            res.end();
        });
        router.post('/v1/login/', (req, res) => {
            getServerWithAuth(req, res, server => {
                server.login({}, (err, session) => {
                    if (err)
                        return returnError(err, res, req);
                    res.json(session);
                });
            });
        });
        router.post('/v1/logout/', (req, res) => {
            getServerWithAuth(req, res, server => {
                server.logout({}, err => {
                    if (err)
                        return returnError(err, res, req);
                    res.end();
                });
            });
        });
        router.get('/v1/notifications/', (req, res) => {
            getServerWithAuth(req, res, {
                allowSession: true
            }, server => {
                const timeSpan = req.query.timeSpan
                    ? Math.min(+req.query.timeSpan || 0, Defaults.MAX_NOTIFICATIONS_TIMESPAN)
                    : Defaults.NOTIFICATIONS_TIMESPAN;
                const opts = {
                    minTs: +Date.now() - timeSpan * 1000,
                    notificationId: req.query.notificationId
                };
                server.getNotifications(opts, (err, notifications) => {
                    if (err)
                        return returnError(err, res, req);
                    res.json(notifications);
                });
            });
        });
        router.get('/v1/txnotes/:txid', (req, res) => {
            getServerWithAuth(req, res, server => {
                const opts = {
                    txid: req.params['txid']
                };
                server.getTxNote(opts, (err, note) => {
                    if (err)
                        return returnError(err, res, req);
                    res.json(note);
                });
            });
        });
        router.put('/v1/txnotes/:txid/', (req, res) => {
            req.body.txid = req.params['txid'];
            getServerWithAuth(req, res, server => {
                server.editTxNote(req.body, (err, note) => {
                    if (err)
                        return returnError(err, res, req);
                    res.json(note);
                });
            });
        });
        router.get('/v1/txnotes/', (req, res) => {
            getServerWithAuth(req, res, server => {
                const opts = {};
                if (req.query.minTs && lodash_1.default.isNumber(+req.query.minTs)) {
                    opts.minTs = +req.query.minTs;
                }
                server.getTxNotes(opts, (err, notes) => {
                    if (err)
                        return returnError(err, res, req);
                    res.json(notes);
                });
            });
        });
        router.get('/v1/nonce/:address', (req, res) => {
            getServerWithAuth(req, res, async (server) => {
                const opts = {
                    coin: req.query.coin || 'eth',
                    chain: req.query.chain,
                    network: req.query.network || 'livenet',
                    address: req.params['address']
                };
                try {
                    const nonce = await server.getNonce(opts);
                    res.json(nonce);
                }
                catch (err) {
                    returnError(err, res, req);
                }
            });
        });
        router.post('/v1/clearcache/', (req, res) => {
            getServerWithAuth(req, res, server => {
                const opts = req.query;
                server.clearWalletCache(opts).then(val => {
                    if (val) {
                        res.sendStatus(200);
                    }
                    else {
                        res.sendStatus(500);
                    }
                });
            });
        });
        router.get('/v1/fiatrates/:code/', (req, res) => {
            SetPublicCache(res, 5 * ONE_MINUTE);
            let server;
            const opts = {
                code: req.params['code'],
                coin: req.query.coin || 'btc',
                ts: req.query.ts ? +req.query.ts : null
            };
            try {
                server = getServer(req, res);
            }
            catch (ex) {
                return returnError(ex, res, req);
            }
            server.getFiatRate(opts, (err, rates) => {
                if (err)
                    return returnError(err, res, req);
                res.json(rates);
            });
        });
        router.get('/v2/fiatrates/:code/', (req, res) => {
            SetPublicCache(res, 5 * ONE_MINUTE);
            let server;
            const opts = {
                code: req.params['code'],
                ts: req.query.ts ? +req.query.ts : null
            };
            try {
                server = getServer(req, res);
            }
            catch (ex) {
                return returnError(ex, res, req);
            }
            server.getHistoricalRates(opts, (err, rates) => {
                if (err)
                    return returnError(err, res, req);
                res.json(rates);
            });
        });
        router.get('/v3/fiatrates/', (req, res) => {
            SetPublicCache(res, 5 * ONE_MINUTE);
            let server;
            const opts = {
                code: req.query.code || null,
                ts: req.query.ts ? +req.query.ts : null
            };
            try {
                server = getServer(req, res);
            }
            catch (ex) {
                return returnError(ex, res, req);
            }
            server.getFiatRates(opts, (err, rates) => {
                if (err)
                    return returnError(err, res, req);
                res.json(rates);
            });
        });
        router.get('/v3/fiatrates/:coin/', (req, res) => {
            SetPublicCache(res, 5 * ONE_MINUTE);
            let server;
            const opts = {
                coin: req.params['coin'],
                code: req.query.code || null,
                ts: req.query.ts ? +req.query.ts : null
            };
            try {
                server = getServer(req, res);
            }
            catch (ex) {
                return returnError(ex, res, req);
            }
            server.getFiatRatesByCoin(opts, (err, rates) => {
                if (err)
                    return returnError(err, res, req);
                res.json(rates);
            });
        });
        router.post('/v1/pushnotifications/subscriptions/', (req, res) => {
            getServerWithAuth(req, res, server => {
                server.pushNotificationsSubscribe(req.body, (err, response) => {
                    if (err)
                        return returnError(err, res, req);
                    res.json(response);
                });
            });
        });
        router.post('/v2/pushnotifications/subscriptions/', (req, res) => {
            getServerWithAuth(req, res, server => {
                server.pushNotificationsBrazeSubscribe(req.body, (err, response) => {
                    if (err)
                        return returnError(err, res, req);
                    res.json(response);
                });
            });
        });
        router.delete('/v1/pushnotifications/subscriptions/', (req, res) => {
            logDeprecated(req);
            getServerWithAuth(req, res, server => {
                server.pushNotificationsUnsubscribe({
                    token: 'dummy'
                }, (err, response) => {
                    if (err)
                        return returnError(err, res, req);
                    res.json(response);
                });
            });
        });
        router.delete('/v2/pushnotifications/subscriptions/:token', (req, res) => {
            const opts = {
                token: req.params['token']
            };
            getServerWithAuth(req, res, server => {
                server.pushNotificationsUnsubscribe(opts, (err, response) => {
                    if (err)
                        return returnError(err, res, req);
                    res.json(response);
                });
            });
        });
        router.delete('/v3/pushnotifications/subscriptions/:externalUserId', (req, res) => {
            const opts = {
                externalUserId: req.params['externalUserId']
            };
            getServerWithAuth(req, res, server => {
                server.pushNotificationsBrazeUnsubscribe(opts, (err, response) => {
                    if (err)
                        return returnError(err, res, req);
                    res.json(response);
                });
            });
        });
        router.post('/v1/txconfirmations/', (req, res) => {
            getServerWithAuth(req, res, server => {
                server.txConfirmationSubscribe(req.body, (err, response) => {
                    if (err)
                        return returnError(err, res, req);
                    res.json(response);
                });
            });
        });
        router.delete('/v1/txconfirmations/:txid', (req, res) => {
            const opts = {
                txid: req.params['txid']
            };
            getServerWithAuth(req, res, server => {
                server.txConfirmationUnsubscribe(opts, (err, response) => {
                    if (err)
                        return returnError(err, res, req);
                    res.json(response);
                });
            });
        });
        router.get('/v1/services', (req, res) => {
            let server;
            try {
                server = getServer(req, res);
            }
            catch (ex) {
                return returnError(ex, res, req);
            }
            const opts = req.query;
            server.getServicesData(opts, (err, response) => {
                if (err)
                    return returnError(err, res, req);
                res.json(response);
            });
        });
        router.post('/v1/service/checkAvailability', (req, res) => {
            let server, response;
            try {
                server = getServer(req, res);
                response = server.checkServiceAvailability(req);
                return res.json(response);
            }
            catch (ex) {
                return returnError(ex, res, req);
            }
        });
        router.post('/v1/service/banxa/getCoins', async (req, res) => {
            let server, response;
            try {
                server = getServer(req, res);
                response = await server.externalServices.banxa.banxaGetCoins(req);
                return res.json(response);
            }
            catch (ex) {
                return returnError(ex, res, req);
            }
        });
        router.post('/v1/service/banxa/paymentMethods', async (req, res) => {
            let server, response;
            try {
                server = getServer(req, res);
                response = await server.externalServices.banxa.banxaGetPaymentMethods(req);
                return res.json(response);
            }
            catch (ex) {
                return returnError(ex, res, req);
            }
        });
        router.post('/v1/service/banxa/quote', (req, res) => {
            getServerWithAuth(req, res, async (server) => {
                let response;
                try {
                    response = await server.externalServices.banxa.banxaGetQuote(req);
                    return res.json(response);
                }
                catch (ex) {
                    return returnError(ex, res, req);
                }
            });
        });
        router.post('/v1/service/banxa/createOrder', (req, res) => {
            getServerWithAuth(req, res, async (server) => {
                let response;
                try {
                    response = await server.externalServices.banxa.banxaCreateOrder(req);
                    return res.json(response);
                }
                catch (ex) {
                    return returnError(ex, res, req);
                }
            });
        });
        router.post('/v1/service/banxa/getOrder', async (req, res) => {
            let server, response;
            try {
                server = getServer(req, res);
                response = await server.externalServices.banxa.banxaGetOrder(req);
                return res.json(response);
            }
            catch (ex) {
                return returnError(ex, res, req);
            }
        });
        router.post('/v1/service/moonpay/getCurrencies', async (req, res) => {
            let server, response;
            try {
                server = getServer(req, res);
                response = await server.externalServices.moonpay.moonpayGetCurrencies(req);
                return res.json(response);
            }
            catch (ex) {
                return returnError(ex, res, req);
            }
        });
        router.post('/v1/service/moonpay/quote', (req, res) => {
            getServerWithAuth(req, res, async (server) => {
                let response;
                try {
                    response = await server.externalServices.moonpay.moonpayGetQuote(req);
                    return res.json(response);
                }
                catch (ex) {
                    return returnError(ex, res, req);
                }
            });
        });
        router.post('/v1/service/moonpay/sellQuote', (req, res) => {
            getServerWithAuth(req, res, async (server) => {
                let response;
                try {
                    response = await server.externalServices.moonpay.moonpayGetSellQuote(req);
                    return res.json(response);
                }
                catch (ex) {
                    return returnError(ex, res, req);
                }
            });
        });
        router.post('/v1/service/moonpay/currencyLimits', async (req, res) => {
            let server, response;
            try {
                server = getServer(req, res);
                response = await server.externalServices.moonpay.moonpayGetCurrencyLimits(req);
                return res.json(response);
            }
            catch (ex) {
                return returnError(ex, res, req);
            }
        });
        router.post('/v1/service/moonpay/signedPaymentUrl', (req, res) => {
            getServerWithAuth(req, res, server => {
                let response;
                try {
                    response = server.externalServices.moonpay.moonpayGetSignedPaymentUrl(req);
                    return res.json(response);
                }
                catch (ex) {
                    return returnError(ex, res, req);
                }
            });
        });
        router.post('/v1/service/moonpay/sellSignedPaymentUrl', (req, res) => {
            getServerWithAuth(req, res, async (server) => {
                let response;
                try {
                    response = await server.externalServices.moonpay.moonpayGetSellSignedPaymentUrl(req);
                    return res.json(response);
                }
                catch (ex) {
                    return returnError(ex, res, req);
                }
            });
        });
        router.post('/v1/service/moonpay/transactionDetails', async (req, res) => {
            let server, response;
            try {
                server = getServer(req, res);
                response = await server.externalServices.moonpay.moonpayGetTransactionDetails(req);
                return res.json(response);
            }
            catch (ex) {
                return returnError(ex, res, req);
            }
        });
        router.post('/v1/service/moonpay/sellTransactionDetails', async (req, res) => {
            let server, response;
            try {
                server = getServer(req, res);
                response = await server.externalServices.moonpay.moonpayGetSellTransactionDetails(req);
                return res.json(response);
            }
            catch (ex) {
                return returnError(ex, res, req);
            }
        });
        router.post('/v1/service/moonpay/cancelSellTransaction', (req, res) => {
            getServerWithAuth(req, res, async (server) => {
                let response;
                try {
                    response = await server.externalServices.moonpay.moonpayCancelSellTransaction(req);
                    return res.json(response);
                }
                catch (ex) {
                    return returnError(ex, res, req);
                }
            });
        });
        router.post('/v1/service/moonpay/accountDetails', async (req, res) => {
            let server, response;
            try {
                server = getServer(req, res);
                response = await server.externalServices.moonpay.moonpayGetAccountDetails(req);
                return res.json(response);
            }
            catch (ex) {
                return returnError(ex, res, req);
            }
        });
        router.post('/v1/service/ramp/quote', (req, res) => {
            getServerWithAuth(req, res, async (server) => {
                let response;
                try {
                    response = await server.externalServices.ramp.rampGetQuote(req);
                    return res.json(response);
                }
                catch (ex) {
                    return returnError(ex, res, req);
                }
            });
        });
        router.post('/v1/service/ramp/sellQuote', (req, res) => {
            getServerWithAuth(req, res, async (server) => {
                let response;
                try {
                    response = await server.externalServices.ramp.rampGetSellQuote(req);
                    return res.json(response);
                }
                catch (ex) {
                    return returnError(ex, res, req);
                }
            });
        });
        router.post('/v1/service/ramp/signedPaymentUrl', (req, res) => {
            getServerWithAuth(req, res, async (server) => {
                let response;
                try {
                    response = await server.externalServices.ramp.rampGetSignedPaymentUrl(req);
                    return res.json(response);
                }
                catch (ex) {
                    return returnError(ex, res, req);
                }
            });
        });
        router.post('/v1/service/ramp/assets', async (req, res) => {
            let server, response;
            try {
                server = getServer(req, res);
                response = await server.externalServices.ramp.rampGetAssets(req);
                return res.json(response);
            }
            catch (ex) {
                return returnError(ex, res, req);
            }
        });
        router.post('/v1/service/ramp/sellTransactionDetails', async (req, res) => {
            let server, response;
            try {
                server = getServer(req, res);
                response = await server.externalServices.ramp.rampGetSellTransactionDetails(req);
                return res.json(response);
            }
            catch (ex) {
                return returnError(ex, res, req);
            }
        });
        router.post('/v1/service/sardine/quote', (req, res) => {
            getServerWithAuth(req, res, server => {
                server.externalServices.sardine
                    .sardineGetQuote(req)
                    .then(response => {
                    res.json(response);
                })
                    .catch(err => {
                    return returnError(err ?? 'unknown', res, req);
                });
            });
        });
        router.post('/v1/service/sardine/getToken', (req, res) => {
            getServerWithAuth(req, res, server => {
                server.externalServices.sardine
                    .sardineGetToken(req)
                    .then(response => {
                    res.json(response);
                })
                    .catch(err => {
                    return returnError(err ?? 'unknown', res, req);
                });
            });
        });
        router.post('/v1/service/sardine/getSupportedTokens', async (req, res) => {
            let server, response;
            try {
                server = getServer(req, res);
                response = await server.externalServices.sardine.sardineGetSupportedTokens(req);
                return res.json(response);
            }
            catch (ex) {
                return returnError(ex, res, req);
            }
        });
        router.post('/v1/service/sardine/currencyLimits', (req, res) => {
            let server;
            try {
                server = getServer(req, res);
            }
            catch (ex) {
                return returnError(ex, res, req);
            }
            server.externalServices.sardine
                .sardineGetCurrencyLimits(req)
                .then(response => {
                res.json(response);
            })
                .catch(err => {
                return returnError(err ?? 'unknown', res, req);
            });
        });
        router.post('/v1/service/sardine/ordersDetails', (req, res) => {
            let server;
            try {
                server = getServer(req, res);
            }
            catch (ex) {
                return returnError(ex, res, req);
            }
            server.externalServices.sardine
                .sardineGetOrdersDetails(req)
                .then(response => {
                res.json(response);
            })
                .catch(err => {
                return returnError(err ?? 'unknown', res, req);
            });
        });
        router.post('/v1/service/simplex/getCurrencies', (req, res) => {
            let server;
            try {
                server = getServer(req, res);
            }
            catch (ex) {
                return returnError(ex, res, req);
            }
            server.externalServices.simplex
                .simplexGetCurrencies(req)
                .then(response => {
                res.json(response);
            })
                .catch(err => {
                return returnError(err ?? 'unknown', res, req);
            });
        });
        router.post('/v1/service/simplex/quote', (req, res) => {
            getServerWithAuth(req, res, server => {
                server.externalServices.simplex
                    .simplexGetQuote(req)
                    .then(response => {
                    res.json(response);
                })
                    .catch(err => {
                    return returnError(err ?? 'unknown', res, req);
                });
            });
        });
        router.post('/v1/service/simplex/sellQuote', (req, res) => {
            getServerWithAuth(req, res, server => {
                server.externalServices.simplex
                    .simplexGetSellQuote(req)
                    .then(response => {
                    res.json(response);
                })
                    .catch(err => {
                    return returnError(err ?? 'unknown', res, req);
                });
            });
        });
        router.post('/v1/service/simplex/paymentRequest', (req, res) => {
            getServerWithAuth(req, res, server => {
                server.externalServices.simplex
                    .simplexPaymentRequest(req)
                    .then(response => {
                    res.json(response);
                })
                    .catch(err => {
                    return returnError(err ?? 'unknown', res, req);
                });
            });
        });
        router.post('/v1/service/simplex/sellPaymentRequest', (req, res) => {
            getServerWithAuth(req, res, server => {
                server.externalServices.simplex
                    .simplexSellPaymentRequest(req)
                    .then(response => {
                    res.json(response);
                })
                    .catch(err => {
                    return returnError(err ?? 'unknown', res, req);
                });
            });
        });
        router.get('/v1/service/simplex/events', (req, res) => {
            getServerWithAuth(req, res, server => {
                const opts = { env: req.query.env };
                server.externalServices.simplex
                    .simplexGetEvents(opts)
                    .then(response => {
                    res.json(response);
                })
                    .catch(err => {
                    return returnError(err ?? 'unknown', res, req);
                });
            });
        });
        router.post('/v1/service/thorswap/supportedChains', (req, res) => {
            let server;
            try {
                server = getServer(req, res);
            }
            catch (ex) {
                return returnError(ex, res, req);
            }
            server.externalServices.thorswap
                .thorswapGetSupportedChains(req)
                .then(response => {
                res.json(response);
            })
                .catch(err => {
                return returnError(err ?? 'unknown', res, req);
            });
        });
        router.post('/v1/service/thorswap/cryptoCurrencies', (req, res) => {
            let server;
            try {
                server = getServer(req, res);
            }
            catch (ex) {
                return returnError(ex, res, req);
            }
            server.externalServices.thorswap
                .thorswapGetCryptoCurrencies(req)
                .then(response => {
                res.json(response);
            })
                .catch(err => {
                return returnError(err ?? 'unknown', res, req);
            });
        });
        router.post('/v1/service/thorswap/getSwapQuote', (req, res) => {
            getServerWithAuth(req, res, async (server) => {
                let response;
                try {
                    response = await server.externalServices.thorswap.thorswapGetSwapQuote(req);
                    return res.json(response);
                }
                catch (ex) {
                    return returnError(ex, res, req);
                }
            });
        });
        router.post('/v1/service/thorswap/getSwapTx', (req, res) => {
            let server;
            try {
                server = getServer(req, res);
            }
            catch (ex) {
                return returnError(ex, res, req);
            }
            server.externalServices.thorswap
                .thorswapGetSwapTx(req)
                .then(response => {
                res.json(response);
            })
                .catch(err => {
                return returnError(err ?? 'unknown', res, req);
            });
        });
        router.post('/v1/service/transak/getAccessToken', (req, res) => {
            getServerWithAuth(req, res, async (server) => {
                let response;
                try {
                    response = await server.externalServices.transak.transakGetAccessToken(req);
                    return res.json(response);
                }
                catch (ex) {
                    return returnError(ex, res, req);
                }
            });
        });
        router.post('/v1/service/transak/cryptoCurrencies', (req, res) => {
            let server;
            try {
                server = getServer(req, res);
            }
            catch (ex) {
                return returnError(ex, res, req);
            }
            server.externalServices.transak
                .transakGetCryptoCurrencies(req)
                .then(response => {
                res.json(response);
            })
                .catch(err => {
                return returnError(err ?? 'unknown', res, req);
            });
        });
        router.post('/v1/service/transak/fiatCurrencies', (req, res) => {
            let server;
            try {
                server = getServer(req, res);
            }
            catch (ex) {
                return returnError(ex, res, req);
            }
            server.externalServices.transak
                .transakGetFiatCurrencies(req)
                .then(response => {
                res.json(response);
            })
                .catch(err => {
                return returnError(err ?? 'unknown', res, req);
            });
        });
        router.post('/v1/service/transak/quote', (req, res) => {
            getServerWithAuth(req, res, async (server) => {
                let response;
                try {
                    response = await server.externalServices.transak.transakGetQuote(req);
                    return res.json(response);
                }
                catch (ex) {
                    return returnError(ex, res, req);
                }
            });
        });
        router.post('/v1/service/transak/signedPaymentUrl', (req, res) => {
            getServerWithAuth(req, res, async (server) => {
                let response;
                try {
                    response = await server.externalServices.transak.transakGetSignedPaymentUrl(req);
                    return res.json(response);
                }
                catch (ex) {
                    return returnError(ex, res, req);
                }
            });
        });
        router.post('/v1/service/transak/orderDetails', (req, res) => {
            let server;
            try {
                server = getServer(req, res);
            }
            catch (ex) {
                return returnError(ex, res, req);
            }
            server.externalServices.transak
                .transakGetOrderDetails(req)
                .then(response => {
                res.json(response);
            })
                .catch(err => {
                return returnError(err ?? 'unknown', res, req);
            });
        });
        router.post('/v1/service/wyre/walletOrderQuotation', (req, res) => {
            getServerWithAuth(req, res, server => {
                server.externalServices.wyre
                    .wyreWalletOrderQuotation(req)
                    .then(response => {
                    res.json(response);
                })
                    .catch(err => {
                    return returnError(err ?? 'unknown', res, req);
                });
            });
        });
        router.post('/v1/service/wyre/walletOrderReservation', (req, res) => {
            getServerWithAuth(req, res, server => {
                server.externalServices.wyre
                    .wyreWalletOrderReservation(req)
                    .then(response => {
                    res.json(response);
                })
                    .catch(err => {
                    return returnError(err ?? 'unknown', res, req);
                });
            });
        });
        router.post('/v1/service/changelly/getCurrencies', (req, res) => {
            let server;
            try {
                server = getServer(req, res);
            }
            catch (ex) {
                return returnError(ex, res, req);
            }
            server.externalServices.changelly
                .changellyGetCurrencies(req)
                .then(response => {
                res.json(response);
            })
                .catch(err => {
                return returnError(err ?? 'unknown', res, req);
            });
        });
        router.post('/v1/service/changelly/getPairsParams', (req, res) => {
            getServerWithAuth(req, res, server => {
                server.externalServices.changelly
                    .changellyGetPairsParams(req)
                    .then(response => {
                    res.json(response);
                })
                    .catch(err => {
                    return returnError(err ?? 'unknown', res, req);
                });
            });
        });
        router.post('/v1/service/changelly/getFixRateForAmount', (req, res) => {
            getServerWithAuth(req, res, server => {
                server.externalServices.changelly
                    .changellyGetFixRateForAmount(req)
                    .then(response => {
                    res.json(response);
                })
                    .catch(err => {
                    return returnError(err ?? 'unknown', res, req);
                });
            });
        });
        router.post('/v1/service/changelly/createFixTransaction', (req, res) => {
            getServerWithAuth(req, res, server => {
                server.externalServices.changelly
                    .changellyCreateFixTransaction(req)
                    .then(response => {
                    res.json(response);
                })
                    .catch(err => {
                    return returnError(err ?? 'unknown', res, req);
                });
            });
        });
        router.post('/v1/service/changelly/getTransactions', (req, res) => {
            let server;
            try {
                server = getServer(req, res);
            }
            catch (ex) {
                return returnError(ex, res, req);
            }
            server.externalServices.changelly
                .changellyGetTransactions(req)
                .then(response => {
                res.json(response);
            })
                .catch(err => {
                return returnError(err ?? 'unknown', res, req);
            });
        });
        router.post('/v1/service/changelly/getStatus', (req, res) => {
            let server;
            try {
                server = getServer(req, res);
            }
            catch (ex) {
                return returnError(ex, res, req);
            }
            server.externalServices.changelly
                .changellyGetStatus(req)
                .then(response => {
                res.json(response);
            })
                .catch(err => {
                return returnError(err ?? 'unknown', res, req);
            });
        });
        router.get('/v1/service/oneInch/getReferrerFee', (req, res) => {
            let server;
            try {
                server = getServer(req, res);
            }
            catch (ex) {
                return returnError(ex, res, req);
            }
            server.externalServices.oneInch
                .oneInchGetReferrerFee(req)
                .then(response => {
                res.json(response);
            })
                .catch(err => {
                return returnError(err ?? 'unknown', res, req);
            });
        });
        router.post('/v1/service/oneInch/getSwap/:chain?', (req, res) => {
            getServerWithAuth(req, res, server => {
                server.externalServices.oneInch
                    .oneInchGetSwap(req)
                    .then(response => {
                    res.json(response);
                })
                    .catch(err => {
                    return returnError(err ?? 'unknown', res, req);
                });
            });
        });
        router.get('/v1/service/oneInch/getTokens/:chain?', (req, res) => {
            SetPublicCache(res, 1 * ONE_MINUTE);
            let server;
            try {
                server = getServer(req, res);
            }
            catch (ex) {
                return returnError(ex, res, req);
            }
            server.coinGeckoGetTokens(req)
                .then(response => {
                res.json(response);
            })
                .catch(err => {
                return returnError(err ?? 'unknown', res, req);
            });
        });
        router.get('/v1/services/dex/getSpenderApprovalWhitelist', (req, res) => {
            let server;
            try {
                server = getServer(req, res);
            }
            catch (ex) {
                return returnError(ex, res, req);
            }
            server.getSpenderApprovalWhitelist((err, response) => {
                if (err)
                    return returnError(err, res, req);
                res.json(response);
            });
        });
        router.get('/v1/service/payId/:payId', (req, res) => {
            let server;
            const payId = req.params['payId'];
            const opts = {
                handle: payId.split('$')[0],
                domain: payId.split('$')[1]
            };
            try {
                server = getServer(req, res);
            }
            catch (ex) {
                return returnError(ex, res, req);
            }
            server
                .discoverPayId(opts)
                .then(response => {
                res.json(response);
            })
                .catch(err => {
                return returnError(err ?? 'unknown', res, req);
            });
        });
        const moralisCorsOptions = {
            origin: (origin, cb) => {
                const moralisWhiteList = config_1.default.moralis?.whitelist ?? [];
                if (moralisWhiteList.indexOf(origin) !== -1) {
                    cb(null, true);
                }
                else {
                    cb(new Error('Not allowed by CORS'));
                }
            },
        };
        router.post('/v1/moralis/getWalletTokenBalances', (0, cors_1.default)(moralisCorsOptions), (req, res) => {
            let server;
            try {
                server = getServer(req, res);
            }
            catch (ex) {
                return returnError(ex, res, req);
            }
            server.moralisGetWalletTokenBalances(req)
                .then(response => {
                res.json(response);
            })
                .catch(err => {
                return returnError(err ?? 'unknown', res, req);
            });
        });
        router.post('/v1/moralis/moralisGetTokenAllowance', (0, cors_1.default)(moralisCorsOptions), (req, res) => {
            let server;
            try {
                server = getServer(req, res);
            }
            catch (ex) {
                return returnError(ex, res, req);
            }
            server.moralisGetTokenAllowance(req)
                .then(response => {
                res.json(response);
            })
                .catch(err => {
                return returnError(err ?? 'unknown', res, req);
            });
        });
        router.post('/v1/moralis/moralisGetNativeBalance', (0, cors_1.default)(moralisCorsOptions), (req, res) => {
            let server;
            try {
                server = getServer(req, res);
            }
            catch (ex) {
                return returnError(ex, res, req);
            }
            server.moralisGetNativeBalance(req)
                .then(response => {
                res.json(response);
            })
                .catch(err => {
                return returnError(err ?? 'unknown', res, req);
            });
        });
        router.post('/v1/moralis/GetTokenPrice', (0, cors_1.default)(moralisCorsOptions), (req, res) => {
            let server;
            try {
                server = getServer(req, res);
            }
            catch (ex) {
                return returnError(ex, res, req);
            }
            server.moralisGetTokenPrice(req)
                .then(response => {
                res.json(response);
            })
                .catch(err => {
                return returnError(err ?? 'unknown', res, req);
            });
        });
        router.post('/v1/moralis/getMultipleERC20TokenPrices', (0, cors_1.default)(moralisCorsOptions), (req, res) => {
            let server;
            try {
                server = getServer(req, res);
            }
            catch (ex) {
                return returnError(ex, res, req);
            }
            server.moralisGetMultipleERC20TokenPrices(req)
                .then(response => {
                res.json(response);
            })
                .catch(err => {
                return returnError(err ?? 'unknown', res, req);
            });
        });
        router.post('/v1/moralis/getERC20TokenBalancesWithPricesByWallet', (0, cors_1.default)(moralisCorsOptions), (req, res) => {
            let server;
            try {
                server = getServer(req, res);
            }
            catch (ex) {
                return returnError(ex, res, req);
            }
            server.moralisGetERC20TokenBalancesWithPricesByWallet(req)
                .then(response => {
                res.json(response);
            })
                .catch(err => {
                return returnError(err ?? 'unknown', res, req);
            });
        });
        router.post('/v1/moralis/getSolWalletPortfolio', (0, cors_1.default)(moralisCorsOptions), (req, res) => {
            let server;
            try {
                server = getServer(req, res);
            }
            catch (ex) {
                return returnError(ex, res, req);
            }
            server.moralisGetSolWalletPortfolio(req)
                .then(response => {
                res.json(response);
            })
                .catch(err => {
                return returnError(err ?? 'unknown', res, req);
            });
        });
        router.get('/v1/service/coinGecko/getRates/:contractAddresses/:altCurrencies/:chain', (req, res) => {
            SetPublicCache(res, 1 * ONE_MINUTE);
            let server;
            try {
                server = getServer(req, res);
            }
            catch (ex) {
                return returnError(ex, res, req);
            }
            server
                .coinGeckoGetRates(req)
                .then(response => {
                res.json(response);
            })
                .catch(err => {
                return returnError(err ?? 'unknown', res, req);
            });
        });
        this.app.use((req, res, next) => {
            res.setHeader('Cache-Control', 'no-store');
            next();
        });
        const staticPath = path_1.default.join(__dirname, '../../static');
        this.app.use('/bws/static', express_1.default.static(staticPath));
        this.app.use(opts.basePath || '/bws/api', router);
        if (config_1.default.staticRoot) {
            logger_1.logger.debug(`Serving static files from ${config_1.default.staticRoot}`);
            this.app.use('/static', express_1.default.static(config_1.default.staticRoot));
        }
        server_1.WalletService.initialize(opts, cb);
    }
}
exports.ExpressApp = ExpressApp;
//# sourceMappingURL=expressapp.js.map