@bitpay-labs/bitcore-wallet-service 11.8.1 → 11.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/package.json +2 -2
  2. package/src/bws.ts +2 -0
  3. package/src/lib/common/utils.ts +6 -0
  4. package/src/lib/expressapp.ts +63 -2378
  5. package/src/lib/model/txproposal.ts +14 -10
  6. package/src/lib/routes/advertisements.ts +151 -0
  7. package/src/lib/routes/blockchain.ts +152 -0
  8. package/src/lib/routes/context.ts +149 -0
  9. package/src/lib/routes/maintenance.ts +111 -0
  10. package/src/lib/routes/moralis.ts +89 -0
  11. package/src/lib/routes/notifications.ts +135 -0
  12. package/src/lib/routes/services.ts +528 -0
  13. package/src/lib/routes/setup.ts +86 -0
  14. package/src/lib/routes/transactions.ts +196 -0
  15. package/src/lib/routes/walletdata.ts +167 -0
  16. package/src/lib/routes/wallets.ts +289 -0
  17. package/src/lib/server.ts +24 -1
  18. package/src/lib/storage.ts +3 -0
  19. package/ts_build/package.json +4 -4
  20. package/ts_build/src/bws.js +3 -0
  21. package/ts_build/src/bws.js.map +1 -1
  22. package/ts_build/src/lib/common/index.d.ts +1 -0
  23. package/ts_build/src/lib/common/index.d.ts.map +1 -1
  24. package/ts_build/src/lib/common/utils.d.ts +1 -0
  25. package/ts_build/src/lib/common/utils.d.ts.map +1 -1
  26. package/ts_build/src/lib/common/utils.js +6 -0
  27. package/ts_build/src/lib/common/utils.js.map +1 -1
  28. package/ts_build/src/lib/expressapp.d.ts.map +1 -1
  29. package/ts_build/src/lib/expressapp.js +64 -2224
  30. package/ts_build/src/lib/expressapp.js.map +1 -1
  31. package/ts_build/src/lib/model/txproposal.d.ts +1 -4
  32. package/ts_build/src/lib/model/txproposal.d.ts.map +1 -1
  33. package/ts_build/src/lib/model/txproposal.js +13 -9
  34. package/ts_build/src/lib/model/txproposal.js.map +1 -1
  35. package/ts_build/src/lib/routes/advertisements.d.ts +11 -0
  36. package/ts_build/src/lib/routes/advertisements.d.ts.map +1 -0
  37. package/ts_build/src/lib/routes/advertisements.js +119 -0
  38. package/ts_build/src/lib/routes/advertisements.js.map +1 -0
  39. package/ts_build/src/lib/routes/blockchain.d.ts +13 -0
  40. package/ts_build/src/lib/routes/blockchain.d.ts.map +1 -0
  41. package/ts_build/src/lib/routes/blockchain.js +159 -0
  42. package/ts_build/src/lib/routes/blockchain.js.map +1 -0
  43. package/ts_build/src/lib/routes/context.d.ts +12 -0
  44. package/ts_build/src/lib/routes/context.d.ts.map +1 -0
  45. package/ts_build/src/lib/routes/context.js +115 -0
  46. package/ts_build/src/lib/routes/context.js.map +1 -0
  47. package/ts_build/src/lib/routes/maintenance.d.ts +10 -0
  48. package/ts_build/src/lib/routes/maintenance.d.ts.map +1 -0
  49. package/ts_build/src/lib/routes/maintenance.js +131 -0
  50. package/ts_build/src/lib/routes/maintenance.js.map +1 -0
  51. package/ts_build/src/lib/routes/moralis.d.ts +9 -0
  52. package/ts_build/src/lib/routes/moralis.d.ts.map +1 -0
  53. package/ts_build/src/lib/routes/moralis.js +78 -0
  54. package/ts_build/src/lib/routes/moralis.js.map +1 -0
  55. package/ts_build/src/lib/routes/notifications.d.ts +10 -0
  56. package/ts_build/src/lib/routes/notifications.d.ts.map +1 -0
  57. package/ts_build/src/lib/routes/notifications.js +120 -0
  58. package/ts_build/src/lib/routes/notifications.js.map +1 -0
  59. package/ts_build/src/lib/routes/services.d.ts +11 -0
  60. package/ts_build/src/lib/routes/services.d.ts.map +1 -0
  61. package/ts_build/src/lib/routes/services.js +430 -0
  62. package/ts_build/src/lib/routes/services.js.map +1 -0
  63. package/ts_build/src/lib/routes/setup.d.ts +4 -0
  64. package/ts_build/src/lib/routes/setup.d.ts.map +1 -0
  65. package/ts_build/src/lib/routes/setup.js +79 -0
  66. package/ts_build/src/lib/routes/setup.js.map +1 -0
  67. package/ts_build/src/lib/routes/transactions.d.ts +9 -0
  68. package/ts_build/src/lib/routes/transactions.d.ts.map +1 -0
  69. package/ts_build/src/lib/routes/transactions.js +188 -0
  70. package/ts_build/src/lib/routes/transactions.js.map +1 -0
  71. package/ts_build/src/lib/routes/walletdata.d.ts +10 -0
  72. package/ts_build/src/lib/routes/walletdata.d.ts.map +1 -0
  73. package/ts_build/src/lib/routes/walletdata.js +186 -0
  74. package/ts_build/src/lib/routes/walletdata.js.map +1 -0
  75. package/ts_build/src/lib/routes/wallets.d.ts +13 -0
  76. package/ts_build/src/lib/routes/wallets.d.ts.map +1 -0
  77. package/ts_build/src/lib/routes/wallets.js +292 -0
  78. package/ts_build/src/lib/routes/wallets.js.map +1 -0
  79. package/ts_build/src/lib/server.d.ts.map +1 -1
  80. package/ts_build/src/lib/server.js +19 -1
  81. package/ts_build/src/lib/server.js.map +1 -1
  82. package/ts_build/src/lib/storage.d.ts.map +1 -1
  83. package/ts_build/src/lib/storage.js +3 -0
  84. package/ts_build/src/lib/storage.js.map +1 -1
@@ -424,16 +424,20 @@ export class TxProposal implements ITxProposal {
424
424
  }
425
425
 
426
426
  getCurrentSignatures() {
427
- const acceptedActions = _.filter(this.actions, a => {
428
- return a.type == 'accept';
429
- });
430
-
431
- return _.map(acceptedActions, x => {
432
- return {
433
- signatures: x.signatures,
434
- xpub: x.xpub
435
- };
436
- });
427
+ const acceptedActions = this.actions.filter(a => a.type == 'accept');
428
+
429
+ const uniqueXpubs = new Set();
430
+ const signatures = [];
431
+ for (const a of acceptedActions) {
432
+ // TSS will have multiple accept actions with the same xpub/signature (different copayerIds)
433
+ if (uniqueXpubs.has(a.xpub)) continue;
434
+ uniqueXpubs.add(a.xpub);
435
+ signatures.push({
436
+ signatures: a.signatures,
437
+ xpub: a.xpub
438
+ });
439
+ }
440
+ return signatures;
437
441
  }
438
442
 
439
443
  getRawTx() {
@@ -0,0 +1,151 @@
1
+ import express from 'express';
2
+ import type * as Types from '../../types/expressapp';
3
+
4
+ interface RouteContext {
5
+ getServer: Types.GetServerFn;
6
+ getServerWithAuth: Types.GetServerWithAuthFn;
7
+ setPublicCache: (res: express.Response, seconds: number) => void;
8
+ returnError: Types.ReturnErrorFn;
9
+ }
10
+
11
+ export function registerAdvertisementRoutes(router: express.Router, context: RouteContext) {
12
+ const { getServer, getServerWithAuth, setPublicCache, returnError } = context;
13
+ const ONE_MINUTE = 60;
14
+
15
+ router.post('/v1/advertisements/', (req, res) => {
16
+ getServerWithAuth(
17
+ req,
18
+ res,
19
+ {
20
+ onlyMarketingStaff: true
21
+ },
22
+ server => {
23
+ server.createAdvert(req.body, (err, advert) => {
24
+ if (err) {
25
+ return returnError(err, res, req);
26
+ }
27
+ if (advert) res.json(advert);
28
+ });
29
+ }
30
+ );
31
+ });
32
+
33
+ router.get('/v1/advertisements/', (req, res) => {
34
+ const testing = req.query.testing;
35
+
36
+ let server;
37
+ try {
38
+ server = getServer(req, res);
39
+ } catch (ex) {
40
+ return returnError(ex, res, req);
41
+ }
42
+
43
+ if (testing) {
44
+ server.getTestingAdverts(req.body, (err, ads) => {
45
+ if (err) return returnError(err, res, req);
46
+ res.json(ads);
47
+ });
48
+ return;
49
+ }
50
+
51
+ setPublicCache(res, 5 * ONE_MINUTE);
52
+ server.getAdverts(req.body, (err, ads) => {
53
+ if (err) return returnError(err, res, req);
54
+ res.json(ads);
55
+ });
56
+ });
57
+
58
+ router.get('/v1/advertisements/:adId/', (req, res) => {
59
+ let server;
60
+
61
+ try {
62
+ server = getServer(req, res);
63
+ } catch (ex) {
64
+ return returnError(ex, res, req);
65
+ }
66
+
67
+ const opts = { adId: req.params['adId'] };
68
+
69
+ if (req.params['adId']) {
70
+ server.getAdvert(opts, (err, ad) => {
71
+ if (err) return returnError(err, res, req);
72
+ res.json(ad);
73
+ });
74
+ }
75
+ });
76
+
77
+ router.get('/v1/advertisements/country/:country', (req, res) => {
78
+ const opts = { country: req.params['country'] };
79
+
80
+ let server;
81
+ try {
82
+ server = getServer(req, res);
83
+ } catch (ex) {
84
+ return returnError(ex, res, req);
85
+ }
86
+
87
+ server.getAdvertsByCountry(opts, (err, ads) => {
88
+ if (err) return returnError(err, res, req);
89
+ res.json(ads);
90
+ });
91
+ });
92
+
93
+ router.post('/v1/advertisements/:adId/activate', (req, res) => {
94
+ const opts = { adId: req.params['adId'] };
95
+
96
+ getServerWithAuth(
97
+ req,
98
+ res,
99
+ {
100
+ onlyMarketingStaff: true
101
+ },
102
+ server => {
103
+ if (req.params['adId']) {
104
+ server.activateAdvert(opts, err => {
105
+ if (err) return returnError(err, res, req);
106
+ res.json({ advertisementId: opts.adId, message: 'advert activated' });
107
+ });
108
+ }
109
+ }
110
+ );
111
+ });
112
+
113
+ router.post('/v1/advertisements/:adId/deactivate', (req, res) => {
114
+ const opts = { adId: req.params['adId'] };
115
+
116
+ getServerWithAuth(
117
+ req,
118
+ res,
119
+ {
120
+ onlyMarketingStaff: true
121
+ },
122
+ server => {
123
+ if (req.params['adId']) {
124
+ server.deactivateAdvert(opts, err => {
125
+ if (err) return returnError(err, res, req);
126
+ res.json({ advertisementId: opts.adId, message: 'advert deactivated' });
127
+ });
128
+ }
129
+ }
130
+ );
131
+ });
132
+
133
+ router.delete('/v1/advertisements/:adId/', (req, res) => {
134
+ getServerWithAuth(
135
+ req,
136
+ res,
137
+ {
138
+ onlyMarketingStaff: true
139
+ },
140
+ server => {
141
+ req.body.adId = req.params['adId'];
142
+ server.removeAdvert(req.body, (err, removedAd) => {
143
+ if (err) return returnError(err, res, req);
144
+ if (removedAd) {
145
+ res.json(removedAd);
146
+ }
147
+ });
148
+ }
149
+ );
150
+ });
151
+ }
@@ -0,0 +1,152 @@
1
+ import express from 'express';
2
+ import * as _ from 'lodash';
3
+ import type * as Types from '../../types/expressapp';
4
+ import type { WalletService } from '../server';
5
+
6
+ interface RouteContext {
7
+ estimateFeeLimiter: express.Handler;
8
+ getServer: Types.GetServerFn;
9
+ getServerWithAuth: Types.GetServerWithAuthFn;
10
+ logDeprecated: Types.LogDeprecatedFn;
11
+ setPublicCache: (res: express.Response, seconds: number) => void;
12
+ returnError: Types.ReturnErrorFn;
13
+ }
14
+
15
+ type RouteHandler = (server: WalletService) => Promise<any> | any;
16
+
17
+ const ONE_MINUTE = 60;
18
+
19
+ function callbackResult<T>(fn: (cb: (err?: any, data?: T) => void) => void): Promise<T> {
20
+ return new Promise((resolve, reject) => {
21
+ fn((err, data) => {
22
+ if (err) return reject(err);
23
+ return resolve(data as T);
24
+ });
25
+ });
26
+ }
27
+
28
+ function getServerOrReturnError(req, res, context: RouteContext): WalletService | null {
29
+ try {
30
+ return context.getServer(req, res);
31
+ } catch (err) {
32
+ context.returnError(err, res, req);
33
+ return null;
34
+ }
35
+ }
36
+
37
+ function respondWithPublicServer(req, res, context: RouteContext, handler: RouteHandler) {
38
+ const server = getServerOrReturnError(req, res, context);
39
+ if (!server) return;
40
+
41
+ Promise.resolve()
42
+ .then(() => handler(server))
43
+ .then(response => {
44
+ res.json(response);
45
+ })
46
+ .catch(err => {
47
+ context.returnError(err ?? 'unknown', res, req);
48
+ });
49
+ }
50
+
51
+ function respondWithAuthServer(req, res, context: RouteContext, handler: RouteHandler) {
52
+ context.getServerWithAuth(req, res, server => {
53
+ Promise.resolve()
54
+ .then(() => handler(server))
55
+ .then(response => {
56
+ res.json(response);
57
+ })
58
+ .catch(err => {
59
+ context.returnError(err ?? 'unknown', res, req);
60
+ });
61
+ });
62
+ }
63
+
64
+ export function registerBlockchainRoutes(router: express.Router, context: RouteContext) {
65
+ const { estimateFeeLimiter, logDeprecated, setPublicCache } = context;
66
+
67
+ router.get('/v1/feelevels/', estimateFeeLimiter, (req, res) => {
68
+ setPublicCache(res, 1 * ONE_MINUTE);
69
+ logDeprecated(req);
70
+
71
+ respondWithPublicServer(req, res, context, server =>
72
+ callbackResult(resolve => {
73
+ const opts: { network?: string } = {};
74
+ if (req.query.network) opts.network = req.query.network as string;
75
+ server.getFeeLevels(opts, resolve);
76
+ }).then((feeLevels: any[]) => {
77
+ _.each(feeLevels, feeLevel => {
78
+ feeLevel.feePerKB = feeLevel.feePerKb;
79
+ delete feeLevel.feePerKb;
80
+ });
81
+ return feeLevels;
82
+ })
83
+ );
84
+ });
85
+
86
+ router.get('/v2/feelevels/', (req, res) => {
87
+ setPublicCache(res, 1 * ONE_MINUTE);
88
+
89
+ respondWithPublicServer(req, res, context, server =>
90
+ callbackResult(resolve => {
91
+ const opts: { coin?: string; network?: string; chain?: string } = {};
92
+ if (req.query.coin) opts.coin = req.query.coin as string;
93
+ if (req.query.chain || req.query.coin) opts.chain = (req.query.chain || req.query.coin) as string;
94
+ if (req.query.network) opts.network = req.query.network as string;
95
+ server.getFeeLevels(opts, resolve);
96
+ })
97
+ );
98
+ });
99
+
100
+ router.post('/v3/estimateGas/', (req, res) => {
101
+ respondWithAuthServer(req, res, context, server => {
102
+ return server.estimateGas(req.body);
103
+ });
104
+ });
105
+
106
+ router.post('/v1/ethmultisig/', (req, res) => {
107
+ respondWithAuthServer(req, res, context, server => {
108
+ return server.getMultisigContractInstantiationInfo(req.body);
109
+ });
110
+ });
111
+
112
+ router.post('/v1/ethmultisig/info', (req, res) => {
113
+ respondWithAuthServer(req, res, context, server => {
114
+ return server.getMultisigContractInfo(req.body);
115
+ });
116
+ });
117
+
118
+ router.post('/v1/multisig/', (req, res) => {
119
+ respondWithAuthServer(req, res, context, server => {
120
+ return server.getMultisigContractInstantiationInfo(req.body);
121
+ });
122
+ });
123
+
124
+ router.post('/v1/multisig/info', (req, res) => {
125
+ respondWithAuthServer(req, res, context, server => {
126
+ return server.getMultisigContractInfo(req.body);
127
+ });
128
+ });
129
+
130
+ router.post('/v1/token/info', (req, res) => {
131
+ respondWithAuthServer(req, res, context, server => {
132
+ return server.getTokenContractInfo(req.body);
133
+ });
134
+ });
135
+
136
+ router.post('/v1/token/allowance', (req, res) => {
137
+ respondWithPublicServer(req, res, context, server => {
138
+ return server.getTokenAllowance(req.body);
139
+ });
140
+ });
141
+
142
+ router.get('/v1/nonce/:address', (req, res) => {
143
+ respondWithAuthServer(req, res, context, server => {
144
+ return server.getNonce({
145
+ coin: req.query.coin || 'eth',
146
+ chain: req.query.chain,
147
+ network: req.query.network || 'livenet',
148
+ address: req.params['address']
149
+ });
150
+ });
151
+ });
152
+ }
@@ -0,0 +1,149 @@
1
+ import express from 'express';
2
+ import * as Types from '../../types/expressapp';
3
+ import { Errors } from '../errors/errordefinitions';
4
+ import { logger } from '../logger';
5
+ import { WalletService } from '../server';
6
+
7
+ interface RouteHelpers {
8
+ getServer: Types.GetServerFn;
9
+ getServerWithAuth: Types.GetServerWithAuthFn;
10
+ getServerWithMultiAuth: Types.GetServerWithMultiAuthFn;
11
+ logDeprecated: Types.LogDeprecatedFn;
12
+ setPublicCache: (res: express.Response, seconds: number) => void;
13
+ }
14
+
15
+ export function createRouteHelpers(returnError: Types.ReturnErrorFn): RouteHelpers {
16
+ const logDeprecated: Types.LogDeprecatedFn = req => {
17
+ logger.warn('DEPRECATED', req.method, req.url, '(' + req.header('x-client-version') + ')');
18
+ };
19
+
20
+ const getCredentials: Types.GetCredentialsFn = req => {
21
+ const identity = req.header('x-identity');
22
+ if (!identity) return;
23
+
24
+ return {
25
+ copayerId: identity,
26
+ signature: req.header('x-signature'),
27
+ session: req.header('x-session')
28
+ };
29
+ };
30
+
31
+ const getServer: Types.GetServerFn = (req, _res) => {
32
+ const opts = {
33
+ clientVersion: req.header('x-client-version'),
34
+ userAgent: req.header('user-agent')
35
+ };
36
+ return WalletService.getInstance(opts);
37
+ };
38
+
39
+ const getServerWithAuth: Types.GetServerWithAuthFn = async (req, res, opts, cb) => {
40
+ if (typeof opts === 'function') {
41
+ cb = opts;
42
+ opts = {};
43
+ }
44
+ opts = (opts || {}) as Types.ServerOpts;
45
+
46
+ const credentials = getCredentials(req);
47
+ if (!credentials) {
48
+ return returnError(Errors.NOT_AUTHORIZED, res, req);
49
+ }
50
+
51
+ const reqUrl = req.redirectedUrl || req.url;
52
+ const auth = {
53
+ copayerId: credentials.copayerId,
54
+ message: req.method.toLowerCase() + '|' + reqUrl + '|' + JSON.stringify(req.body),
55
+ signature: credentials.signature,
56
+ clientVersion: req.header('x-client-version'),
57
+ userAgent: req.header('user-agent'),
58
+ walletId: req.header('x-wallet-id'),
59
+ session: undefined
60
+ };
61
+
62
+ if (opts.allowSession) {
63
+ auth.session = credentials.session;
64
+ }
65
+
66
+ try {
67
+ const server: WalletService = await new Promise((resolve, reject) => {
68
+ WalletService.getInstanceWithAuth(auth, (err, server) => {
69
+ if (err) {
70
+ return reject(err);
71
+ }
72
+
73
+ if (opts.onlySupportStaff && !server.copayerIsSupportStaff) {
74
+ return reject(Errors.NOT_AUTHORIZED);
75
+ }
76
+
77
+ if (server.copayerIsSupportStaff) {
78
+ req.isSupportStaff = true;
79
+ }
80
+
81
+ if (opts.onlyMarketingStaff && !server.copayerIsMarketingStaff) {
82
+ return reject(Errors.NOT_AUTHORIZED);
83
+ }
84
+
85
+ req.walletId = server.walletId;
86
+ req.copayerId = server.copayerId;
87
+
88
+ return resolve(server);
89
+ });
90
+ });
91
+
92
+ if (cb) {
93
+ return cb(server);
94
+ }
95
+ return server;
96
+ } catch (err) {
97
+ if (opts.silentFailure) {
98
+ if (cb) {
99
+ return cb(null, err);
100
+ }
101
+ throw err;
102
+ }
103
+ return returnError(err, res, req);
104
+ }
105
+ };
106
+
107
+ const getServerWithMultiAuth: Types.GetServerWithMultiAuthFn = (req, res, opts = {}) => {
108
+ const identitiesHeader = req.headers['x-identities'];
109
+ const identitiesHeaderValue = Array.isArray(identitiesHeader) ? identitiesHeader.join(',') : identitiesHeader;
110
+ const identities = identitiesHeaderValue ? identitiesHeaderValue.split(',') : false;
111
+ const signature = req.headers['x-signature'];
112
+ if (!identities || !signature) {
113
+ throw Errors.NOT_AUTHORIZED;
114
+ }
115
+
116
+ if (!Array.isArray(identities)) {
117
+ throw Errors.NOT_AUTHORIZED;
118
+ }
119
+
120
+ return identities.map(
121
+ id =>
122
+ new Promise((resolve, reject) =>
123
+ getServerWithAuth(
124
+ Object.assign(req, {
125
+ headers: {
126
+ ...req.headers,
127
+ 'x-identity': id
128
+ }
129
+ }),
130
+ res,
131
+ opts,
132
+ (server, err) => (err ? reject(err) : resolve(server))
133
+ )
134
+ )
135
+ );
136
+ };
137
+
138
+ const setPublicCache = (res: express.Response, seconds: number) => {
139
+ res.setHeader('Cache-Control', `public, max-age=${seconds}, stale-if-error=${10 * seconds}`);
140
+ };
141
+
142
+ return {
143
+ getServer,
144
+ getServerWithAuth,
145
+ getServerWithMultiAuth,
146
+ logDeprecated,
147
+ setPublicCache
148
+ };
149
+ }
@@ -0,0 +1,111 @@
1
+ import express from 'express';
2
+ import * as _ from 'lodash';
3
+ import { WalletService } from '../server';
4
+ import { Stats } from '../stats';
5
+ import type * as Types from '../../types/expressapp';
6
+
7
+ interface RouteContext {
8
+ getServerWithAuth: Types.GetServerWithAuthFn;
9
+ setPublicCache: (res: express.Response, seconds: number) => void;
10
+ returnError: Types.ReturnErrorFn;
11
+ }
12
+
13
+ const ONE_MINUTE = 60;
14
+
15
+ export function registerMaintenanceRoutes(router: express.Router, context: RouteContext) {
16
+ const { getServerWithAuth, setPublicCache, returnError } = context;
17
+
18
+ router.post('/v1/addresses/scan/', (req, res) => {
19
+ getServerWithAuth(req, res, server => {
20
+ req.body = req.body || {};
21
+ req.body.startIdx = server.copayerIsSupportStaff ? Number(req.body.startIdx) : null;
22
+ server.startScan(req.body, (err, started) => {
23
+ if (err) return returnError(err, res, req);
24
+ res.json(started);
25
+ res.end();
26
+ });
27
+ });
28
+ });
29
+
30
+ router.get('/v1/stats/', (req, res) => {
31
+ setPublicCache(res, 1 * ONE_MINUTE);
32
+ const opts: {
33
+ network?: string;
34
+ coin?: string;
35
+ from?: string;
36
+ to?: string;
37
+ } = {};
38
+
39
+ if (req.query.network) opts.network = req.query.network as string;
40
+ if (req.query.coin) opts.coin = req.query.coin as string;
41
+ if (req.query.from) opts.from = req.query.from as string;
42
+ if (req.query.to) opts.to = req.query.to as string;
43
+
44
+ const stats = new Stats(opts);
45
+ stats.run((err, data) => {
46
+ if (err) return returnError(err, res, req);
47
+ res.json(data);
48
+ res.end();
49
+ });
50
+ });
51
+
52
+ router.get('/v1/version/', (req, res) => {
53
+ setPublicCache(res, 1 * ONE_MINUTE);
54
+ res.json({
55
+ serviceVersion: WalletService.getServiceVersion()
56
+ });
57
+ res.end();
58
+ });
59
+
60
+ router.get('/v1/txnotes/:txid', (req, res) => {
61
+ getServerWithAuth(req, res, server => {
62
+ server.getTxNote(
63
+ {
64
+ txid: req.params['txid']
65
+ },
66
+ (err, note) => {
67
+ if (err) return returnError(err, res, req);
68
+ res.json(note);
69
+ }
70
+ );
71
+ });
72
+ });
73
+
74
+ router.put('/v1/txnotes/:txid/', (req, res) => {
75
+ req.body.txid = req.params['txid'];
76
+ getServerWithAuth(req, res, server => {
77
+ server.editTxNote(req.body, (err, note) => {
78
+ if (err) return returnError(err, res, req);
79
+ res.json(note);
80
+ });
81
+ });
82
+ });
83
+
84
+ router.get('/v1/txnotes/', (req, res) => {
85
+ getServerWithAuth(req, res, server => {
86
+ const opts: { minTs?: number } = {};
87
+ if (req.query.minTs && _.isNumber(+req.query.minTs)) {
88
+ opts.minTs = +req.query.minTs;
89
+ }
90
+ server.getTxNotes(opts, (err, notes) => {
91
+ if (err) return returnError(err, res, req);
92
+ res.json(notes);
93
+ });
94
+ });
95
+ });
96
+
97
+ router.post('/v1/clearcache/', (req, res) => {
98
+ getServerWithAuth(req, res, server => {
99
+ server
100
+ .clearWalletCache(req.query)
101
+ .then(val => {
102
+ if (val) {
103
+ res.sendStatus(200);
104
+ } else {
105
+ res.sendStatus(500);
106
+ }
107
+ })
108
+ .catch(err => returnError(err, res, req));
109
+ });
110
+ });
111
+ }
@@ -0,0 +1,89 @@
1
+ import cors from 'cors';
2
+ import express from 'express';
3
+ import config from '../../config';
4
+ import type * as Types from '../../types/expressapp';
5
+ import type { WalletService } from '../server';
6
+
7
+ interface RouteContext {
8
+ getServer: Types.GetServerFn;
9
+ returnError: Types.ReturnErrorFn;
10
+ }
11
+
12
+ type RouteHandler = (server: WalletService) => Promise<any>;
13
+
14
+ function getServerOrReturnError(req, res, context: RouteContext): WalletService | null {
15
+ try {
16
+ return context.getServer(req, res);
17
+ } catch (err) {
18
+ context.returnError(err, res, req);
19
+ return null;
20
+ }
21
+ }
22
+
23
+ function respondWithPublicServer(req, res, context: RouteContext, handler: RouteHandler) {
24
+ const server = getServerOrReturnError(req, res, context);
25
+ if (!server) return;
26
+
27
+ handler(server)
28
+ .then(response => {
29
+ res.json(response);
30
+ })
31
+ .catch(err => {
32
+ context.returnError(err ?? 'unknown', res, req);
33
+ });
34
+ }
35
+
36
+ export function registerMoralisRoutes(router: express.Router, context: RouteContext) {
37
+ const moralisCorsOptions = {
38
+ origin: (origin, cb) => {
39
+ const moralisWhiteList = config.moralis?.whitelist ?? [];
40
+ if (moralisWhiteList.indexOf(origin) !== -1) {
41
+ cb(null, true);
42
+ } else {
43
+ cb(new Error('Not allowed by CORS'));
44
+ }
45
+ }
46
+ };
47
+
48
+ router.post('/v1/moralis/getWalletTokenBalances', cors(moralisCorsOptions), (req, res) => {
49
+ respondWithPublicServer(req, res, context, server => {
50
+ return server.moralisGetWalletTokenBalances(req);
51
+ });
52
+ });
53
+
54
+ router.post('/v1/moralis/moralisGetTokenAllowance', cors(moralisCorsOptions), (req, res) => {
55
+ respondWithPublicServer(req, res, context, server => {
56
+ return server.moralisGetTokenAllowance(req);
57
+ });
58
+ });
59
+
60
+ router.post('/v1/moralis/moralisGetNativeBalance', cors(moralisCorsOptions), (req, res) => {
61
+ respondWithPublicServer(req, res, context, server => {
62
+ return server.moralisGetNativeBalance(req);
63
+ });
64
+ });
65
+
66
+ router.post('/v1/moralis/GetTokenPrice', cors(moralisCorsOptions), (req, res) => {
67
+ respondWithPublicServer(req, res, context, server => {
68
+ return server.moralisGetTokenPrice(req);
69
+ });
70
+ });
71
+
72
+ router.post('/v1/moralis/getMultipleERC20TokenPrices', cors(moralisCorsOptions), (req, res) => {
73
+ respondWithPublicServer(req, res, context, server => {
74
+ return server.moralisGetMultipleERC20TokenPrices(req);
75
+ });
76
+ });
77
+
78
+ router.post('/v1/moralis/getERC20TokenBalancesWithPricesByWallet', cors(moralisCorsOptions), (req, res) => {
79
+ respondWithPublicServer(req, res, context, server => {
80
+ return server.moralisGetERC20TokenBalancesWithPricesByWallet(req);
81
+ });
82
+ });
83
+
84
+ router.post('/v1/moralis/getSolWalletPortfolio', cors(moralisCorsOptions), (req, res) => {
85
+ respondWithPublicServer(req, res, context, server => {
86
+ return server.moralisGetSolWalletPortfolio(req);
87
+ });
88
+ });
89
+ }