@bitpay-labs/bitcore-wallet-service 11.10.3 → 11.10.5

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 (36) hide show
  1. package/.mocharc.yml +2 -0
  2. package/.nycrc.yml +13 -0
  3. package/package.json +6 -25
  4. package/src/externalservices/ramp.ts +31 -11
  5. package/src/lib/expressapp.ts +1 -0
  6. package/src/lib/routes/moralis.ts +35 -7
  7. package/src/lib/routes/services.ts +8 -8
  8. package/src/lib/server.ts +49 -0
  9. package/test/expressapp.test.ts +83 -0
  10. package/test/integration/externalservices/moralis.test.ts +476 -0
  11. package/test/integration/externalservices/ramp.test.ts +151 -20
  12. package/ts_build/package.json +5 -24
  13. package/ts_build/src/externalservices/ramp.d.ts.map +1 -1
  14. package/ts_build/src/externalservices/ramp.js +19 -18
  15. package/ts_build/src/externalservices/ramp.js.map +1 -1
  16. package/ts_build/src/lib/expressapp.d.ts.map +1 -1
  17. package/ts_build/src/lib/expressapp.js +1 -0
  18. package/ts_build/src/lib/expressapp.js.map +1 -1
  19. package/ts_build/src/lib/routes/moralis.d.ts +1 -0
  20. package/ts_build/src/lib/routes/moralis.d.ts.map +1 -1
  21. package/ts_build/src/lib/routes/moralis.js +30 -7
  22. package/ts_build/src/lib/routes/moralis.js.map +1 -1
  23. package/ts_build/src/lib/routes/services.js +8 -8
  24. package/ts_build/src/lib/routes/services.js.map +1 -1
  25. package/ts_build/src/lib/server.d.ts +2 -0
  26. package/ts_build/src/lib/server.d.ts.map +1 -1
  27. package/ts_build/src/lib/server.js +42 -0
  28. package/ts_build/src/lib/server.js.map +1 -1
  29. package/ts_build/test/expressapp.test.js +79 -0
  30. package/ts_build/test/expressapp.test.js.map +1 -1
  31. package/ts_build/test/integration/externalservices/moralis.test.d.ts +2 -0
  32. package/ts_build/test/integration/externalservices/moralis.test.d.ts.map +1 -0
  33. package/ts_build/test/integration/externalservices/moralis.test.js +455 -0
  34. package/ts_build/test/integration/externalservices/moralis.test.js.map +1 -0
  35. package/ts_build/test/integration/externalservices/ramp.test.js +113 -20
  36. package/ts_build/test/integration/externalservices/ramp.test.js.map +1 -1
package/.mocharc.yml ADDED
@@ -0,0 +1,2 @@
1
+ enable-source-maps: true
2
+ exit: true
package/.nycrc.yml ADDED
@@ -0,0 +1,13 @@
1
+ include: [
2
+ ts_build/src,
3
+ src
4
+ ]
5
+ reporter: [
6
+ html,
7
+ text-summary
8
+ ]
9
+ check-coverage: true
10
+ statements: 60
11
+ branches: 50
12
+ functions: 60
13
+ lines: 70
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@bitpay-labs/bitcore-wallet-service",
3
3
  "description": "A service for Mutisig HD Bitcoin Wallets",
4
4
  "author": "BitPay Inc",
5
- "version": "11.10.3",
5
+ "version": "11.10.5",
6
6
  "license": "MIT",
7
7
  "main": "ts_build/src/index.js",
8
8
  "types": "./ts_build/src/index.d.ts",
@@ -24,9 +24,7 @@
24
24
  "scripts": {
25
25
  "start": "npm run clean && npm run build && ./start.sh",
26
26
  "stop": "./stop.sh",
27
- "coverage": "npm run compile && nyc mocha 'ts_build/test/**/*.test.js'",
28
- "test": "npm run compile && mocha --exit 'ts_build/test/**/*.test.js'",
29
- "test:ci": "BWS_LOG_LEVEL=none npm run test",
27
+ "test": "npm run compile && nyc mocha 'ts_build/test/**/*.test.js'",
30
28
  "build": "tsc && npm run cp:templates",
31
29
  "build:prod": "tsc -p tsconfig.prod.json && npm run cp:templates",
32
30
  "build:docker": "docker build -t bitpay/bitcore-wallet-service:latest -f ./Dockerfile ../..",
@@ -43,9 +41,9 @@
43
41
  "cp:templates": "cp -r ./templates ./ts_build/templates"
44
42
  },
45
43
  "dependencies": {
46
- "@bitpay-labs/bitcore-logging": "^11.10.3",
47
- "@bitpay-labs/bitcore-tss": "^11.10.3",
48
- "@bitpay-labs/crypto-wallet-core": "^11.10.3",
44
+ "@bitpay-labs/bitcore-logging": "^11.10.4",
45
+ "@bitpay-labs/bitcore-tss": "^11.10.4",
46
+ "@bitpay-labs/crypto-wallet-core": "^11.10.4",
49
47
  "@sendgrid/mail": "6.5.4",
50
48
  "abi-decoder": "2.4.0",
51
49
  "async": "0.9.2",
@@ -86,27 +84,10 @@
86
84
  "@types/request": "^2.48.1",
87
85
  "chai": "^5.2.0",
88
86
  "memdown": "^1.0.0",
89
- "mocha": "^5.2.0",
90
- "nyc": "^17.1.0",
91
87
  "sinon": "^7.1.1",
92
88
  "supertest": "*",
93
89
  "typescript": "^5.7.3"
94
90
  },
95
- "nyc": {
96
- "include": [
97
- "ts_build/src",
98
- "src"
99
- ],
100
- "reporter": [
101
- "html",
102
- "text-summary"
103
- ],
104
- "check-coverage": true,
105
- "lines": 60,
106
- "functions": 60,
107
- "branches": 60,
108
- "statements": 60
109
- },
110
91
  "bitcoreNode": "./bitcorenode",
111
92
  "contributors": [
112
93
  {
@@ -126,5 +107,5 @@
126
107
  "email": "kjoseph@bitpay.com"
127
108
  }
128
109
  ],
129
- "gitHead": "70298eedd1e458b23139e275125a07c577219bac"
110
+ "gitHead": "78b95920daa1de2feaa6744d009ad033f520fc3e"
130
111
  }
@@ -112,14 +112,13 @@ export class RampService {
112
112
  const webRequiredParams = [
113
113
  'selectedCountryCode',
114
114
  ];
115
- const appRequiredParams = [
115
+ let appRequiredParams = [
116
116
  'enabledFlows',
117
117
  'defaultFlow',
118
118
  'selectedCountryCode',
119
- 'defaultAsset',
120
119
  ];
121
- const extraRequiredParams = req.body.flow && req.body.flow === 'sell' ? ['offrampAsset'] : ['finalUrl', 'userAddress', 'swapAmount', 'swapAsset'];
122
- appRequiredParams.concat(extraRequiredParams);
120
+ const extraRequiredParams = req.body.flow && req.body.flow === 'sell' ? [] : ['finalUrl', 'userAddress'];
121
+ appRequiredParams = appRequiredParams.concat(extraRequiredParams);
123
122
 
124
123
  const requiredParams = req.body.context === 'web' ? webRequiredParams : appRequiredParams;
125
124
  const keys = this.rampGetKeys(req);
@@ -138,21 +137,42 @@ export class RampService {
138
137
  qs.push('selectedCountryCode=' + encodeURIComponent(req.body.selectedCountryCode));
139
138
  if (req.body.finalUrl) qs.push('finalUrl=' + encodeURIComponent(req.body.finalUrl));
140
139
  if (req.body.userAddress) qs.push('userAddress=' + encodeURIComponent(req.body.userAddress));
141
- if (req.body.swapAsset) qs.push('swapAsset=' + encodeURIComponent(req.body.swapAsset));
142
- if (req.body.offrampAsset) qs.push('offrampAsset=' + encodeURIComponent(req.body.offrampAsset));
143
140
  if (req.body.enabledFlows) qs.push('enabledFlows=' + encodeURIComponent(req.body.enabledFlows));
144
141
  if (req.body.defaultFlow) qs.push('defaultFlow=' + encodeURIComponent(req.body.defaultFlow));
145
142
  if (req.body.hostLogoUrl) qs.push('hostLogoUrl=' + encodeURIComponent(req.body.hostLogoUrl));
146
143
  if (req.body.hostAppName) qs.push('hostAppName=' + encodeURIComponent(req.body.hostAppName));
147
- if (req.body.swapAmount) qs.push('swapAmount=' + encodeURIComponent(req.body.swapAmount));
148
- if (req.body.fiatValue) qs.push('fiatValue=' + encodeURIComponent(req.body.fiatValue));
149
- if (req.body.fiatCurrency) qs.push('fiatCurrency=' + encodeURIComponent(req.body.fiatCurrency));
150
- if (req.body.defaultAsset) qs.push('defaultAsset=' + encodeURIComponent(req.body.defaultAsset));
151
144
  if (req.body.userEmailAddress) qs.push('userEmailAddress=' + encodeURIComponent(req.body.userEmailAddress));
152
145
  if (req.body.useSendCryptoCallback) qs.push('useSendCryptoCallback=' + encodeURIComponent(req.body.useSendCryptoCallback));
153
146
  if (req.body.paymentMethodType) qs.push('paymentMethodType=' + encodeURIComponent(req.body.paymentMethodType));
154
147
  if (req.body.hideExitButton) qs.push('hideExitButton=' + encodeURIComponent(req.body.hideExitButton));
155
- if (req.body.useSendCryptoCallbackVersion) qs.push('useSendCryptoCallbackVersion=' + encodeURIComponent(req.body.useSendCryptoCallbackVersion));
148
+
149
+ // Ramp deprecated the legacy per-flow search params in favor of a unified format.
150
+ // Ref: https://docs.rampnetwork.com/search-params-migration
151
+ // Older app versions still send the legacy fields, so we translate them into the new
152
+ // unified params here to keep those requests working going forward.
153
+ // `flow === 'sell'` => OFFRAMP; otherwise => ONRAMP.
154
+ // If a newer client already sends the new params, those take precedence.
155
+ const isOfframp = req.body.flow === 'sell';
156
+
157
+ // enabledCryptoAssets <- swapAsset (onramp) / offrampAsset (offramp)
158
+ const enabledCryptoAssets = req.body.enabledCryptoAssets ?? (isOfframp ? req.body.offrampAsset : req.body.swapAsset);
159
+ if (enabledCryptoAssets) qs.push('enabledCryptoAssets=' + encodeURIComponent(enabledCryptoAssets));
160
+
161
+ // inAsset (incoming, paid by the user) <- fiatCurrency (onramp) / defaultAsset (offramp)
162
+ const inAsset = req.body.inAsset ?? (isOfframp ? req.body.defaultAsset : req.body.fiatCurrency);
163
+ if (inAsset) qs.push('inAsset=' + encodeURIComponent(inAsset));
164
+
165
+ // outAsset (outgoing, received by the user) <- defaultAsset (onramp) / fiatCurrency (offramp)
166
+ const outAsset = req.body.outAsset ?? (isOfframp ? req.body.fiatCurrency : req.body.defaultAsset);
167
+ if (outAsset) qs.push('outAsset=' + encodeURIComponent(outAsset));
168
+
169
+ // inAssetValue (units, no decimals) <- fiatValue (onramp) / swapAmount (offramp)
170
+ const inAssetValue = req.body.inAssetValue ?? (isOfframp ? req.body.swapAmount : req.body.fiatValue);
171
+ if (inAssetValue) qs.push('inAssetValue=' + encodeURIComponent(inAssetValue));
172
+
173
+ // outAssetValue (units, no decimals) <- swapAmount (onramp) / fiatValue (offramp)
174
+ const outAssetValue = req.body.outAssetValue ?? (isOfframp ? req.body.fiatValue : req.body.swapAmount);
175
+ if (outAssetValue) qs.push('outAssetValue=' + encodeURIComponent(outAssetValue));
156
176
 
157
177
  const queryString = qs.join('&');
158
178
 
@@ -126,6 +126,7 @@ export class ExpressApp {
126
126
 
127
127
  registerMoralisRoutes(router, {
128
128
  getServer,
129
+ getServerWithAuth,
129
130
  returnError
130
131
  });
131
132
 
@@ -6,6 +6,7 @@ import type { WalletService } from '../server';
6
6
 
7
7
  interface RouteContext {
8
8
  getServer: Types.GetServerFn;
9
+ getServerWithAuth: Types.GetServerWithAuthFn;
9
10
  returnError: Types.ReturnErrorFn;
10
11
  }
11
12
 
@@ -33,6 +34,21 @@ function respondWithPublicServer(req, res, context: RouteContext, handler: Route
33
34
  });
34
35
  }
35
36
 
37
+ function walletAuthOrPublic(context: RouteContext) {
38
+ return function(req, res, next) {
39
+ if (!req.header('x-identity')) {
40
+ // Not from wallet
41
+ return next();
42
+ }
43
+ return context.getServerWithAuth(req, res, _server => {
44
+ if (!req.header('origin')) {
45
+ req.headers['origin'] = config.moralis?.whitelist?.[0];
46
+ }
47
+ return next();
48
+ });
49
+ };
50
+ }
51
+
36
52
  export function registerMoralisRoutes(router: express.Router, context: RouteContext) {
37
53
  const moralisCorsOptions = {
38
54
  origin: (origin, cb) => {
@@ -45,45 +61,57 @@ export function registerMoralisRoutes(router: express.Router, context: RouteCont
45
61
  }
46
62
  };
47
63
 
48
- router.post('/v1/moralis/getWalletTokenBalances', cors(moralisCorsOptions), (req, res) => {
64
+ router.post('/v1/moralis/getWalletTokenBalances', walletAuthOrPublic(context), cors(moralisCorsOptions), (req, res) => {
49
65
  respondWithPublicServer(req, res, context, server => {
50
66
  return server.moralisGetWalletTokenBalances(req);
51
67
  });
52
68
  });
53
69
 
54
- router.post('/v1/moralis/moralisGetTokenAllowance', cors(moralisCorsOptions), (req, res) => {
70
+ router.post('/v1/moralis/moralisGetTokenAllowance', walletAuthOrPublic(context), cors(moralisCorsOptions), (req, res) => {
55
71
  respondWithPublicServer(req, res, context, server => {
56
72
  return server.moralisGetTokenAllowance(req);
57
73
  });
58
74
  });
59
75
 
60
- router.post('/v1/moralis/moralisGetNativeBalance', cors(moralisCorsOptions), (req, res) => {
76
+ router.post('/v1/moralis/moralisGetNativeBalance', walletAuthOrPublic(context), cors(moralisCorsOptions), (req, res) => {
61
77
  respondWithPublicServer(req, res, context, server => {
62
78
  return server.moralisGetNativeBalance(req);
63
79
  });
64
80
  });
65
81
 
66
- router.post('/v1/moralis/GetTokenPrice', cors(moralisCorsOptions), (req, res) => {
82
+ router.post('/v1/moralis/GetTokenPrice', walletAuthOrPublic(context), cors(moralisCorsOptions), (req, res) => {
67
83
  respondWithPublicServer(req, res, context, server => {
68
84
  return server.moralisGetTokenPrice(req);
69
85
  });
70
86
  });
71
87
 
72
- router.post('/v1/moralis/getMultipleERC20TokenPrices', cors(moralisCorsOptions), (req, res) => {
88
+ router.post('/v1/moralis/getMultipleERC20TokenPrices', walletAuthOrPublic(context), cors(moralisCorsOptions), (req, res) => {
73
89
  respondWithPublicServer(req, res, context, server => {
74
90
  return server.moralisGetMultipleERC20TokenPrices(req);
75
91
  });
76
92
  });
77
93
 
78
- router.post('/v1/moralis/getERC20TokenBalancesWithPricesByWallet', cors(moralisCorsOptions), (req, res) => {
94
+ router.post('/v1/moralis/getERC20TokenBalancesWithPricesByWallet', walletAuthOrPublic(context), cors(moralisCorsOptions), (req, res) => {
79
95
  respondWithPublicServer(req, res, context, server => {
80
96
  return server.moralisGetERC20TokenBalancesWithPricesByWallet(req);
81
97
  });
82
98
  });
83
99
 
84
- router.post('/v1/moralis/getSolWalletPortfolio', cors(moralisCorsOptions), (req, res) => {
100
+ router.post('/v1/moralis/getSolWalletPortfolio', walletAuthOrPublic(context), cors(moralisCorsOptions), (req, res) => {
85
101
  respondWithPublicServer(req, res, context, server => {
86
102
  return server.moralisGetSolWalletPortfolio(req);
87
103
  });
88
104
  });
105
+
106
+ router.post('/v1/moralis/getTransactionVerbose', walletAuthOrPublic(context), cors(moralisCorsOptions), (req, res) => {
107
+ respondWithPublicServer(req, res, context, server => {
108
+ return server.moralisGetTransactionVerbose(req);
109
+ });
110
+ });
111
+
112
+ router.post('/v1/moralis/getMultipleSolTokenPrices', walletAuthOrPublic(context), cors(moralisCorsOptions), (req, res) => {
113
+ respondWithPublicServer(req, res, context, server => {
114
+ return server.moralisGetMultipleSolTokenPrices(req);
115
+ });
116
+ });
89
117
  }
@@ -232,7 +232,7 @@ export function registerServiceRoutes(router: express.Router, context: RouteCont
232
232
  });
233
233
 
234
234
  router.post('/v1/service/banxa/getOrder', (req, res) => {
235
- respondWithPublicServer(req, res, context, server => {
235
+ respondWithAuthServer(req, res, context, server => {
236
236
  return server.externalServices.banxa.banxaGetOrder(req);
237
237
  });
238
238
  });
@@ -274,7 +274,7 @@ export function registerServiceRoutes(router: express.Router, context: RouteCont
274
274
  });
275
275
 
276
276
  router.post('/v1/service/moonpay/transactionDetails', (req, res) => {
277
- respondWithPublicServer(req, res, context, server => {
277
+ respondWithAuthServer(req, res, context, server => {
278
278
  return server.externalServices.moonpay.moonpayGetTransactionDetails(req);
279
279
  });
280
280
  });
@@ -292,7 +292,7 @@ export function registerServiceRoutes(router: express.Router, context: RouteCont
292
292
  });
293
293
 
294
294
  router.post('/v1/service/moonpay/accountDetails', (req, res) => {
295
- respondWithPublicServer(req, res, context, server => {
295
+ respondWithAuthServer(req, res, context, server => {
296
296
  return server.externalServices.moonpay.moonpayGetAccountDetails(req);
297
297
  });
298
298
  });
@@ -364,7 +364,7 @@ export function registerServiceRoutes(router: express.Router, context: RouteCont
364
364
  });
365
365
 
366
366
  router.post('/v1/service/sardine/ordersDetails', (req, res) => {
367
- respondWithPublicServer(req, res, context, server => {
367
+ respondWithAuthServer(req, res, context, server => {
368
368
  return server.externalServices.sardine.sardineGetOrdersDetails(req);
369
369
  });
370
370
  });
@@ -431,7 +431,7 @@ export function registerServiceRoutes(router: express.Router, context: RouteCont
431
431
  });
432
432
 
433
433
  router.post('/v1/service/thorswap/getSwapTx', (req, res) => {
434
- respondWithPublicServer(req, res, context, server => {
434
+ respondWithAuthServer(req, res, context, server => {
435
435
  return server.externalServices.thorswap.thorswapGetSwapTx(req);
436
436
  });
437
437
  });
@@ -467,7 +467,7 @@ export function registerServiceRoutes(router: express.Router, context: RouteCont
467
467
  });
468
468
 
469
469
  router.post('/v1/service/transak/orderDetails', cors(transakCorsOptions), (req, res) => {
470
- respondWithPublicServer(req, res, context, server => {
470
+ respondWithAuthServer(req, res, context, server => {
471
471
  return server.externalServices.transak.transakGetOrderDetails(req);
472
472
  });
473
473
  });
@@ -509,13 +509,13 @@ export function registerServiceRoutes(router: express.Router, context: RouteCont
509
509
  });
510
510
 
511
511
  router.post('/v1/service/changelly/getTransactions', (req, res) => {
512
- respondWithPublicServer(req, res, context, server => {
512
+ respondWithAuthServer(req, res, context, server => {
513
513
  return server.externalServices.changelly.changellyGetTransactions(req);
514
514
  });
515
515
  });
516
516
 
517
517
  router.post('/v1/service/changelly/getStatus', (req, res) => {
518
- respondWithPublicServer(req, res, context, server => {
518
+ respondWithAuthServer(req, res, context, server => {
519
519
  return server.externalServices.changelly.changellyGetStatus(req);
520
520
  });
521
521
  });
package/src/lib/server.ts CHANGED
@@ -5612,6 +5612,55 @@ export class WalletService implements IWalletService {
5612
5612
  });
5613
5613
  }
5614
5614
 
5615
+ moralisGetTransactionVerbose(req): Promise<any> {
5616
+ return new Promise(async (resolve, reject) => {
5617
+ try {
5618
+ const response = await Moralis.EvmApi.transaction.getTransactionVerbose({
5619
+ transactionHash: req.body.transactionHash,
5620
+ chain: req.body.chain,
5621
+ });
5622
+
5623
+ return resolve(response?.raw ?? response);
5624
+ } catch (err) {
5625
+ reject(err);
5626
+ }
5627
+ });
5628
+ }
5629
+
5630
+ moralisGetMultipleSolTokenPrices(req): Promise<any> {
5631
+ return new Promise((resolve, reject) => {
5632
+ if (!config.moralis) return reject(new Error('Moralis missing credentials'));
5633
+ if (!checkRequired(req.body, ['addresses']) || !Array.isArray(req.body.addresses)) {
5634
+ return reject(new ClientError('moralisGetMultipleSolTokenPrices request missing arguments'));
5635
+ }
5636
+
5637
+ const network = req.body.network === 'devnet' ? 'devnet' : 'mainnet';
5638
+ const headers = {
5639
+ 'Accept': 'application/json',
5640
+ 'Content-Type': 'application/json',
5641
+ 'X-Api-Key': config.moralis.apiKey,
5642
+ };
5643
+
5644
+ const URL: string = `https://solana-gateway.moralis.io/token/${network}/prices`;
5645
+
5646
+ this.request.post(
5647
+ URL,
5648
+ {
5649
+ headers,
5650
+ body: { addresses: req.body.addresses },
5651
+ json: true
5652
+ },
5653
+ (err, data) => {
5654
+ if (err) {
5655
+ return reject(err.body ?? err);
5656
+ } else {
5657
+ return resolve(data.body ?? data);
5658
+ }
5659
+ }
5660
+ );
5661
+ });
5662
+ }
5663
+
5615
5664
  moralisGetSolWalletPortfolio(req): Promise<any> {
5616
5665
  return new Promise(async (resolve, reject) => {
5617
5666
  let network;
@@ -610,6 +610,89 @@ describe('ExpressApp', function() {
610
610
  });
611
611
  });
612
612
 
613
+ describe('Moralis routes (wallet-authenticated or public)', function() {
614
+ const whitelistedOrigin = 'https://whitelisted-dapp.example';
615
+ let originalMoralisConfig;
616
+ beforeEach(function() {
617
+ originalMoralisConfig = config.moralis;
618
+ config.moralis = { whitelist: [whitelistedOrigin] };
619
+ });
620
+ afterEach(function() {
621
+ config.moralis = originalMoralisConfig;
622
+ });
623
+
624
+ it('/v1/moralis/getMultipleERC20TokenPrices should work without auth headers (public/dApp)', function(done) {
625
+ const server = {
626
+ moralisGetMultipleERC20TokenPrices: sinon.stub().resolves([{ tokenAddress: '0xaaa', usdPrice: 1 }]),
627
+ };
628
+ sandbox.stub(WalletService, 'initialize').callsArg(1);
629
+ sandbox.stub(WalletService, 'getInstance').returns(server);
630
+ start(ExpressApp, function() {
631
+ const requestOptions = {
632
+ url: testHost + ':' + testPort + config.basePath + '/v1/moralis/getMultipleERC20TokenPrices',
633
+ method: 'post',
634
+ json: { chain: '0x1', tokens: [{ tokenAddress: '0xaaa' }] },
635
+ headers: {
636
+ origin: whitelistedOrigin
637
+ }
638
+ };
639
+ request(requestOptions, function(err, res, body) {
640
+ should.not.exist(err);
641
+ res.statusCode.should.equal(200);
642
+ body[0].tokenAddress.should.equal('0xaaa');
643
+ done();
644
+ });
645
+ });
646
+ });
647
+
648
+ it('/v1/moralis/getMultipleERC20TokenPrices should work with valid wallet auth headers', function(done) {
649
+ const server = {
650
+ moralisGetMultipleERC20TokenPrices: sinon.stub().resolves([{ tokenAddress: '0xaaa', usdPrice: 1 }]),
651
+ };
652
+ sandbox.stub(WalletService, 'initialize').callsArg(1);
653
+ sandbox.stub(WalletService, 'getInstance').returns(server);
654
+ sandbox.stub(WalletService, 'getInstanceWithAuth').callsArgWith(1, null, server);
655
+ start(ExpressApp, function() {
656
+ const requestOptions = {
657
+ url: testHost + ':' + testPort + config.basePath + '/v1/moralis/getMultipleERC20TokenPrices',
658
+ method: 'post',
659
+ json: { chain: '0x1', tokens: [{ tokenAddress: '0xaaa' }] },
660
+ headers: {
661
+ 'x-identity': 'identity',
662
+ 'x-signature': 'signature'
663
+ }
664
+ };
665
+ request(requestOptions, function(err, res, body) {
666
+ should.not.exist(err);
667
+ res.statusCode.should.equal(200);
668
+ body[0].tokenAddress.should.equal('0xaaa');
669
+ done();
670
+ });
671
+ });
672
+ });
673
+
674
+ it('/v1/moralis/getMultipleERC20TokenPrices should fail with invalid wallet auth headers', function(done) {
675
+ sandbox.stub(WalletService, 'initialize').callsArg(1);
676
+ sandbox.stub(WalletService, 'getInstanceWithAuth').callsArgWith(1, new ClientError('NOT_AUTHORIZED', 'Not authorized'));
677
+ start(ExpressApp, function() {
678
+ const requestOptions = {
679
+ url: testHost + ':' + testPort + config.basePath + '/v1/moralis/getMultipleERC20TokenPrices',
680
+ method: 'post',
681
+ json: { chain: '0x1', tokens: [{ tokenAddress: '0xaaa' }] },
682
+ headers: {
683
+ 'x-identity': 'identity',
684
+ 'x-signature': 'bad-signature'
685
+ }
686
+ };
687
+ request(requestOptions, function(err, res) {
688
+ should.not.exist(err);
689
+ res.statusCode.should.equal(401);
690
+ done();
691
+ });
692
+ });
693
+ });
694
+ });
695
+
613
696
  describe('Token allowance', function() {
614
697
  it('/v1/token/allowance', function(done) {
615
698
  const server = {