@across-protocol/sdk 3.2.14 → 3.2.16

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 (34) hide show
  1. package/dist/cjs/clients/BundleDataClient/BundleDataClient.d.ts +2 -1
  2. package/dist/cjs/clients/BundleDataClient/BundleDataClient.js +7 -4
  3. package/dist/cjs/clients/BundleDataClient/BundleDataClient.js.map +1 -1
  4. package/dist/cjs/clients/BundleDataClient/utils/SuperstructUtils.d.ts +0 -2
  5. package/dist/cjs/clients/BundleDataClient/utils/SuperstructUtils.js +1 -2
  6. package/dist/cjs/clients/BundleDataClient/utils/SuperstructUtils.js.map +1 -1
  7. package/dist/cjs/providers/rateLimitedProvider.js +1 -0
  8. package/dist/cjs/providers/rateLimitedProvider.js.map +1 -1
  9. package/dist/cjs/utils/Profiler.d.ts +40 -0
  10. package/dist/cjs/utils/Profiler.js +114 -0
  11. package/dist/cjs/utils/Profiler.js.map +1 -0
  12. package/dist/esm/clients/BundleDataClient/BundleDataClient.d.ts +2 -1
  13. package/dist/esm/clients/BundleDataClient/BundleDataClient.js +11 -4
  14. package/dist/esm/clients/BundleDataClient/BundleDataClient.js.map +1 -1
  15. package/dist/esm/clients/BundleDataClient/utils/SuperstructUtils.d.ts +0 -2
  16. package/dist/esm/clients/BundleDataClient/utils/SuperstructUtils.js +2 -3
  17. package/dist/esm/clients/BundleDataClient/utils/SuperstructUtils.js.map +1 -1
  18. package/dist/esm/providers/rateLimitedProvider.js +1 -0
  19. package/dist/esm/providers/rateLimitedProvider.js.map +1 -1
  20. package/dist/esm/utils/Profiler.d.ts +81 -0
  21. package/dist/esm/utils/Profiler.js +155 -0
  22. package/dist/esm/utils/Profiler.js.map +1 -0
  23. package/dist/types/clients/BundleDataClient/BundleDataClient.d.ts +2 -1
  24. package/dist/types/clients/BundleDataClient/BundleDataClient.d.ts.map +1 -1
  25. package/dist/types/clients/BundleDataClient/utils/SuperstructUtils.d.ts +0 -2
  26. package/dist/types/clients/BundleDataClient/utils/SuperstructUtils.d.ts.map +1 -1
  27. package/dist/types/providers/rateLimitedProvider.d.ts.map +1 -1
  28. package/dist/types/utils/Profiler.d.ts +82 -0
  29. package/dist/types/utils/Profiler.d.ts.map +1 -0
  30. package/package.json +1 -1
  31. package/src/clients/BundleDataClient/BundleDataClient.ts +12 -4
  32. package/src/clients/BundleDataClient/utils/SuperstructUtils.ts +2 -2
  33. package/src/providers/rateLimitedProvider.ts +1 -0
  34. package/src/utils/Profiler.ts +194 -0
@@ -171,8 +171,16 @@ export class BundleDataClient {
171
171
  this.bundleTimestampCache[key] = timestamps;
172
172
  }
173
173
 
174
- private getArweaveClientKey(blockRangesForChains: number[][]): string {
175
- return `bundles-${blockRangesForChains}`;
174
+ static getArweaveClientKey(blockRangesForChains: number[][]): string {
175
+ // As a unique key for this bundle, use the bundle mainnet end block, which should
176
+ // never be duplicated between bundles as long as thebundle block range
177
+ // always progresses forwards, which I think is a safe assumption. Other chains might pause
178
+ // but mainnet should never pause.
179
+ return blockRangesForChains[0][1].toString();
180
+ }
181
+
182
+ private getArweaveBundleDataClientKey(blockRangesForChains: number[][]): string {
183
+ return `bundles-${BundleDataClient.getArweaveClientKey(blockRangesForChains)}`;
176
184
  }
177
185
 
178
186
  private async loadPersistedDataFromArweave(
@@ -183,7 +191,7 @@ export class BundleDataClient {
183
191
  }
184
192
  const start = performance.now();
185
193
  const persistedData = await this.clients.arweaveClient.getByTopic(
186
- this.getArweaveClientKey(blockRangesForChains),
194
+ this.getArweaveBundleDataClientKey(blockRangesForChains),
187
195
  BundleDataSS
188
196
  );
189
197
  // If there is no data or the data is empty, return undefined because we couldn't
@@ -579,7 +587,7 @@ export class BundleDataClient {
579
587
  }
580
588
 
581
589
  private async loadArweaveData(blockRangesForChains: number[][]): Promise<LoadDataReturnValue> {
582
- const arweaveKey = this.getArweaveClientKey(blockRangesForChains);
590
+ const arweaveKey = this.getArweaveBundleDataClientKey(blockRangesForChains);
583
591
  // eslint-disable-next-line @typescript-eslint/no-misused-promises
584
592
  if (!this.arweaveDataCache[arweaveKey]) {
585
593
  this.arweaveDataCache[arweaveKey] = this.loadPersistedDataFromArweave(blockRangesForChains);
@@ -10,6 +10,7 @@ import {
10
10
  pattern,
11
11
  boolean,
12
12
  defaulted,
13
+ type,
13
14
  } from "superstruct";
14
15
  import { BigNumber } from "../../../utils";
15
16
 
@@ -122,8 +123,7 @@ const nestedV3BundleFillsSS = record(
122
123
  )
123
124
  );
124
125
 
125
- export const BundleDataSS = object({
126
- bundleBlockRanges: array(array(number())),
126
+ export const BundleDataSS = type({
127
127
  bundleDepositsV3: nestedV3DepositRecordSS,
128
128
  expiredDepositsToRefundV3: nestedV3DepositRecordSS,
129
129
  unexecutableSlowFills: nestedV3DepositRecordWithLpFeePctSS,
@@ -51,6 +51,7 @@ export class RateLimitedProvider extends ethers.providers.StaticJsonRpcProvider
51
51
  method,
52
52
  params,
53
53
  chainId: this.network.chainId,
54
+ datadog: true,
54
55
  };
55
56
 
56
57
  // In this path we log an rpc response sample.
@@ -0,0 +1,194 @@
1
+ import { performance } from "node:perf_hooks";
2
+ import { Logger } from "winston";
3
+ import crypto from "crypto";
4
+ import { DefaultLogLevels } from "./LogUtils";
5
+
6
+ type Detail = {
7
+ message?: string;
8
+ [key: string]: unknown;
9
+ };
10
+
11
+ const defaultMeta = { datadog: true };
12
+
13
+ export type PerformanceData = {
14
+ task: string; // The name of the task being measured.
15
+ duration: number; // Duration in milliseconds.
16
+ message: string; // A descriptive message about the task.
17
+ at: string; // Identifier indicating where the profiling is happening.
18
+ data?: Record<string, unknown>; // Additional detail data.
19
+ };
20
+
21
+ type ProfilerOptions = {
22
+ logger: Logger;
23
+ at: string;
24
+ logLevel?: DefaultLogLevels;
25
+ } & Record<string, unknown>;
26
+
27
+ export class Profiler {
28
+ private marks: Map<string, { time: number; detail?: Record<string, unknown> }>;
29
+ private at: string;
30
+ private detail: Detail;
31
+ private logger: Logger;
32
+ private logLevel: DefaultLogLevels;
33
+
34
+ /**
35
+ * Initializes a new instance of the Profiler class.
36
+ * @param logger The logger instance for logging performance data.
37
+ * @param at A string identifier for where the profiler is used.
38
+ * @param detail Optional additional detail data.
39
+ */
40
+ constructor({ logger, at, logLevel, ...detail }: ProfilerOptions) {
41
+ this.marks = new Map();
42
+ this.logger = logger;
43
+ this.at = at;
44
+ this.logLevel = logLevel ?? "debug";
45
+ this.detail = detail;
46
+ }
47
+
48
+ log(logLevel: DefaultLogLevels, data: Parameters<Logger["log"]>[1]): void {
49
+ this.logger.log(logLevel, {
50
+ at: this.at,
51
+ ...defaultMeta,
52
+ ...data,
53
+ });
54
+ }
55
+
56
+ logMeasure(data: Omit<PerformanceData, "at">, logLevel: DefaultLogLevels = this.logLevel): void {
57
+ this.log(logLevel, {
58
+ ...data,
59
+ });
60
+ }
61
+
62
+ /**
63
+ * Starts a profiling session for a task.
64
+ * @param task The name of the task being measured.
65
+ * @param detail Optional detail data to merge.
66
+ * @returns An object containing the start time and a stop function.
67
+ */
68
+ start(task: string, detail?: Detail): { startTime: number; stop: (_detail?: Detail) => number | undefined } {
69
+ const start = crypto.randomUUID();
70
+ const startTime = this.mark(start, detail);
71
+ return {
72
+ startTime,
73
+ stop: (_detail?: Detail) => this.measure(task, { from: start, ...(detail ?? {}), ...(_detail ?? {}) }),
74
+ };
75
+ }
76
+
77
+ /**
78
+ * Records a mark with a label and optional detail.
79
+ * @param label The label for the mark.
80
+ * @param detail Optional detail data to merge.
81
+ * @returns The current timestamp in milliseconds.
82
+ */
83
+ mark(label: string, detail?: Detail): number {
84
+ const currentTime = performance.now();
85
+
86
+ // Merge additional data
87
+ this.detail = { ...(this.detail ?? {}), ...(detail ?? {}) };
88
+
89
+ // Store the mark
90
+ this.marks.set(label, { time: currentTime, detail });
91
+ return currentTime;
92
+ }
93
+
94
+ /**
95
+ * Measures the duration between two marks and logs the performance data.
96
+ * @param task The name of the task for this measurement.
97
+ * @param params An object containing:
98
+ * - `from`: The label of the starting mark.
99
+ * - `to` (optional): The label of the ending mark.
100
+ * - Additional detail data to merge.
101
+ * @returns The duration in milliseconds, or undefined if the start mark is not found.
102
+ */
103
+ measure(
104
+ task: string,
105
+ params: {
106
+ from: string;
107
+ to?: string;
108
+ } & Detail
109
+ ): number | undefined {
110
+ const { from, to, ...detail } = params;
111
+ const startMark = this.marks.get(from);
112
+ const endMark = to ? this.marks.get(to) : undefined;
113
+
114
+ if (!startMark) {
115
+ this.log("warn", {
116
+ message: `Cannot find start mark for label "${from}".`,
117
+ ...this.detail,
118
+ });
119
+ return;
120
+ }
121
+ const endTime = endMark?.time ?? performance.now();
122
+
123
+ const duration = endTime - startMark.time;
124
+
125
+ // Merge detail
126
+ const { message, ...combinedDetail } = { ...(this.detail ?? {}), ...(detail ?? {}) };
127
+ const defaultMessage = `Profiler Log: ${task}`;
128
+
129
+ this.logMeasure({
130
+ task,
131
+ duration,
132
+ message: message ?? defaultMessage,
133
+ data: combinedDetail,
134
+ });
135
+
136
+ return duration;
137
+ }
138
+
139
+ /**
140
+ * Measures the performance of an asynchronous operation represented by a promise.
141
+ * @param pr The promise representing the asynchronous operation to measure.
142
+ * @param task The name of the task for this measurement.
143
+ * @param detail Optional detail data to merge.
144
+ * @returns A promise that resolves with the result of the asynchronous operation.
145
+ */
146
+ async measureAsync<T>(pr: Promise<T>, task: string, detail?: Detail): Promise<T> {
147
+ const startTime = performance.now();
148
+
149
+ try {
150
+ const result = await pr;
151
+ return result;
152
+ } finally {
153
+ const endTime = performance.now();
154
+ const duration = endTime - startTime;
155
+ const { message, ...combinedDetail } = { ...detail };
156
+ const defaultMessage = `Profiler Log: ${task}`;
157
+
158
+ this.logMeasure({
159
+ task,
160
+ duration,
161
+ message: message ?? defaultMessage,
162
+ data: combinedDetail,
163
+ });
164
+ }
165
+ }
166
+
167
+ /**
168
+ * Measures the performance of a synchronous function by wrapping it.
169
+ * @param fn The synchronous function to measure.
170
+ * @param task The name of the task for this measurement.
171
+ * @param detail Optional detail data to merge.
172
+ * @returns The result of the synchronous function.
173
+ */
174
+ measureSync<T>(fn: () => T, task: string, detail?: Detail): T {
175
+ const startTime = performance.now();
176
+
177
+ try {
178
+ const result = fn();
179
+ return result;
180
+ } finally {
181
+ const endTime = performance.now();
182
+ const duration = endTime - startTime;
183
+ const { message, ...combinedDetail } = { ...detail };
184
+ const defaultMessage = `Profiler Log: ${task}`;
185
+
186
+ this.logMeasure({
187
+ task,
188
+ duration,
189
+ message: message ?? defaultMessage,
190
+ data: combinedDetail,
191
+ });
192
+ }
193
+ }
194
+ }