@hyperlane-xyz/rebalancer 0.1.2 → 1.0.0

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 (223) hide show
  1. package/README.md +134 -14
  2. package/dist/config/RebalancerConfig.d.ts +2 -2
  3. package/dist/config/RebalancerConfig.d.ts.map +1 -1
  4. package/dist/config/RebalancerConfig.js +4 -3
  5. package/dist/config/RebalancerConfig.js.map +1 -1
  6. package/dist/config/RebalancerConfig.test.js +434 -163
  7. package/dist/config/RebalancerConfig.test.js.map +1 -1
  8. package/dist/config/types.d.ts +1650 -290
  9. package/dist/config/types.d.ts.map +1 -1
  10. package/dist/config/types.js +124 -46
  11. package/dist/config/types.js.map +1 -1
  12. package/dist/core/Rebalancer.d.ts +14 -7
  13. package/dist/core/Rebalancer.d.ts.map +1 -1
  14. package/dist/core/Rebalancer.js +168 -99
  15. package/dist/core/Rebalancer.js.map +1 -1
  16. package/dist/core/Rebalancer.test.d.ts +2 -0
  17. package/dist/core/Rebalancer.test.d.ts.map +1 -0
  18. package/dist/core/Rebalancer.test.js +391 -0
  19. package/dist/core/Rebalancer.test.js.map +1 -0
  20. package/dist/core/RebalancerService.d.ts +16 -2
  21. package/dist/core/RebalancerService.d.ts.map +1 -1
  22. package/dist/core/RebalancerService.js +164 -21
  23. package/dist/core/RebalancerService.js.map +1 -1
  24. package/dist/core/RebalancerService.test.d.ts +2 -0
  25. package/dist/core/RebalancerService.test.d.ts.map +1 -0
  26. package/dist/core/RebalancerService.test.js +809 -0
  27. package/dist/core/RebalancerService.test.js.map +1 -0
  28. package/dist/factories/RebalancerContextFactory.d.ts +11 -0
  29. package/dist/factories/RebalancerContextFactory.d.ts.map +1 -1
  30. package/dist/factories/RebalancerContextFactory.js +60 -13
  31. package/dist/factories/RebalancerContextFactory.js.map +1 -1
  32. package/dist/index.d.ts +6 -6
  33. package/dist/index.d.ts.map +1 -1
  34. package/dist/index.js +4 -3
  35. package/dist/index.js.map +1 -1
  36. package/dist/interfaces/IMonitor.d.ts +6 -8
  37. package/dist/interfaces/IMonitor.d.ts.map +1 -1
  38. package/dist/interfaces/IMonitor.js.map +1 -1
  39. package/dist/interfaces/IRebalancer.d.ts +20 -4
  40. package/dist/interfaces/IRebalancer.d.ts.map +1 -1
  41. package/dist/interfaces/IStrategy.d.ts +18 -2
  42. package/dist/interfaces/IStrategy.d.ts.map +1 -1
  43. package/dist/metrics/Metrics.d.ts +4 -2
  44. package/dist/metrics/Metrics.d.ts.map +1 -1
  45. package/dist/metrics/Metrics.js +21 -1
  46. package/dist/metrics/Metrics.js.map +1 -1
  47. package/dist/metrics/scripts/metrics.d.ts +2 -0
  48. package/dist/metrics/scripts/metrics.d.ts.map +1 -1
  49. package/dist/metrics/scripts/metrics.js +12 -0
  50. package/dist/metrics/scripts/metrics.js.map +1 -1
  51. package/dist/monitor/Monitor.d.ts +8 -3
  52. package/dist/monitor/Monitor.d.ts.map +1 -1
  53. package/dist/monitor/Monitor.js +75 -15
  54. package/dist/monitor/Monitor.js.map +1 -1
  55. package/dist/strategy/BaseStrategy.d.ts +51 -5
  56. package/dist/strategy/BaseStrategy.d.ts.map +1 -1
  57. package/dist/strategy/BaseStrategy.js +199 -19
  58. package/dist/strategy/BaseStrategy.js.map +1 -1
  59. package/dist/strategy/CollateralDeficitStrategy.d.ts +65 -0
  60. package/dist/strategy/CollateralDeficitStrategy.d.ts.map +1 -0
  61. package/dist/strategy/CollateralDeficitStrategy.js +245 -0
  62. package/dist/strategy/CollateralDeficitStrategy.js.map +1 -0
  63. package/dist/strategy/CollateralDeficitStrategy.test.d.ts +2 -0
  64. package/dist/strategy/CollateralDeficitStrategy.test.d.ts.map +1 -0
  65. package/dist/strategy/CollateralDeficitStrategy.test.js +364 -0
  66. package/dist/strategy/CollateralDeficitStrategy.test.js.map +1 -0
  67. package/dist/strategy/CompositeStrategy.d.ts +18 -0
  68. package/dist/strategy/CompositeStrategy.d.ts.map +1 -0
  69. package/dist/strategy/CompositeStrategy.js +63 -0
  70. package/dist/strategy/CompositeStrategy.js.map +1 -0
  71. package/dist/strategy/CompositeStrategy.test.d.ts +2 -0
  72. package/dist/strategy/CompositeStrategy.test.d.ts.map +1 -0
  73. package/dist/strategy/CompositeStrategy.test.js +265 -0
  74. package/dist/strategy/CompositeStrategy.test.js.map +1 -0
  75. package/dist/strategy/MinAmountStrategy.d.ts +12 -5
  76. package/dist/strategy/MinAmountStrategy.d.ts.map +1 -1
  77. package/dist/strategy/MinAmountStrategy.js +23 -14
  78. package/dist/strategy/MinAmountStrategy.js.map +1 -1
  79. package/dist/strategy/MinAmountStrategy.test.js +88 -20
  80. package/dist/strategy/MinAmountStrategy.test.js.map +1 -1
  81. package/dist/strategy/StrategyFactory.d.ts +15 -6
  82. package/dist/strategy/StrategyFactory.d.ts.map +1 -1
  83. package/dist/strategy/StrategyFactory.js +48 -10
  84. package/dist/strategy/StrategyFactory.js.map +1 -1
  85. package/dist/strategy/StrategyFactory.test.js +2 -2
  86. package/dist/strategy/StrategyFactory.test.js.map +1 -1
  87. package/dist/strategy/WeightedStrategy.d.ts +13 -4
  88. package/dist/strategy/WeightedStrategy.d.ts.map +1 -1
  89. package/dist/strategy/WeightedStrategy.js +18 -6
  90. package/dist/strategy/WeightedStrategy.js.map +1 -1
  91. package/dist/strategy/WeightedStrategy.test.js +108 -18
  92. package/dist/strategy/WeightedStrategy.test.js.map +1 -1
  93. package/dist/strategy/index.d.ts +2 -0
  94. package/dist/strategy/index.d.ts.map +1 -1
  95. package/dist/strategy/index.js +2 -0
  96. package/dist/strategy/index.js.map +1 -1
  97. package/dist/test/helpers.d.ts +93 -3
  98. package/dist/test/helpers.d.ts.map +1 -1
  99. package/dist/test/helpers.js +267 -10
  100. package/dist/test/helpers.js.map +1 -1
  101. package/dist/tracking/ActionTracker.d.ts +49 -0
  102. package/dist/tracking/ActionTracker.d.ts.map +1 -0
  103. package/dist/tracking/ActionTracker.js +422 -0
  104. package/dist/tracking/ActionTracker.js.map +1 -0
  105. package/dist/tracking/ActionTracker.test.d.ts +2 -0
  106. package/dist/tracking/ActionTracker.test.d.ts.map +1 -0
  107. package/dist/tracking/ActionTracker.test.js +637 -0
  108. package/dist/tracking/ActionTracker.test.js.map +1 -0
  109. package/dist/tracking/IActionTracker.d.ts +101 -0
  110. package/dist/tracking/IActionTracker.d.ts.map +1 -0
  111. package/dist/tracking/IActionTracker.js +2 -0
  112. package/dist/tracking/IActionTracker.js.map +1 -0
  113. package/dist/tracking/InflightContextAdapter.d.ts +18 -0
  114. package/dist/tracking/InflightContextAdapter.d.ts.map +1 -0
  115. package/dist/tracking/InflightContextAdapter.js +35 -0
  116. package/dist/tracking/InflightContextAdapter.js.map +1 -0
  117. package/dist/tracking/InflightContextAdapter.test.d.ts +2 -0
  118. package/dist/tracking/InflightContextAdapter.test.d.ts.map +1 -0
  119. package/dist/tracking/InflightContextAdapter.test.js +172 -0
  120. package/dist/tracking/InflightContextAdapter.test.js.map +1 -0
  121. package/dist/tracking/index.d.ts +7 -0
  122. package/dist/tracking/index.d.ts.map +1 -0
  123. package/dist/tracking/index.js +6 -0
  124. package/dist/tracking/index.js.map +1 -0
  125. package/dist/tracking/store/IStore.d.ts +41 -0
  126. package/dist/tracking/store/IStore.d.ts.map +1 -0
  127. package/dist/tracking/store/IStore.js +2 -0
  128. package/dist/tracking/store/IStore.js.map +1 -0
  129. package/dist/tracking/store/InMemoryStore.d.ts +21 -0
  130. package/dist/tracking/store/InMemoryStore.d.ts.map +1 -0
  131. package/dist/tracking/store/InMemoryStore.js +40 -0
  132. package/dist/tracking/store/InMemoryStore.js.map +1 -0
  133. package/dist/tracking/store/InMemoryStore.test.d.ts +2 -0
  134. package/dist/tracking/store/InMemoryStore.test.d.ts.map +1 -0
  135. package/dist/tracking/store/InMemoryStore.test.js +290 -0
  136. package/dist/tracking/store/InMemoryStore.test.js.map +1 -0
  137. package/dist/tracking/store/index.d.ts +3 -0
  138. package/dist/tracking/store/index.d.ts.map +1 -0
  139. package/dist/tracking/store/index.js +2 -0
  140. package/dist/tracking/store/index.js.map +1 -0
  141. package/dist/tracking/types.d.ts +43 -0
  142. package/dist/tracking/types.d.ts.map +1 -0
  143. package/dist/tracking/types.js +2 -0
  144. package/dist/tracking/types.js.map +1 -0
  145. package/dist/utils/ExplorerClient.d.ts +39 -1
  146. package/dist/utils/ExplorerClient.d.ts.map +1 -1
  147. package/dist/utils/ExplorerClient.js +205 -2
  148. package/dist/utils/ExplorerClient.js.map +1 -1
  149. package/dist/utils/balanceUtils.js +2 -2
  150. package/dist/utils/balanceUtils.js.map +1 -1
  151. package/dist/utils/balanceUtils.test.js +1 -0
  152. package/dist/utils/balanceUtils.test.js.map +1 -1
  153. package/dist/utils/bridgeUtils.d.ts +1 -3
  154. package/dist/utils/bridgeUtils.d.ts.map +1 -1
  155. package/dist/utils/bridgeUtils.js +1 -5
  156. package/dist/utils/bridgeUtils.js.map +1 -1
  157. package/dist/utils/bridgeUtils.test.js +3 -14
  158. package/dist/utils/bridgeUtils.test.js.map +1 -1
  159. package/package.json +11 -9
  160. package/src/config/RebalancerConfig.test.ts +459 -163
  161. package/src/config/RebalancerConfig.ts +5 -3
  162. package/src/config/types.ts +159 -52
  163. package/src/core/Rebalancer.test.ts +632 -0
  164. package/src/core/Rebalancer.ts +247 -157
  165. package/src/core/RebalancerService.test.ts +1144 -0
  166. package/src/core/RebalancerService.ts +245 -23
  167. package/src/factories/RebalancerContextFactory.ts +115 -14
  168. package/src/index.ts +16 -4
  169. package/src/interfaces/IMonitor.ts +15 -8
  170. package/src/interfaces/IRebalancer.ts +22 -4
  171. package/src/interfaces/IStrategy.ts +23 -2
  172. package/src/metrics/Metrics.ts +26 -5
  173. package/src/metrics/scripts/metrics.ts +14 -0
  174. package/src/monitor/Monitor.ts +109 -22
  175. package/src/strategy/BaseStrategy.ts +316 -26
  176. package/src/strategy/CollateralDeficitStrategy.test.ts +551 -0
  177. package/src/strategy/CollateralDeficitStrategy.ts +390 -0
  178. package/src/strategy/CompositeStrategy.test.ts +405 -0
  179. package/src/strategy/CompositeStrategy.ts +102 -0
  180. package/src/strategy/MinAmountStrategy.test.ts +189 -88
  181. package/src/strategy/MinAmountStrategy.ts +44 -13
  182. package/src/strategy/StrategyFactory.test.ts +2 -2
  183. package/src/strategy/StrategyFactory.ts +91 -8
  184. package/src/strategy/WeightedStrategy.test.ts +187 -72
  185. package/src/strategy/WeightedStrategy.ts +41 -7
  186. package/src/strategy/index.ts +2 -0
  187. package/src/test/helpers.ts +418 -14
  188. package/src/tracking/ActionTracker.test.ts +783 -0
  189. package/src/tracking/ActionTracker.ts +647 -0
  190. package/src/tracking/IActionTracker.ts +140 -0
  191. package/src/tracking/InflightContextAdapter.test.ts +203 -0
  192. package/src/tracking/InflightContextAdapter.ts +42 -0
  193. package/src/tracking/index.ts +36 -0
  194. package/src/tracking/store/IStore.ts +48 -0
  195. package/src/tracking/store/InMemoryStore.test.ts +338 -0
  196. package/src/tracking/store/InMemoryStore.ts +58 -0
  197. package/src/tracking/store/index.ts +2 -0
  198. package/src/tracking/types.ts +74 -0
  199. package/src/utils/ExplorerClient.ts +266 -3
  200. package/src/utils/balanceUtils.test.ts +1 -0
  201. package/src/utils/balanceUtils.ts +2 -2
  202. package/src/utils/bridgeUtils.test.ts +3 -15
  203. package/src/utils/bridgeUtils.ts +0 -10
  204. package/dist/core/WithInflightGuard.d.ts +0 -20
  205. package/dist/core/WithInflightGuard.d.ts.map +0 -1
  206. package/dist/core/WithInflightGuard.js +0 -47
  207. package/dist/core/WithInflightGuard.js.map +0 -1
  208. package/dist/core/WithInflightGuard.test.d.ts +0 -2
  209. package/dist/core/WithInflightGuard.test.d.ts.map +0 -1
  210. package/dist/core/WithInflightGuard.test.js +0 -64
  211. package/dist/core/WithInflightGuard.test.js.map +0 -1
  212. package/dist/core/WithSemaphore.d.ts +0 -22
  213. package/dist/core/WithSemaphore.d.ts.map +0 -1
  214. package/dist/core/WithSemaphore.js +0 -67
  215. package/dist/core/WithSemaphore.js.map +0 -1
  216. package/dist/core/WithSemaphore.test.d.ts +0 -2
  217. package/dist/core/WithSemaphore.test.d.ts.map +0 -1
  218. package/dist/core/WithSemaphore.test.js +0 -83
  219. package/dist/core/WithSemaphore.test.js.map +0 -1
  220. package/src/core/WithInflightGuard.test.ts +0 -131
  221. package/src/core/WithInflightGuard.ts +0 -67
  222. package/src/core/WithSemaphore.test.ts +0 -111
  223. package/src/core/WithSemaphore.ts +0 -92
@@ -2,11 +2,37 @@ import type { Logger } from 'pino';
2
2
 
3
3
  export type InflightRebalanceQueryParams = {
4
4
  bridges: string[];
5
- domains: number[];
5
+ routersByDomain: Record<number, string>; // Domain ID → router address (derive routers and domains from this)
6
6
  txSender: string;
7
7
  limit?: number;
8
8
  };
9
9
 
10
+ export type UserTransferQueryParams = {
11
+ routersByDomain: Record<number, string>; // Domain ID → router address (derive routers and domains from this)
12
+ excludeTxSender: string; // Rebalancer address to exclude
13
+ limit?: number;
14
+ };
15
+
16
+ export type RebalanceActionQueryParams = {
17
+ bridges: string[]; // Bridge contract addresses
18
+ routersByDomain: Record<number, string>; // Domain ID → router address (derive routers and domains from this)
19
+ rebalancerAddress: string; // Only include rebalancer's txs
20
+ limit?: number;
21
+ };
22
+
23
+ export type ExplorerMessage = {
24
+ msg_id: string;
25
+ origin_domain_id: number;
26
+ destination_domain_id: number;
27
+ sender: string;
28
+ recipient: string;
29
+ origin_tx_hash: string;
30
+ origin_tx_sender: string;
31
+ origin_tx_recipient: string;
32
+ is_delivered: boolean;
33
+ message_body: string;
34
+ };
35
+
10
36
  export class ExplorerClient {
11
37
  constructor(private readonly baseUrl: string) {}
12
38
 
@@ -14,15 +40,43 @@ export class ExplorerClient {
14
40
  return addr.replace(/^0x/i, '\\x').toLowerCase();
15
41
  }
16
42
 
43
+ /**
44
+ * Normalize all hex fields in Explorer response from PostgreSQL bytea format (\\x) to standard hex (0x)
45
+ */
46
+ private normalizeExplorerMessage(msg: any): ExplorerMessage {
47
+ const normalizeHex = (hex: string): string => {
48
+ if (!hex) return hex;
49
+ return hex.startsWith('\\x') ? '0x' + hex.slice(2) : hex;
50
+ };
51
+
52
+ return {
53
+ msg_id: normalizeHex(msg.msg_id),
54
+ origin_domain_id: msg.origin_domain_id,
55
+ destination_domain_id: msg.destination_domain_id,
56
+ sender: normalizeHex(msg.sender),
57
+ recipient: normalizeHex(msg.recipient),
58
+ origin_tx_hash: normalizeHex(msg.origin_tx_hash),
59
+ origin_tx_sender: normalizeHex(msg.origin_tx_sender),
60
+ origin_tx_recipient: normalizeHex(msg.origin_tx_recipient),
61
+ is_delivered: msg.is_delivered,
62
+ message_body: normalizeHex(msg.message_body),
63
+ };
64
+ }
65
+
17
66
  async hasUndeliveredRebalance(
18
67
  params: InflightRebalanceQueryParams,
19
68
  logger: Logger,
20
69
  ): Promise<boolean> {
21
- const { bridges, domains, txSender, limit = 5 } = params;
70
+ const { bridges, routersByDomain, txSender, limit = 5 } = params;
71
+
72
+ // Derive routers and domains from routersByDomain
73
+ const routers = Object.values(routersByDomain);
74
+ const domains = Object.keys(routersByDomain).map(Number);
22
75
 
23
76
  const variables = {
24
77
  senders: bridges.map((a) => this.toBytea(a)),
25
78
  recipients: bridges.map((a) => this.toBytea(a)),
79
+ originTxRecipients: routers.map((a) => this.toBytea(a)),
26
80
  originDomains: domains,
27
81
  destDomains: domains,
28
82
  txSenders: [this.toBytea(txSender)],
@@ -35,6 +89,7 @@ export class ExplorerClient {
35
89
  query InflightRebalancesForRoute(
36
90
  $senders: [bytea!],
37
91
  $recipients: [bytea!],
92
+ $originTxRecipients: [bytea!],
38
93
  $originDomains: [Int!],
39
94
  $destDomains: [Int!],
40
95
  $txSenders: [bytea!],
@@ -46,6 +101,7 @@ export class ExplorerClient {
46
101
  { is_delivered: { _eq: false } },
47
102
  { sender: { _in: $senders } },
48
103
  { recipient: { _in: $recipients } },
104
+ { origin_tx_recipient: { _in: $originTxRecipients } },
49
105
  { origin_domain_id: { _in: $originDomains } },
50
106
  { destination_domain_id: { _in: $destDomains } },
51
107
  { origin_tx_sender: { _in: $txSenders } }
@@ -61,7 +117,9 @@ export class ExplorerClient {
61
117
  recipient
62
118
  origin_tx_hash
63
119
  origin_tx_sender
120
+ origin_tx_recipient
64
121
  is_delivered
122
+ message_body
65
123
  }
66
124
  }`;
67
125
 
@@ -94,6 +152,211 @@ export class ExplorerClient {
94
152
 
95
153
  logger.debug({ rows }, 'Explorer query rows');
96
154
 
97
- return rows.length > 0;
155
+ // Post-query validation: verify each message's origin domain matches the expected router
156
+ const validatedRows = rows.filter((msg: any) => {
157
+ const expectedRouter = routersByDomain[msg.origin_domain_id];
158
+ if (!expectedRouter) return false;
159
+ const normalizedMsgRouter = msg.origin_tx_recipient?.startsWith('\\x')
160
+ ? '0x' + msg.origin_tx_recipient.slice(2)
161
+ : msg.origin_tx_recipient;
162
+ return (
163
+ normalizedMsgRouter?.toLowerCase() === expectedRouter.toLowerCase()
164
+ );
165
+ });
166
+
167
+ logger.debug(
168
+ { totalRows: rows.length, validatedRows: validatedRows.length },
169
+ 'Post-query validation results',
170
+ );
171
+
172
+ return validatedRows.length > 0;
173
+ }
174
+
175
+ /**
176
+ * Query inflight user transfers from the Explorer.
177
+ * Returns transfers where sender/recipient are routers, excluding rebalancer's own transactions.
178
+ */
179
+ async getInflightUserTransfers(
180
+ params: UserTransferQueryParams,
181
+ logger: Logger,
182
+ ): Promise<ExplorerMessage[]> {
183
+ const { routersByDomain, excludeTxSender, limit = 100 } = params;
184
+
185
+ // Derive routers and domains from routersByDomain
186
+ const routers = Object.values(routersByDomain);
187
+ const domains = Object.keys(routersByDomain).map(Number);
188
+
189
+ const variables = {
190
+ senders: routers.map((a) => this.toBytea(a)),
191
+ recipients: routers.map((a) => this.toBytea(a)),
192
+ originDomains: domains,
193
+ destDomains: domains,
194
+ excludeTxSender: this.toBytea(excludeTxSender),
195
+ limit,
196
+ };
197
+
198
+ logger.debug({ variables }, 'Explorer getInflightUserTransfers query');
199
+
200
+ const query = `
201
+ query InflightUserTransfers(
202
+ $senders: [bytea!],
203
+ $recipients: [bytea!],
204
+ $originDomains: [Int!],
205
+ $destDomains: [Int!],
206
+ $excludeTxSender: bytea!,
207
+ $limit: Int = 100
208
+ ) {
209
+ message_view(
210
+ where: {
211
+ _and: [
212
+ { is_delivered: { _eq: false } },
213
+ { sender: { _in: $senders } },
214
+ { recipient: { _in: $recipients } },
215
+ { origin_domain_id: { _in: $originDomains } },
216
+ { destination_domain_id: { _in: $destDomains } },
217
+ { origin_tx_sender: { _neq: $excludeTxSender } }
218
+ ]
219
+ }
220
+ order_by: { origin_tx_id: desc }
221
+ limit: $limit
222
+ ) {
223
+ msg_id
224
+ origin_domain_id
225
+ destination_domain_id
226
+ sender
227
+ recipient
228
+ origin_tx_hash
229
+ origin_tx_sender
230
+ origin_tx_recipient
231
+ is_delivered
232
+ message_body
233
+ }
234
+ }`;
235
+
236
+ const res = await fetch(this.baseUrl, {
237
+ method: 'POST',
238
+ headers: { 'Content-Type': 'application/json' },
239
+ body: JSON.stringify({ query, variables }),
240
+ });
241
+
242
+ logger.debug(
243
+ { status: res.status },
244
+ 'Explorer getInflightUserTransfers response',
245
+ );
246
+
247
+ if (!res.ok) {
248
+ let errorDetails: string;
249
+ try {
250
+ const errorJson = await res.json();
251
+ errorDetails = JSON.stringify(errorJson);
252
+ } catch (_e) {
253
+ try {
254
+ errorDetails = await res.text();
255
+ } catch (_textError) {
256
+ errorDetails = 'Unable to read response body';
257
+ }
258
+ }
259
+ throw new Error(`Explorer query failed: ${res.status} ${errorDetails}`);
260
+ }
261
+
262
+ const json = await res.json();
263
+ const messages = json?.data?.message_view ?? [];
264
+ return messages.map((msg: any) => this.normalizeExplorerMessage(msg));
265
+ }
266
+
267
+ /**
268
+ * Query inflight rebalance actions from the Explorer.
269
+ * Returns messages where sender/recipient are bridges, tx sender is the rebalancer,
270
+ * and origin_tx_recipient is one of this warp route's routers.
271
+ */
272
+ async getInflightRebalanceActions(
273
+ params: RebalanceActionQueryParams,
274
+ logger: Logger,
275
+ ): Promise<ExplorerMessage[]> {
276
+ const { bridges, routersByDomain, rebalancerAddress, limit = 100 } = params;
277
+
278
+ // Derive routers and domains from routersByDomain
279
+ const routers = Object.values(routersByDomain);
280
+ const domains = Object.keys(routersByDomain).map(Number);
281
+
282
+ const variables = {
283
+ senders: bridges.map((a) => this.toBytea(a)),
284
+ recipients: bridges.map((a) => this.toBytea(a)),
285
+ originTxRecipients: routers.map((a) => this.toBytea(a)),
286
+ originDomains: domains,
287
+ destDomains: domains,
288
+ txSender: this.toBytea(rebalancerAddress),
289
+ limit,
290
+ };
291
+
292
+ logger.debug({ variables }, 'Explorer getInflightRebalanceActions query');
293
+
294
+ const query = `
295
+ query InflightRebalanceActions(
296
+ $senders: [bytea!],
297
+ $recipients: [bytea!],
298
+ $originTxRecipients: [bytea!],
299
+ $originDomains: [Int!],
300
+ $destDomains: [Int!],
301
+ $txSender: bytea!,
302
+ $limit: Int = 100
303
+ ) {
304
+ message_view(
305
+ where: {
306
+ _and: [
307
+ { is_delivered: { _eq: false } },
308
+ { sender: { _in: $senders } },
309
+ { recipient: { _in: $recipients } },
310
+ { origin_tx_recipient: { _in: $originTxRecipients } },
311
+ { origin_domain_id: { _in: $originDomains } },
312
+ { destination_domain_id: { _in: $destDomains } },
313
+ { origin_tx_sender: { _eq: $txSender } }
314
+ ]
315
+ }
316
+ order_by: { origin_tx_id: desc }
317
+ limit: $limit
318
+ ) {
319
+ msg_id
320
+ origin_domain_id
321
+ destination_domain_id
322
+ sender
323
+ recipient
324
+ origin_tx_hash
325
+ origin_tx_sender
326
+ origin_tx_recipient
327
+ is_delivered
328
+ message_body
329
+ }
330
+ }`;
331
+
332
+ const res = await fetch(this.baseUrl, {
333
+ method: 'POST',
334
+ headers: { 'Content-Type': 'application/json' },
335
+ body: JSON.stringify({ query, variables }),
336
+ });
337
+
338
+ logger.debug(
339
+ { status: res.status },
340
+ 'Explorer getInflightRebalanceActions response',
341
+ );
342
+
343
+ if (!res.ok) {
344
+ let errorDetails: string;
345
+ try {
346
+ const errorJson = await res.json();
347
+ errorDetails = JSON.stringify(errorJson);
348
+ } catch (_e) {
349
+ try {
350
+ errorDetails = await res.text();
351
+ } catch (_textError) {
352
+ errorDetails = 'Unable to read response body';
353
+ }
354
+ }
355
+ throw new Error(`Explorer query failed: ${res.status} ${errorDetails}`);
356
+ }
357
+
358
+ const json = await res.json();
359
+ const messages = json?.data?.message_view ?? [];
360
+ return messages.map((msg: any) => this.normalizeExplorerMessage(msg));
98
361
  }
99
362
  }
@@ -35,6 +35,7 @@ describe('getRawBalances', () => {
35
35
  bridgedSupply: tokenBridgedSupply,
36
36
  },
37
37
  ],
38
+ confirmedBlockTags: { mainnet: 1000 },
38
39
  };
39
40
  });
40
41
 
@@ -26,7 +26,7 @@ export function getRawBalances(
26
26
 
27
27
  // Ignore tokens that are not in the provided chains list
28
28
  if (!chainSet.has(token.chainName)) {
29
- logger.info(
29
+ logger.debug(
30
30
  {
31
31
  context: getRawBalances.name,
32
32
  chain: token.chainName,
@@ -40,7 +40,7 @@ export function getRawBalances(
40
40
 
41
41
  // Ignore tokens that are not collateralized or are otherwise ineligible
42
42
  if (!isCollateralizedTokenEligibleForRebalancing(token)) {
43
- logger.info(
43
+ logger.debug(
44
44
  {
45
45
  context: getRawBalances.name,
46
46
  chain: token.chainName,
@@ -1,5 +1,4 @@
1
1
  import { expect } from 'chai';
2
- import { pino } from 'pino';
3
2
 
4
3
  import { type ChainMap } from '@hyperlane-xyz/sdk';
5
4
 
@@ -8,29 +7,24 @@ import {
8
7
  getBridgeConfig,
9
8
  } from './bridgeUtils.js';
10
9
 
11
- const testLogger = pino({ level: 'silent' });
12
-
13
10
  describe('bridgeConfig', () => {
14
11
  it('should return the base bridge config when no overrides exist', () => {
15
12
  const bridges: ChainMap<BridgeConfigWithOverride> = {
16
13
  chain1: {
17
14
  bridge: '0x1234567890123456789012345678901234567890',
18
15
  bridgeMinAcceptedAmount: 1000,
19
- bridgeIsWarp: true,
20
16
  },
21
17
  chain2: {
22
18
  bridge: '0x0987654321098765432109876543210987654321',
23
19
  bridgeMinAcceptedAmount: 2000,
24
- bridgeIsWarp: true,
25
20
  },
26
21
  };
27
22
 
28
- const result = getBridgeConfig(bridges, 'chain1', 'chain2', testLogger);
23
+ const result = getBridgeConfig(bridges, 'chain1', 'chain2');
29
24
 
30
25
  expect(result).to.deep.equal({
31
26
  bridge: '0x1234567890123456789012345678901234567890',
32
27
  bridgeMinAcceptedAmount: 1000,
33
- bridgeIsWarp: true,
34
28
  });
35
29
  });
36
30
 
@@ -39,7 +33,6 @@ describe('bridgeConfig', () => {
39
33
  chain1: {
40
34
  bridge: '0x1234567890123456789012345678901234567890',
41
35
  bridgeMinAcceptedAmount: 1000,
42
- bridgeIsWarp: true,
43
36
  override: {
44
37
  chain2: {
45
38
  bridgeMinAcceptedAmount: 5000,
@@ -49,16 +42,14 @@ describe('bridgeConfig', () => {
49
42
  chain2: {
50
43
  bridge: '0x0987654321098765432109876543210987654321',
51
44
  bridgeMinAcceptedAmount: 2000,
52
- bridgeIsWarp: true,
53
45
  },
54
46
  };
55
47
 
56
- const result = getBridgeConfig(bridges, 'chain1', 'chain2', testLogger);
48
+ const result = getBridgeConfig(bridges, 'chain1', 'chain2');
57
49
 
58
50
  expect(result).to.deep.equal({
59
51
  bridge: '0x1234567890123456789012345678901234567890',
60
52
  bridgeMinAcceptedAmount: 5000,
61
- bridgeIsWarp: true,
62
53
  });
63
54
  });
64
55
 
@@ -67,7 +58,6 @@ describe('bridgeConfig', () => {
67
58
  chain1: {
68
59
  bridge: '0x1234567890123456789012345678901234567890',
69
60
  bridgeMinAcceptedAmount: 1000,
70
- bridgeIsWarp: true,
71
61
  override: {
72
62
  chain2: {
73
63
  bridge: '0xABCDEF0123456789ABCDEF0123456789ABCDEF01',
@@ -77,16 +67,14 @@ describe('bridgeConfig', () => {
77
67
  chain2: {
78
68
  bridge: '0x0987654321098765432109876543210987654321',
79
69
  bridgeMinAcceptedAmount: 2000,
80
- bridgeIsWarp: true,
81
70
  },
82
71
  };
83
72
 
84
- const result = getBridgeConfig(bridges, 'chain1', 'chain2', testLogger);
73
+ const result = getBridgeConfig(bridges, 'chain1', 'chain2');
85
74
 
86
75
  expect(result).to.deep.equal({
87
76
  bridge: '0xABCDEF0123456789ABCDEF0123456789ABCDEF01',
88
77
  bridgeMinAcceptedAmount: 1000,
89
- bridgeIsWarp: true,
90
78
  });
91
79
  });
92
80
  });
@@ -1,5 +1,3 @@
1
- import { type Logger } from 'pino';
2
-
3
1
  import type { ChainMap, ChainName } from '@hyperlane-xyz/sdk';
4
2
 
5
3
  export type BridgeConfigWithOverride = BridgeConfig & {
@@ -9,7 +7,6 @@ export type BridgeConfigWithOverride = BridgeConfig & {
9
7
  export type BridgeConfig = {
10
8
  bridge: string;
11
9
  bridgeMinAcceptedAmount: string | number;
12
- bridgeIsWarp: boolean;
13
10
  };
14
11
 
15
12
  /**
@@ -23,15 +20,8 @@ export function getBridgeConfig(
23
20
  bridges: ChainMap<BridgeConfigWithOverride>,
24
21
  fromChain: ChainName,
25
22
  toChain: ChainName,
26
- logger: Logger,
27
23
  ): BridgeConfig {
28
24
  const fromConfig = bridges[fromChain];
29
-
30
- if (!fromConfig) {
31
- logger.error({ fromChain }, 'Bridge config not found');
32
- throw new Error(`Bridge config not found for chain ${fromChain}`);
33
- }
34
-
35
25
  const routeSpecificOverrides = fromConfig.override?.[toChain];
36
26
 
37
27
  // Create a new object with the properties from bridgeConfig, excluding the overrides property
@@ -1,20 +0,0 @@
1
- import type { Logger } from 'pino';
2
- import { type ChainMetadataManager } from '@hyperlane-xyz/sdk';
3
- import { type RebalancerConfig } from '../config/RebalancerConfig.js';
4
- import type { IRebalancer } from '../interfaces/IRebalancer.js';
5
- import type { RebalancingRoute } from '../interfaces/IStrategy.js';
6
- import { type ExplorerClient } from '../utils/ExplorerClient.js';
7
- /**
8
- * Prevents rebalancing if there are inflight rebalances for the warp route.
9
- */
10
- export declare class WithInflightGuard implements IRebalancer {
11
- private readonly config;
12
- private readonly rebalancer;
13
- private readonly explorer;
14
- private readonly txSender;
15
- private readonly chainManager;
16
- private readonly logger;
17
- constructor(config: RebalancerConfig, rebalancer: IRebalancer, explorer: ExplorerClient, txSender: string, chainManager: ChainMetadataManager, logger: Logger);
18
- rebalance(routes: RebalancingRoute[]): Promise<void>;
19
- }
20
- //# sourceMappingURL=WithInflightGuard.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"WithInflightGuard.d.ts","sourceRoot":"","sources":["../../src/core/WithInflightGuard.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAEnC,OAAO,EAAE,KAAK,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAE/D,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AACnE,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAEjE;;GAEG;AACH,qBAAa,iBAAkB,YAAW,WAAW;IAIjD,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,YAAY;IAP/B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;gBAGb,MAAM,EAAE,gBAAgB,EACxB,UAAU,EAAE,WAAW,EACvB,QAAQ,EAAE,cAAc,EACxB,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,oBAAoB,EACnD,MAAM,EAAE,MAAM;IAKV,SAAS,CAAC,MAAM,EAAE,gBAAgB,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CAwC3D"}
@@ -1,47 +0,0 @@
1
- /**
2
- * Prevents rebalancing if there are inflight rebalances for the warp route.
3
- */
4
- export class WithInflightGuard {
5
- config;
6
- rebalancer;
7
- explorer;
8
- txSender;
9
- chainManager;
10
- logger;
11
- constructor(config, rebalancer, explorer, txSender, chainManager, logger) {
12
- this.config = config;
13
- this.rebalancer = rebalancer;
14
- this.explorer = explorer;
15
- this.txSender = txSender;
16
- this.chainManager = chainManager;
17
- this.logger = logger.child({ class: WithInflightGuard.name });
18
- }
19
- async rebalance(routes) {
20
- // Always enforce the inflight guard
21
- if (routes.length === 0) {
22
- return this.rebalancer.rebalance(routes);
23
- }
24
- const chains = Object.keys(this.config.strategyConfig.chains);
25
- const bridges = chains.map((chain) => this.config.strategyConfig.chains[chain].bridge);
26
- const domains = chains.map((chain) => this.chainManager.getDomainId(chain));
27
- let hasInflightRebalances = false;
28
- try {
29
- hasInflightRebalances = await this.explorer.hasUndeliveredRebalance({
30
- bridges,
31
- domains: Array.from(new Set(domains)),
32
- txSender: this.txSender,
33
- limit: 5,
34
- }, this.logger);
35
- }
36
- catch (e) {
37
- this.logger.error({ status: e.status, body: e.body }, 'Explorer inflight query failed');
38
- throw e;
39
- }
40
- if (hasInflightRebalances) {
41
- this.logger.info('Inflight rebalance detected via Explorer; skipping this cycle');
42
- return;
43
- }
44
- return this.rebalancer.rebalance(routes);
45
- }
46
- }
47
- //# sourceMappingURL=WithInflightGuard.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"WithInflightGuard.js","sourceRoot":"","sources":["../../src/core/WithInflightGuard.ts"],"names":[],"mappings":"AASA;;GAEG;AACH,MAAM,OAAO,iBAAiB;IAIT;IACA;IACA;IACA;IACA;IAPF,MAAM,CAAS;IAEhC,YACmB,MAAwB,EACxB,UAAuB,EACvB,QAAwB,EACxB,QAAgB,EAChB,YAAkC,EACnD,MAAc;QALG,WAAM,GAAN,MAAM,CAAkB;QACxB,eAAU,GAAV,UAAU,CAAa;QACvB,aAAQ,GAAR,QAAQ,CAAgB;QACxB,aAAQ,GAAR,QAAQ,CAAQ;QAChB,iBAAY,GAAZ,YAAY,CAAsB;QAGnD,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,iBAAiB,CAAC,IAAI,EAAE,CAAC,CAAC;IAChE,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,MAA0B;QACxC,oCAAoC;QACpC,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACxB,OAAO,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QAC3C,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;QAC9D,MAAM,OAAO,GAAG,MAAM,CAAC,GAAG,CACxB,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAC3D,CAAC;QACF,MAAM,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC;QAE5E,IAAI,qBAAqB,GAAG,KAAK,CAAC;QAClC,IAAI,CAAC;YACH,qBAAqB,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,uBAAuB,CACjE;gBACE,OAAO;gBACP,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC;gBACrC,QAAQ,EAAE,IAAI,CAAC,QAAQ;gBACvB,KAAK,EAAE,CAAC;aACT,EACD,IAAI,CAAC,MAAM,CACZ,CAAC;QACJ,CAAC;QAAC,OAAO,CAAM,EAAE,CAAC;YAChB,IAAI,CAAC,MAAM,CAAC,KAAK,CACf,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,EAClC,gCAAgC,CACjC,CAAC;YACF,MAAM,CAAC,CAAC;QACV,CAAC;QAED,IAAI,qBAAqB,EAAE,CAAC;YAC1B,IAAI,CAAC,MAAM,CAAC,IAAI,CACd,+DAA+D,CAChE,CAAC;YACF,OAAO;QACT,CAAC;QAED,OAAO,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IAC3C,CAAC;CACF"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=WithInflightGuard.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"WithInflightGuard.test.d.ts","sourceRoot":"","sources":["../../src/core/WithInflightGuard.test.ts"],"names":[],"mappings":""}
@@ -1,64 +0,0 @@
1
- import chai, { expect } from 'chai';
2
- import chaiAsPromised from 'chai-as-promised';
3
- import { ethers } from 'ethers';
4
- import { pino } from 'pino';
5
- import Sinon from 'sinon';
6
- import { chainMetadata } from '@hyperlane-xyz/registry';
7
- import { ChainMetadataManager } from '@hyperlane-xyz/sdk';
8
- import { MockRebalancer, buildTestConfig } from '../test/helpers.js';
9
- import { ExplorerClient } from '../utils/ExplorerClient.js';
10
- import { WithInflightGuard } from './WithInflightGuard.js';
11
- chai.use(chaiAsPromised);
12
- const testLogger = pino({ level: 'silent' });
13
- describe('WithInflightGuard', () => {
14
- it('forwards empty routes without calling Explorer', async () => {
15
- const config = buildTestConfig();
16
- const rebalancer = new MockRebalancer();
17
- const rebalanceSpy = Sinon.spy(rebalancer, 'rebalance');
18
- const explorer = new ExplorerClient('http://localhost');
19
- const explorerSpy = Sinon.stub(explorer, 'hasUndeliveredRebalance');
20
- const guard = new WithInflightGuard(config, rebalancer, explorer, ethers.Wallet.createRandom().address, new ChainMetadataManager(chainMetadata), testLogger);
21
- await guard.rebalance([]);
22
- expect(explorerSpy.called).to.be.false;
23
- expect(rebalanceSpy.calledOnce).to.be.true;
24
- expect(rebalanceSpy.calledWith([])).to.be.true;
25
- });
26
- it('calls underlying rebalancer when no inflight is detected', async () => {
27
- const config = buildTestConfig({}, ['ethereum', 'arbitrum']);
28
- const routes = [{ origin: 'ethereum' }];
29
- const rebalancer = new MockRebalancer();
30
- const rebalanceSpy = Sinon.spy(rebalancer, 'rebalance');
31
- const explorer = new ExplorerClient('http://localhost');
32
- const explorerSpy = Sinon.stub(explorer, 'hasUndeliveredRebalance').resolves(false);
33
- const guard = new WithInflightGuard(config, rebalancer, explorer, ethers.Wallet.createRandom().address, new ChainMetadataManager(chainMetadata), testLogger);
34
- await guard.rebalance(routes);
35
- expect(explorerSpy.calledOnce).to.be.true;
36
- expect(rebalanceSpy.calledOnce).to.be.true;
37
- expect(rebalanceSpy.calledWith(routes)).to.be.true;
38
- });
39
- it('skips rebalancing when inflight is detected', async () => {
40
- const config = buildTestConfig({}, ['ethereum', 'arbitrum']);
41
- const routes = [{ origin: 'ethereum' }];
42
- const rebalancer = new MockRebalancer();
43
- const rebalanceSpy = Sinon.spy(rebalancer, 'rebalance');
44
- const explorer = new ExplorerClient('http://localhost');
45
- const explorerSpy = Sinon.stub(explorer, 'hasUndeliveredRebalance').resolves(true);
46
- const guard = new WithInflightGuard(config, rebalancer, explorer, ethers.Wallet.createRandom().address, new ChainMetadataManager(chainMetadata), testLogger);
47
- await guard.rebalance(routes);
48
- expect(explorerSpy.calledOnce).to.be.true;
49
- expect(rebalanceSpy.called).to.be.false;
50
- });
51
- it('propagates explorer query error', async () => {
52
- const config = buildTestConfig({}, ['ethereum', 'arbitrum']);
53
- const routes = [{ origin: 'ethereum' }];
54
- const rebalancer = new MockRebalancer();
55
- const rebalanceSpy = Sinon.spy(rebalancer, 'rebalance');
56
- const explorer = new ExplorerClient('http://localhost');
57
- const explorerSpy = Sinon.stub(explorer, 'hasUndeliveredRebalance').rejects(new Error('Explorer HTTP 405'));
58
- const guard = new WithInflightGuard(config, rebalancer, explorer, ethers.Wallet.createRandom().address, new ChainMetadataManager(chainMetadata), testLogger);
59
- await expect(guard.rebalance(routes)).to.be.rejectedWith('Explorer HTTP 405');
60
- expect(explorerSpy.calledOnce).to.be.true;
61
- expect(rebalanceSpy.called).to.be.false;
62
- });
63
- });
64
- //# sourceMappingURL=WithInflightGuard.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"WithInflightGuard.test.js","sourceRoot":"","sources":["../../src/core/WithInflightGuard.test.ts"],"names":[],"mappings":"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"}
@@ -1,22 +0,0 @@
1
- import type { Logger } from 'pino';
2
- import { type RebalancerConfig } from '../config/RebalancerConfig.js';
3
- import type { IRebalancer } from '../interfaces/IRebalancer.js';
4
- import type { RebalancingRoute } from '../interfaces/IStrategy.js';
5
- /**
6
- * Prevents frequent rebalancing operations while bridges complete.
7
- */
8
- export declare class WithSemaphore implements IRebalancer {
9
- private readonly config;
10
- private readonly rebalancer;
11
- private waitUntil;
12
- private executing;
13
- private readonly logger;
14
- constructor(config: RebalancerConfig, rebalancer: IRebalancer, logger: Logger);
15
- /**
16
- * Rebalance with timing control
17
- * @param routes - Routes to process
18
- */
19
- rebalance(routes: RebalancingRoute[]): Promise<void>;
20
- private getHighestLockTime;
21
- }
22
- //# sourceMappingURL=WithSemaphore.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"WithSemaphore.d.ts","sourceRoot":"","sources":["../../src/core/WithSemaphore.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAEnC,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAEnE;;GAEG;AACH,qBAAa,aAAc,YAAW,WAAW;IAQ7C,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAP7B,OAAO,CAAC,SAAS,CAAa;IAE9B,OAAO,CAAC,SAAS,CAAkB;IACnC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;gBAGb,MAAM,EAAE,gBAAgB,EACxB,UAAU,EAAE,WAAW,EACxC,MAAM,EAAE,MAAM;IAKhB;;;OAGG;IACG,SAAS,CAAC,MAAM,EAAE,gBAAgB,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IA+C1D,OAAO,CAAC,kBAAkB;CAgB3B"}