@dydxprotocol/v4-client-js 0.32.0 → 0.32.1

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.
@@ -3,7 +3,7 @@ import {
3
3
  } from '../src/clients/constants';
4
4
  import { NetworkOptimizer } from '../src/network_optimizer';
5
5
 
6
- async function test(): Promise<void> {
6
+ async function testNodes(): Promise<void> {
7
7
  // all valid endpoints
8
8
  try {
9
9
  const optimizer = new NetworkOptimizer();
@@ -48,4 +48,33 @@ async function test(): Promise<void> {
48
48
  }
49
49
  }
50
50
 
51
- test().catch(console.log);
51
+ async function testIndexers(): Promise<void> {
52
+ // all valid endpoints
53
+ try {
54
+ const optimizer = new NetworkOptimizer();
55
+ const endpoints = [
56
+ 'https://indexer.v4testnet2.dydx.exchange',
57
+ ];
58
+ const optimal = await optimizer.findOptimalIndexer(endpoints);
59
+ console.log(optimal);
60
+ } catch (error) {
61
+ console.log(error.message);
62
+ }
63
+
64
+ // all invalid endpoints
65
+
66
+ try {
67
+ const optimizer = new NetworkOptimizer();
68
+ const endpoints = [
69
+ 'https://example.com',
70
+ 'https://example.org',
71
+ ];
72
+ const optimal = await optimizer.findOptimalIndexer(endpoints);
73
+ console.log(optimal);
74
+ } catch (error) {
75
+ console.log(error.message);
76
+ }
77
+ }
78
+
79
+ testNodes().catch(console.log);
80
+ testIndexers().catch(console.log);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dydxprotocol/v4-client-js",
3
- "version": "0.32.0",
3
+ "version": "0.32.1",
4
4
  "description": "General client library for the new dYdX system (v4 decentralized)",
5
5
  "main": "build/src/index.js",
6
6
  "scripts": {
@@ -862,3 +862,27 @@ export async function getOptimalNode(endpointUrlsAsJson: string): Promise<string
862
862
  return wrappedError(error);
863
863
  }
864
864
  }
865
+
866
+ export async function getOptimalIndexer(endpointUrlsAsJson: string): Promise<string> {
867
+ /*
868
+ param:
869
+ endpointUrlsAsJson:
870
+ {
871
+ "endpointUrls": [
872
+ "https://api.example.org"
873
+ ]
874
+ }
875
+ */
876
+ try {
877
+ const param = JSON.parse(endpointUrlsAsJson);
878
+ const endpointUrls = param.endpointUrls;
879
+ const networkOptimizer = new NetworkOptimizer();
880
+ const optimalUrl = await networkOptimizer.findOptimalIndexer(endpointUrls);
881
+ const url = {
882
+ url: optimalUrl,
883
+ };
884
+ return encodeJson(url);
885
+ } catch (error) {
886
+ return wrappedError(error);
887
+ }
888
+ }
@@ -1,18 +1,17 @@
1
- import { Block } from '@cosmjs/stargate';
2
-
1
+ import { IndexerClient } from './clients/indexer-client';
3
2
  import { ValidatorClient } from './clients/validator-client';
4
3
  import { encodeJson } from './lib/helpers';
5
- import { ValidatorConfig } from './types';
4
+ import { IndexerConfig, ValidatorConfig } from './types';
6
5
 
7
6
  class PingResponse {
8
- public readonly block: Block;
7
+ public readonly height: number;
9
8
  public readonly responseTime: Date;
10
9
  public endpoint?: string;
11
10
 
12
11
  constructor(
13
- block: Block,
12
+ height: number,
14
13
  ) {
15
- this.block = block;
14
+ this.height = height;
16
15
  this.responseTime = new Date();
17
16
  }
18
17
  }
@@ -32,6 +31,15 @@ export class NetworkOptimizer {
32
31
  )).filter(isTruthy);
33
32
  }
34
33
 
34
+ private indexerClients(
35
+ endpointUrls: string[],
36
+ ): IndexerClient[] {
37
+ return endpointUrls.map((endpointUrl) => new IndexerClient(
38
+ // socket is not used for finding optimal indexer, but required as a parameter to the config
39
+ new IndexerConfig(endpointUrl, endpointUrl.replace('https://', 'wss://').replace('http://', 'ws://')),
40
+ )).filter(isTruthy);
41
+ }
42
+
35
43
  async findOptimalNode(endpointUrls: string[], chainId: string): Promise<string> {
36
44
  if (endpointUrls.length === 0) {
37
45
  const errorResponse = {
@@ -46,10 +54,46 @@ export class NetworkOptimizer {
46
54
  clients
47
55
  .map(async (client) => {
48
56
  const block = await client.get.latestBlock();
49
- const response = new PingResponse(block);
57
+ const response = new PingResponse(block.header.height);
58
+ return {
59
+ endpoint: client.config.restEndpoint,
60
+ height: response.height,
61
+ time: response.responseTime.getTime(),
62
+ };
63
+ })
64
+ .map((promise) => promise.catch((_) => undefined)),
65
+ )).filter(isTruthy);
66
+
67
+ if (responses.length === 0) {
68
+ throw new Error('Could not connect to endpoints');
69
+ }
70
+ const maxHeight = Math.max(...responses.map(({ height }) => height));
71
+ return responses
72
+ // Only consider nodes at `maxHeight`
73
+ .filter(({ height }) => height === maxHeight)
74
+ // Return the endpoint with the fastest response time
75
+ .sort((a, b) => a.time - b.time)[0]
76
+ .endpoint;
77
+ }
78
+
79
+ async findOptimalIndexer(endpointUrls: string[]): Promise<string> {
80
+ if (endpointUrls.length === 0) {
81
+ const errorResponse = {
82
+ error: {
83
+ message: 'No URL provided',
84
+ },
85
+ };
86
+ return encodeJson(errorResponse);
87
+ }
88
+ const clients = this.indexerClients(endpointUrls);
89
+ const responses = (await Promise.all(
90
+ clients
91
+ .map(async (client) => {
92
+ const block = await client.markets.getHeight();
93
+ const response = new PingResponse(+block.height);
50
94
  return {
51
95
  endpoint: client.config.restEndpoint,
52
- height: response.block.header.height,
96
+ height: response.height,
53
97
  time: response.responseTime.getTime(),
54
98
  };
55
99
  })