@xyo-network/chain-bridge 1.23.0 → 2.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 (120) hide show
  1. package/dist/node/BridgeActor.d.ts +1 -0
  2. package/dist/node/BridgeActor.d.ts.map +1 -1
  3. package/dist/node/index.mjs +2056 -1407
  4. package/dist/node/index.mjs.map +7 -1
  5. package/dist/node/server/routes/bridge/routeDefinitions/getRouteDefinitions.d.ts.map +1 -1
  6. package/dist/node/server/routes/bridge/routeDefinitions/pathParams/ChainIdPathParam.d.ts +2 -1
  7. package/dist/node/server/routes/bridge/routeDefinitions/pathParams/ChainIdPathParam.d.ts.map +1 -1
  8. package/dist/node/server/routes/bridge/routeDefinitions/routes/bridgeConfig.d.ts +0 -22
  9. package/dist/node/server/routes/bridge/routeDefinitions/routes/bridgeConfig.d.ts.map +1 -1
  10. package/dist/node/server/routes/bridge/routeDefinitions/routes/bridgeFromRemoteEstimate.d.ts +4 -0
  11. package/dist/node/server/routes/bridge/routeDefinitions/routes/bridgeFromRemoteEstimate.d.ts.map +1 -0
  12. package/dist/node/server/routes/bridge/routeDefinitions/routes/bridgeFromRemoteRetry.d.ts +10 -0
  13. package/dist/node/server/routes/bridge/routeDefinitions/routes/bridgeFromRemoteRetry.d.ts.map +1 -0
  14. package/dist/node/server/routes/bridge/routeDefinitions/routes/bridgeFromRemoteRetryFailed.d.ts +9 -0
  15. package/dist/node/server/routes/bridge/routeDefinitions/routes/bridgeFromRemoteRetryFailed.d.ts.map +1 -0
  16. package/dist/node/server/routes/bridge/routeDefinitions/routes/bridgeFromRemoteStatus.d.ts +0 -81
  17. package/dist/node/server/routes/bridge/routeDefinitions/routes/bridgeFromRemoteStatus.d.ts.map +1 -1
  18. package/dist/node/server/routes/bridge/routeDefinitions/routes/bridgeFromRemoteStatusByTx.d.ts +28 -0
  19. package/dist/node/server/routes/bridge/routeDefinitions/routes/bridgeFromRemoteStatusByTx.d.ts.map +1 -0
  20. package/dist/node/server/routes/bridge/routeDefinitions/routes/bridgeToRemote.d.ts +0 -81
  21. package/dist/node/server/routes/bridge/routeDefinitions/routes/bridgeToRemote.d.ts.map +1 -1
  22. package/dist/node/server/routes/bridge/routeDefinitions/routes/bridgeToRemoteEstimate.d.ts +0 -72
  23. package/dist/node/server/routes/bridge/routeDefinitions/routes/bridgeToRemoteEstimate.d.ts.map +1 -1
  24. package/dist/node/server/routes/bridge/routeDefinitions/routes/bridgeToRemoteMaxEstimate.d.ts +0 -72
  25. package/dist/node/server/routes/bridge/routeDefinitions/routes/bridgeToRemoteMaxEstimate.d.ts.map +1 -1
  26. package/dist/node/server/routes/bridge/routeDefinitions/routes/bridgeToRemoteRetry.d.ts +10 -0
  27. package/dist/node/server/routes/bridge/routeDefinitions/routes/bridgeToRemoteRetry.d.ts.map +1 -0
  28. package/dist/node/server/routes/bridge/routeDefinitions/routes/bridgeToRemoteRetryFailed.d.ts +9 -0
  29. package/dist/node/server/routes/bridge/routeDefinitions/routes/bridgeToRemoteRetryFailed.d.ts.map +1 -0
  30. package/dist/node/server/routes/bridge/routeDefinitions/routes/bridgeToRemoteStatus.d.ts +0 -81
  31. package/dist/node/server/routes/bridge/routeDefinitions/routes/bridgeToRemoteStatus.d.ts.map +1 -1
  32. package/dist/node/server/routes/bridge/routeDefinitions/routes/index.d.ts +6 -0
  33. package/dist/node/server/routes/bridge/routeDefinitions/routes/index.d.ts.map +1 -1
  34. package/dist/node/server/server.d.ts +3 -1
  35. package/dist/node/server/server.d.ts.map +1 -1
  36. package/dist/node/services/BridgeFulfillmentState.d.ts +22 -13
  37. package/dist/node/services/BridgeFulfillmentState.d.ts.map +1 -1
  38. package/dist/node/services/IBridgeServiceCollection.d.ts +12 -1
  39. package/dist/node/services/IBridgeServiceCollection.d.ts.map +1 -1
  40. package/dist/node/services/evm/getFeeStructure.d.ts +1 -1
  41. package/dist/node/services/evm/getFeeStructure.d.ts.map +1 -1
  42. package/dist/node/services/evm/getRemoteConfirmationDepth.d.ts.map +1 -1
  43. package/dist/node/services/evm/index.d.ts +1 -0
  44. package/dist/node/services/evm/index.d.ts.map +1 -1
  45. package/dist/node/services/evm/resolveDeployBlock.d.ts +28 -0
  46. package/dist/node/services/evm/resolveDeployBlock.d.ts.map +1 -0
  47. package/dist/node/services/getServices.d.ts +3 -1
  48. package/dist/node/services/getServices.d.ts.map +1 -1
  49. package/dist/node/services/queue/flows/createEthToXl1BridgeJob/createEthToXl1BridgeJob.d.ts +1 -1
  50. package/dist/node/services/queue/flows/createEthToXl1BridgeJob/getJobIdForEthToXl1BridgeJob.d.ts +2 -13
  51. package/dist/node/services/queue/flows/createEthToXl1BridgeJob/getJobIdForEthToXl1BridgeJob.d.ts.map +1 -1
  52. package/dist/node/services/queue/index.d.ts +2 -0
  53. package/dist/node/services/queue/index.d.ts.map +1 -1
  54. package/dist/node/services/queue/retryFailedJobs.d.ts +39 -0
  55. package/dist/node/services/queue/retryFailedJobs.d.ts.map +1 -0
  56. package/dist/node/services/queue/retrySingleFailedJob.d.ts +29 -0
  57. package/dist/node/services/queue/retrySingleFailedJob.d.ts.map +1 -0
  58. package/dist/node/services/queue/scanner/EvmBridgeCursor.d.ts +1 -0
  59. package/dist/node/services/queue/scanner/EvmBridgeCursor.d.ts.map +1 -1
  60. package/dist/node/services/queue/scanner/EvmBridgeScanner.d.ts +1 -0
  61. package/dist/node/services/queue/scanner/EvmBridgeScanner.d.ts.map +1 -1
  62. package/dist/node/services/queue/scanner/EvmBridgeScannerRunner.d.ts +1 -2
  63. package/dist/node/services/queue/scanner/EvmBridgeScannerRunner.d.ts.map +1 -1
  64. package/dist/node/services/queue/scanner/buildEvmBridgeScannerRunner.d.ts +0 -3
  65. package/dist/node/services/queue/scanner/buildEvmBridgeScannerRunner.d.ts.map +1 -1
  66. package/dist/node/services/queue/workers/EthEventVerification.d.ts.map +1 -1
  67. package/dist/node/services/queue/workers/EthToXl1BridgeParent.d.ts.map +1 -1
  68. package/dist/node/services/queue/workers/EthTransactionMonitor.d.ts.map +1 -1
  69. package/dist/node/services/queue/workers/EthTransactionPreparation.d.ts.map +1 -1
  70. package/dist/node/services/queue/workers/EthTransactionSubmission.d.ts.map +1 -1
  71. package/dist/node/services/queue/workers/EthTransactionSubmissionStorage.d.ts.map +1 -1
  72. package/dist/node/services/queue/workers/Xl1ReserveTxFulfillment.d.ts.map +1 -1
  73. package/dist/node/services/queue/workers/Xl1ToEthBridgeParent.d.ts.map +1 -1
  74. package/dist/node/services/queue/workers/Xl1TransactionMonitor.d.ts.map +1 -1
  75. package/dist/node/services/queue/workers/Xl1TransactionPreparation.d.ts.map +1 -1
  76. package/dist/node/services/queue/workers/Xl1TransactionSubmission.d.ts.map +1 -1
  77. package/dist/node/services/queue/workers/Xl1TransactionSubmissionStorage.d.ts.map +1 -1
  78. package/dist/node/services/queue/workers/util/buildAcceptedSnapshot.d.ts +47 -0
  79. package/dist/node/services/queue/workers/util/buildAcceptedSnapshot.d.ts.map +1 -0
  80. package/dist/node/services/queue/workers/util/buildEthToXl1ReserveTx.d.ts +22 -6
  81. package/dist/node/services/queue/workers/util/buildEthToXl1ReserveTx.d.ts.map +1 -1
  82. package/dist/node/services/queue/workers/util/index.d.ts +1 -0
  83. package/dist/node/services/queue/workers/util/index.d.ts.map +1 -1
  84. package/dist/node/services/queue/workers/util/resolveEvmBlockTagAtDepth.d.ts +22 -7
  85. package/dist/node/services/queue/workers/util/resolveEvmBlockTagAtDepth.d.ts.map +1 -1
  86. package/dist/node/services/queue/workers/util/verifyEthBridgeEvent.d.ts +7 -4
  87. package/dist/node/services/queue/workers/util/verifyEthBridgeEvent.d.ts.map +1 -1
  88. package/dist/node/services/util/generateBridgeEstimate.d.ts.map +1 -1
  89. package/dist/node/services/util/index.d.ts +0 -5
  90. package/dist/node/services/util/index.d.ts.map +1 -1
  91. package/dist/node/services/validation/index.d.ts +1 -0
  92. package/dist/node/services/validation/index.d.ts.map +1 -1
  93. package/dist/node/services/validation/validateAmountMeetsMinBridgeAmount.d.ts +20 -0
  94. package/dist/node/services/validation/validateAmountMeetsMinBridgeAmount.d.ts.map +1 -0
  95. package/dist/node/services/validation/validateBridgeEstimate.d.ts.map +1 -1
  96. package/dist/node/services/validation/validateSufficientXl1ReserveBalance.d.ts +15 -10
  97. package/dist/node/services/validation/validateSufficientXl1ReserveBalance.d.ts.map +1 -1
  98. package/dist/node/telemetry/bucketFailureReason.d.ts +17 -0
  99. package/dist/node/telemetry/bucketFailureReason.d.ts.map +1 -0
  100. package/dist/node/telemetry/createBalanceMonitor.d.ts +5 -0
  101. package/dist/node/telemetry/createBalanceMonitor.d.ts.map +1 -1
  102. package/dist/node/telemetry/createBridgeFlowMetrics.d.ts +76 -0
  103. package/dist/node/telemetry/createBridgeFlowMetrics.d.ts.map +1 -0
  104. package/dist/node/telemetry/createInFlightPoller.d.ts +29 -0
  105. package/dist/node/telemetry/createInFlightPoller.d.ts.map +1 -0
  106. package/dist/node/telemetry/createQueueMetrics.d.ts +4 -0
  107. package/dist/node/telemetry/createQueueMetrics.d.ts.map +1 -1
  108. package/dist/node/telemetry/index.d.ts +3 -0
  109. package/dist/node/telemetry/index.d.ts.map +1 -1
  110. package/package.json +98 -97
  111. package/dist/node/services/util/BridgeFees.d.ts +0 -13
  112. package/dist/node/services/util/BridgeFees.d.ts.map +0 -1
  113. package/dist/node/services/util/bridgeFeesAsBigInt.d.ts +0 -7
  114. package/dist/node/services/util/bridgeFeesAsBigInt.d.ts.map +0 -1
  115. package/dist/node/services/util/calculateBridgeFees.d.ts +0 -6
  116. package/dist/node/services/util/calculateBridgeFees.d.ts.map +0 -1
  117. package/dist/node/services/util/calculateMaxBridgeAmount.d.ts +0 -11
  118. package/dist/node/services/util/calculateMaxBridgeAmount.d.ts.map +0 -1
  119. package/dist/node/services/util/createBridgeTransfer.d.ts +0 -14
  120. package/dist/node/services/util/createBridgeTransfer.d.ts.map +0 -1
@@ -1,5 +1,15 @@
1
1
  var __defProp = Object.defineProperty;
2
- var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
4
+ var __decorateClass = (decorators, target, key, kind) => {
5
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
6
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
7
+ if (decorator = decorators[i])
8
+ result = (kind ? decorator(target, key, result) : decorator(result)) || result;
9
+ if (kind && result) __defProp(target, key, result);
10
+ return result;
11
+ };
12
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
3
13
 
4
14
  // src/BridgeActor.ts
5
15
  import { creatable } from "@xylabs/sdk-js";
@@ -16,7 +26,7 @@ import { isDefined } from "@xylabs/sdk-js";
16
26
  import { Redis } from "ioredis";
17
27
  var connection;
18
28
  var maxRetriesPerRequest = null;
19
- var getConnection = /* @__PURE__ */ __name((config) => {
29
+ var getConnection = (config) => {
20
30
  if (isDefined(connection)) return connection;
21
31
  const { redisHost: host, redisPort: port } = config;
22
32
  connection = new Redis({
@@ -25,7 +35,7 @@ var getConnection = /* @__PURE__ */ __name((config) => {
25
35
  maxRetriesPerRequest
26
36
  });
27
37
  return connection;
28
- }, "getConnection");
38
+ };
29
39
 
30
40
  // src/services/queue/flowProducer.ts
31
41
  import { isDefined as isDefined2 } from "@xylabs/sdk-js";
@@ -36,7 +46,7 @@ var prefix = "xl1-bridge";
36
46
 
37
47
  // src/services/queue/flowProducer.ts
38
48
  var flowProducer;
39
- var getFlowProducer = /* @__PURE__ */ __name((connection2, telemetry2) => {
49
+ var getFlowProducer = (connection2, telemetry2) => {
40
50
  if (isDefined2(flowProducer)) return flowProducer;
41
51
  flowProducer = new FlowProducer({
42
52
  connection: connection2,
@@ -44,355 +54,392 @@ var getFlowProducer = /* @__PURE__ */ __name((connection2, telemetry2) => {
44
54
  prefix
45
55
  });
46
56
  return flowProducer;
47
- }, "getFlowProducer");
57
+ };
48
58
 
49
59
  // src/services/queue/workers/EthEventVerification.ts
50
- import { assertEx as assertEx2, isNull } from "@xylabs/sdk-js";
60
+ import {
61
+ assertEx as assertEx7,
62
+ isNull,
63
+ spanAsync as spanAsync4
64
+ } from "@xylabs/sdk-js";
51
65
  import { UnrecoverableError, Worker } from "bullmq";
52
66
 
53
- // src/services/queue/workers/util/buildEthToXl1ReserveTx.ts
54
- import { toHex } from "@xylabs/sdk-js";
55
- import { PayloadBuilder } from "@xyo-network/sdk-js";
56
- import { BridgeIntentSchema, BridgeSourceObservationSchema, buildTransaction, createTransferPayload } from "@xyo-network/xl1-sdk";
57
- async function buildEthToXl1ReserveTx(options2) {
58
- const { amount, bridgeAccount, bridgeId, destAddress, evmChainId, evmContractAddress, evmSrcAddress, evmTokenAddress, evmTxHash, exp, nbf, xl1ChainId, xl1TokenAddress } = options2;
59
- const amountHex = toHex(amount);
60
- const nonce = `evm:${evmChainId.toLowerCase()}:${evmContractAddress.toLowerCase()}:${bridgeId.toString()}`;
61
- const transfer = createTransferPayload(bridgeAccount.address, {
62
- [destAddress]: amount
63
- });
64
- const intent = new PayloadBuilder({
65
- schema: BridgeIntentSchema
66
- }).fields({
67
- dest: xl1ChainId,
68
- destAddress,
69
- destAmount: amountHex,
70
- destToken: xl1TokenAddress,
71
- nonce,
72
- src: evmChainId,
73
- srcAddress: evmSrcAddress,
74
- srcAmount: amountHex,
75
- srcToken: evmTokenAddress
76
- }).build();
77
- const sourceObservation = new PayloadBuilder({
78
- schema: BridgeSourceObservationSchema
79
- }).fields({
80
- dest: xl1ChainId,
81
- destAddress,
82
- destAmount: amountHex,
83
- destToken: xl1TokenAddress,
84
- src: evmChainId,
85
- srcAddress: evmSrcAddress,
86
- srcAmount: amountHex,
87
- srcConfirmation: evmTxHash,
88
- srcToken: evmTokenAddress
89
- }).build();
90
- return buildTransaction(xl1ChainId, [
91
- transfer
92
- ], [
93
- intent,
94
- sourceObservation
95
- ], bridgeAccount, nbf, exp);
67
+ // src/telemetry/bucketFailureReason.ts
68
+ function bucketFailureReason(failedReason) {
69
+ if (/below_min_bridge_amount/i.test(failedReason)) return "below_min_bridge_amount";
70
+ if (/reserve below required|reserve_insufficient/i.test(failedReason)) return "reserve_insufficient";
71
+ if (/bridgestoremote slot empty|orphaned by reorg|non-canonical at/i.test(failedReason)) return "orphaned_at_depth";
72
+ if (/attempts? exhausted|attempt \d+ expired/i.test(failedReason)) return "attempts_exhausted";
73
+ return "other";
96
74
  }
97
- __name(buildEthToXl1ReserveTx, "buildEthToXl1ReserveTx");
98
-
99
- // src/services/queue/workers/util/resolveEvmBlockTagAtDepth.ts
100
- async function resolveEvmBlockTagAtDepth(provider, depth) {
101
- if (depth === "finalized") return "finalized";
102
- const head = await provider.getBlockNumber();
103
- return Math.max(head - depth, 0);
104
- }
105
- __name(resolveEvmBlockTagAtDepth, "resolveEvmBlockTagAtDepth");
106
-
107
- // src/services/queue/workers/util/submitEthTransaction.ts
108
- import { assertEx, hexToBigInt, toEthAddress } from "@xylabs/sdk-js";
109
- import { PayloadBuilder as PayloadBuilder2 } from "@xyo-network/sdk-js";
110
- import { isBridgeIntent } from "@xyo-network/xl1-sdk";
111
- var submitEthTransaction = /* @__PURE__ */ __name(async (tx, offChainPayloads, bridge, wallet) => {
112
- const xl1Transaction = assertEx(tx[0], () => "No corresponding XL1 transaction found");
113
- const allPayloads = [
114
- ...tx[1],
115
- ...offChainPayloads
116
- ];
117
- const bridgeIntent = assertEx(allPayloads.find(isBridgeIntent), () => "No bridge intent found");
118
- const srcAddress = toEthAddress(bridgeIntent.srcAddress);
119
- const destAddress = toEthAddress(bridgeIntent.destAddress);
120
- const amount = hexToBigInt(bridgeIntent.destAmount);
121
- const nonce = hexToBigInt(await PayloadBuilder2.hash(xl1Transaction));
122
- const bridgeTx = await bridge.connect(wallet).bridgeFromRemote(srcAddress, destAddress, amount, nonce);
123
- const receipt = await bridgeTx.wait(1);
124
- return receipt?.hash;
125
- }, "submitEthTransaction");
126
-
127
- // src/services/queue/workers/util/submitXl1Transaction.ts
128
- var submitXl1Transaction = /* @__PURE__ */ __name(async (preparedTx, offChain = [], gateway) => {
129
- const result = await gateway.addTransactionToChain(preparedTx, offChain);
130
- return result;
131
- }, "submitXl1Transaction");
132
75
 
133
- // src/services/queue/workers/util/verifyEthBridgeEvent.ts
134
- import { asHex, toAddress } from "@xylabs/sdk-js";
135
- import { ZeroAddress } from "ethers";
136
- async function verifyEthBridgeEvent(id, bridge, provider, confirmationDepth) {
137
- const blockTag = await resolveEvmBlockTagAtDepth(provider, confirmationDepth);
138
- const data = await bridge.bridgesToRemote(id, {
139
- blockTag
140
- });
141
- if (data.srcAddress === ZeroAddress) {
142
- return null;
143
- }
144
- const filter = bridge.filters.BridgedToRemote(id);
145
- const events = await bridge.queryFilter(filter, 0, blockTag);
146
- const event = events[0];
147
- if (event === void 0) {
148
- return null;
76
+ // src/telemetry/createBalanceMonitor.ts
77
+ import { spanAsync } from "@xylabs/sdk-js";
78
+ var DEFAULT_INTERVAL_MS = 6e4;
79
+ var WEI_PER_GWEI = 10n ** 9n;
80
+ var TOKEN_DECIMALS = 10n ** 18n;
81
+ function createBalanceMonitor(config) {
82
+ const {
83
+ account,
84
+ bridge,
85
+ bridgeableToken,
86
+ gateway,
87
+ meter,
88
+ provider,
89
+ remoteChainId,
90
+ wallet,
91
+ intervalMs = DEFAULT_INTERVAL_MS
92
+ } = config;
93
+ let timer;
94
+ const ethWalletGasBalance = meter.createGauge(
95
+ "bridge_eth_wallet_gas_balance_gwei",
96
+ { description: "ETH balance of the bridge runner wallet (in gwei)", unit: "gwei" }
97
+ );
98
+ const liquidityTokenBalance = meter.createGauge(
99
+ "bridge_eth_liquidity_token_balance",
100
+ { description: "ERC-20 token balance of the liquidity source (in whole tokens)", unit: "tokens" }
101
+ );
102
+ const liquidityTokenAllowance = meter.createGauge(
103
+ "bridge_eth_liquidity_token_allowance",
104
+ { description: "ERC-20 token allowance from liquidity source to bridge contract (in whole tokens)", unit: "tokens" }
105
+ );
106
+ const xl1AccountBalance = meter.createGauge(
107
+ "bridge_xl1_account_balance",
108
+ { description: "XL1 native balance of the bridge reserve account (in whole XL1)", unit: "xl1" }
109
+ );
110
+ const walletAddress = wallet.address;
111
+ async function poll() {
112
+ await spanAsync("bridge:balance-monitor:poll", async () => {
113
+ try {
114
+ const balance = await provider.getBalance(walletAddress);
115
+ ethWalletGasBalance.record(Number(balance / WEI_PER_GWEI), { address: walletAddress, remoteChainId });
116
+ } catch (err) {
117
+ console.error("[BalanceMonitor] Failed to read ETH wallet gas balance:", err);
118
+ }
119
+ try {
120
+ const liquiditySourceAddress = await bridge.liquiditySource();
121
+ const balance = await bridgeableToken.balanceOf(liquiditySourceAddress);
122
+ liquidityTokenBalance.record(Number(balance / TOKEN_DECIMALS), { address: liquiditySourceAddress, remoteChainId });
123
+ } catch (err) {
124
+ console.error("[BalanceMonitor] Failed to read liquidity source token balance:", err);
125
+ }
126
+ try {
127
+ const liquiditySourceAddress = await bridge.liquiditySource();
128
+ const bridgeAddress = await bridge.getAddress();
129
+ const allowance = await bridgeableToken.allowance(liquiditySourceAddress, bridgeAddress);
130
+ liquidityTokenAllowance.record(Number(allowance / TOKEN_DECIMALS), { address: liquiditySourceAddress, remoteChainId });
131
+ } catch (err) {
132
+ console.error("[BalanceMonitor] Failed to read liquidity source token allowance:", err);
133
+ }
134
+ try {
135
+ const viewer = gateway.connection.viewer;
136
+ if (viewer) {
137
+ const balance = await viewer.account.balance.accountBalance(account.address);
138
+ xl1AccountBalance.record(Number(balance / TOKEN_DECIMALS), { address: account.address.toString(), remoteChainId });
139
+ }
140
+ } catch (err) {
141
+ console.error("[BalanceMonitor] Failed to read XL1 account balance:", err);
142
+ }
143
+ }, { timeBudgetLimit: 2e3 });
149
144
  }
150
145
  return {
151
- amount: data.amount,
152
- destAddress: toAddress(data.destAddress),
153
- destToken: toAddress(data.destToken),
154
- evmTxHash: asHex(event.transactionHash, true),
155
- srcAddress: toAddress(data.srcAddress)
146
+ start() {
147
+ void poll();
148
+ timer = setInterval(() => void poll(), intervalMs);
149
+ },
150
+ stop() {
151
+ if (timer) {
152
+ clearInterval(timer);
153
+ timer = void 0;
154
+ }
155
+ }
156
156
  };
157
157
  }
158
- __name(verifyEthBridgeEvent, "verifyEthBridgeEvent");
159
158
 
160
- // src/services/queue/workers/EthEventVerification.ts
161
- var name = "Verify ETH Bridge Event at Depth";
162
- var queueName = "eth-event-verify";
163
- var createWorker = /* @__PURE__ */ __name((connection2, telemetry2, services) => {
164
- const svc = assertEx2(services, () => "services not provided");
165
- const { bridge, bridgeFulfillmentMap, provider, remoteConfirmationDepth } = svc;
166
- const worker = new Worker(queueName, async (job) => {
167
- const { bridgeId, identity } = job.data;
168
- const id = BigInt(bridgeId);
169
- const existing = await bridgeFulfillmentMap.get(identity);
170
- if (existing?.canonical) {
171
- await job.log(`[${identity}] canonical already set; verification skipped`);
172
- return;
173
- }
174
- const state = existing ?? {
175
- identity,
176
- previousAttempts: []
159
+ // src/telemetry/createBridgeFlowMetrics.ts
160
+ function createBridgeFlowMetrics(config) {
161
+ const { meter, remoteChainId } = config;
162
+ if (meter === void 0) {
163
+ const noop = () => {
177
164
  };
178
- if (state.failed) state.failed = void 0;
179
- await job.log(`[${identity}] verifying BridgedToRemote(${id}) at depth ${remoteConfirmationDepth}`);
180
- const data = await verifyEthBridgeEvent(id, bridge, provider, remoteConfirmationDepth);
181
- if (isNull(data)) {
182
- state.failed = {
183
- at: Date.now(),
184
- reason: "non-canonical at confirmation depth \u2014 orphaned by reorg or never reached canonical state"
185
- };
186
- await bridgeFulfillmentMap.set(identity, state);
187
- await job.log(`[${identity}] non-canonical at depth \u2014 marked failed`);
188
- throw new UnrecoverableError(`[${identity}] bridgesToRemote slot empty at confirmation depth ${remoteConfirmationDepth}`);
189
- }
190
- state.canonical = data;
191
- await bridgeFulfillmentMap.set(identity, state);
192
- await job.log(`[${identity}] verified: src=${data.srcAddress} dest=${data.destAddress} amount=${data.amount} evmTxHash=${data.evmTxHash}`);
193
- }, {
194
- connection: connection2,
195
- telemetry: telemetry2,
196
- prefix
197
- });
198
- worker.on("failed", (job, err) => {
199
- console.error(`[${name}] Job ${job?.id} failed:`, err.message);
200
- });
201
- worker.on("error", (err) => {
202
- console.error(`[${name}] Worker error:`, err);
203
- });
204
- }, "createWorker");
205
- var EthEventVerification = {
206
- createWorker,
207
- name,
208
- queueName
209
- };
210
-
211
- // src/services/queue/workers/EthToXl1BridgeParent.ts
212
- import { Worker as Worker2 } from "bullmq";
213
- var name2 = "Bridge Ethereum to XL1";
214
- var queueName2 = "eth-to-xl1-bridge";
215
- var createWorker2 = /* @__PURE__ */ __name((connection2, telemetry2) => {
216
- const worker = new Worker2(queueName2, async (job) => {
217
- await job.log(`[${job.name}] start`);
218
- await job.log(`[${job.name}] done`);
219
- return {};
220
- }, {
221
- connection: connection2,
222
- telemetry: telemetry2,
223
- prefix
224
- });
225
- worker.on("failed", (job, err) => {
226
- console.error(`[${name2}] Job ${job?.id} failed:`, err.message);
227
- });
228
- worker.on("error", (err) => {
229
- console.error(`[${name2}] Worker error:`, err);
230
- });
231
- }, "createWorker");
232
- var EthToXl1BridgeParent = {
233
- createWorker: createWorker2,
234
- name: name2,
235
- queueName: queueName2
236
- };
237
-
238
- // src/services/queue/workers/EthTransactionMonitor.ts
239
- import { assertEx as assertEx3 } from "@xylabs/sdk-js";
240
- import { PayloadBuilder as PayloadBuilder3 } from "@xyo-network/sdk-js";
241
- import { Worker as Worker3 } from "bullmq";
242
- var name3 = "Monitor Submitted ETH Transaction";
243
- var queueName3 = "eth-tx-monitor";
244
- var createWorker3 = /* @__PURE__ */ __name((connection2, telemetry2, services) => {
245
- const provider = assertEx3(services?.provider, () => "provider service not provided");
246
- const stateMap = assertEx3(services?.ethTxStateMap, () => "ethTxStateMap service not provided");
247
- const worker = new Worker3(queueName3, async (job) => {
248
- const { tx } = job.data;
249
- const hash = await PayloadBuilder3.hash(tx[0]);
250
- const state = assertEx3(await stateMap.get(hash), () => "State not found");
251
- const submissionHash = assertEx3(state?.submissionHash, () => "submissionHash not found");
252
- const receipt = assertEx3(await provider.getTransactionReceipt(submissionHash), () => "Transaction receipt not found");
253
- await job.log(`[${hash}] confirmed ETH tx ${submissionHash} in block ${receipt.blockNumber}`);
254
- const { blockHash, blockNumber } = receipt;
255
- state.confirmationHash = blockHash;
256
- await stateMap.set(hash, state);
257
165
  return {
258
- blockHash,
259
- blockNumber,
260
- submissionHash
166
+ recordAttemptExpiration: noop,
167
+ recordRetried: noop,
168
+ recordSuccess: noop,
169
+ recordTerminalFailure: noop
261
170
  };
262
- }, {
263
- connection: connection2,
264
- telemetry: telemetry2,
265
- prefix
266
- });
267
- worker.on("failed", (job, err) => {
268
- console.error(`[${name3}] Job ${job?.id} failed:`, err.message);
269
- });
270
- worker.on("error", (err) => {
271
- console.error(`[${name3}] Worker error:`, err);
272
- });
273
- }, "createWorker");
274
- var EthTransactionMonitor = {
275
- createWorker: createWorker3,
276
- name: name3,
277
- queueName: queueName3
278
- };
171
+ }
172
+ const completed = meter.createCounter(
173
+ "bridge_completed_total",
174
+ { description: "Successful bridge settlements, per direction" }
175
+ );
176
+ const settleLatency = meter.createHistogram(
177
+ "bridge_settle_latency_seconds",
178
+ { description: "Wall-clock seconds from acceptance to fulfillment, per direction", unit: "s" }
179
+ );
180
+ const feeRevenue = meter.createCounter(
181
+ "bridge_fee_revenue_total",
182
+ { description: "Cumulative bridge fees collected (AttoXL1), per direction and token", unit: "AttoXL1" }
183
+ );
184
+ const attemptExpirations = meter.createCounter(
185
+ "bridge_attempt_expirations_total",
186
+ { description: "Per-attempt failures that did not exhaust retries \u2014 chain or network friction" }
187
+ );
188
+ const terminalFailures = meter.createCounter(
189
+ "bridge_terminal_failures_total",
190
+ { description: "Terminal failures (retries exhausted or UnrecoverableError), bucketed by reason" }
191
+ );
192
+ const retried = meter.createCounter(
193
+ "bridge_retried_total",
194
+ { description: "Operator-initiated retries (failed \u2192 waiting), per direction and trigger" }
195
+ );
196
+ return {
197
+ recordSuccess({
198
+ direction,
199
+ feeAmount,
200
+ latencySeconds,
201
+ token
202
+ }) {
203
+ completed.add(1, { remoteChainId, direction });
204
+ if (latencySeconds !== void 0) {
205
+ settleLatency.record(latencySeconds, { remoteChainId, direction });
206
+ }
207
+ feeRevenue.add(Number(feeAmount), {
208
+ remoteChainId,
209
+ direction,
210
+ token
211
+ });
212
+ },
213
+ recordAttemptExpiration({ direction }) {
214
+ attemptExpirations.add(1, { remoteChainId, direction });
215
+ },
216
+ recordRetried({
217
+ count,
218
+ direction,
219
+ trigger
220
+ }) {
221
+ const delta = count ?? 1;
222
+ if (delta <= 0) return;
223
+ retried.add(delta, {
224
+ remoteChainId,
225
+ direction,
226
+ trigger
227
+ });
228
+ },
229
+ recordTerminalFailure({ direction, reason }) {
230
+ terminalFailures.add(1, {
231
+ remoteChainId,
232
+ direction,
233
+ reason
234
+ });
235
+ }
236
+ };
237
+ }
279
238
 
280
- // src/services/queue/workers/EthTransactionPreparation.ts
281
- import { assertEx as assertEx14, hexToBigInt as hexToBigInt9 } from "@xylabs/sdk-js";
282
- import { PayloadBuilder as PayloadBuilder7 } from "@xyo-network/sdk-js";
283
- import { isBridgeIntent as isBridgeIntent4 } from "@xyo-network/xl1-sdk";
284
- import { Worker as Worker4 } from "bullmq";
285
- import { getAddress } from "ethers";
239
+ // src/telemetry/createInFlightPoller.ts
240
+ import { spanAsync as spanAsync2 } from "@xylabs/sdk-js";
241
+ var DEFAULT_INTERVAL_MS2 = 6e4;
242
+ function createInFlightPoller(config) {
243
+ const {
244
+ bridgeFulfillmentMap,
245
+ meter,
246
+ remoteChainId,
247
+ intervalMs = DEFAULT_INTERVAL_MS2
248
+ } = config;
249
+ let timer;
250
+ const inFlightGauge = meter.createGauge(
251
+ "bridge_in_flight",
252
+ { description: "Bridges currently in-flight (canonical observed, fulfillment pending), per direction" }
253
+ );
254
+ const poll = async () => {
255
+ await spanAsync2("bridge:inflight:poll", async () => {
256
+ try {
257
+ let count = 0;
258
+ for await (const [, state] of bridgeFulfillmentMap) {
259
+ if (state.canonical !== void 0 && state.fulfilled === void 0) count++;
260
+ }
261
+ inFlightGauge.record(count, { remoteChainId, direction: "inbound" });
262
+ } catch (err) {
263
+ console.error("[InFlightPoller] Failed to poll bridgeFulfillmentMap:", err);
264
+ }
265
+ }, { timeBudgetLimit: 1e3 });
266
+ };
267
+ return {
268
+ poll,
269
+ start() {
270
+ void poll();
271
+ timer = setInterval(() => void poll(), intervalMs);
272
+ },
273
+ stop() {
274
+ if (timer) {
275
+ clearInterval(timer);
276
+ timer = void 0;
277
+ }
278
+ }
279
+ };
280
+ }
286
281
 
287
- // src/services/validation/validateBridgeEstimateExact.ts
288
- import { hexToBigInt as hexToBigInt5, isUndefined } from "@xylabs/sdk-js";
289
- import { PayloadBuilder as PayloadBuilder5 } from "@xyo-network/sdk-js";
282
+ // src/telemetry/createQueueMetrics.ts
283
+ import { spanAsync as spanAsync3 } from "@xylabs/sdk-js";
284
+ var DEFAULT_INTERVAL_MS3 = 3e4;
285
+ function createQueueMetrics(config) {
286
+ const {
287
+ meter,
288
+ queues,
289
+ remoteChainId,
290
+ intervalMs = DEFAULT_INTERVAL_MS3
291
+ } = config;
292
+ let timer;
293
+ const waitingGauge = meter.createGauge(
294
+ "bridge_queue_waiting",
295
+ { description: "Number of waiting jobs in the bridge queue" }
296
+ );
297
+ const activeGauge = meter.createGauge(
298
+ "bridge_queue_active",
299
+ { description: "Number of active jobs in the bridge queue" }
300
+ );
301
+ const completedGauge = meter.createGauge(
302
+ "bridge_queue_completed",
303
+ { description: "Number of completed jobs in the bridge queue" }
304
+ );
305
+ const failedGauge = meter.createGauge(
306
+ "bridge_queue_failed",
307
+ { description: "Number of failed jobs in the bridge queue" }
308
+ );
309
+ const delayedGauge = meter.createGauge(
310
+ "bridge_queue_delayed",
311
+ { description: "Number of delayed jobs in the bridge queue" }
312
+ );
313
+ async function poll() {
314
+ await spanAsync3("bridge:queue-metrics:poll", async () => {
315
+ for (const [name13, queue] of Object.entries(queues)) {
316
+ try {
317
+ const counts = await queue.getJobCounts("waiting", "active", "completed", "failed", "delayed");
318
+ const attrs = { queue_name: name13, remoteChainId };
319
+ waitingGauge.record(counts.waiting ?? 0, attrs);
320
+ activeGauge.record(counts.active ?? 0, attrs);
321
+ completedGauge.record(counts.completed ?? 0, attrs);
322
+ failedGauge.record(counts.failed ?? 0, attrs);
323
+ delayedGauge.record(counts.delayed ?? 0, attrs);
324
+ } catch (err) {
325
+ console.error(`[QueueMetrics] Failed to read job counts for queue ${name13}:`, err);
326
+ }
327
+ }
328
+ }, { timeBudgetLimit: 1e3 });
329
+ }
330
+ return {
331
+ start() {
332
+ void poll();
333
+ timer = setInterval(() => void poll(), intervalMs);
334
+ },
335
+ stop() {
336
+ if (timer) {
337
+ clearInterval(timer);
338
+ timer = void 0;
339
+ }
340
+ }
341
+ };
342
+ }
290
343
 
291
344
  // src/services/evm/asChainId.ts
292
- import { asHex as asHex2 } from "@xylabs/sdk-js";
293
- var asChainId = /* @__PURE__ */ __name((value) => {
294
- const chainId = asHex2(value);
345
+ import { asHex } from "@xylabs/sdk-js";
346
+ var asChainId = (value) => {
347
+ const chainId = asHex(value);
295
348
  return chainId;
296
- }, "asChainId");
349
+ };
297
350
 
298
351
  // src/services/evm/asToken.ts
299
352
  import { asAddress } from "@xylabs/sdk-js";
300
- var asToken = /* @__PURE__ */ __name((value) => {
353
+ var asToken = (value) => {
301
354
  const token = asAddress(value);
302
355
  return token;
303
- }, "asToken");
356
+ };
304
357
 
305
358
  // src/services/evm/getBridgeEscrowAddress.ts
306
- import { asAddress as asAddress2, assertEx as assertEx4 } from "@xylabs/sdk-js";
307
- var tryGetBridgeEscrowAddress = /* @__PURE__ */ __name((config) => {
359
+ import { asAddress as asAddress2, assertEx } from "@xylabs/sdk-js";
360
+ var tryGetBridgeEscrowAddress = (config) => {
308
361
  const address = asAddress2(config.escrowAddress);
309
362
  return address;
310
- }, "tryGetBridgeEscrowAddress");
363
+ };
311
364
 
312
365
  // src/services/evm/getBridgeFeesAddress.ts
313
- import { asAddress as asAddress3, assertEx as assertEx5 } from "@xylabs/sdk-js";
314
- var tryGetBridgeFeesAddress = /* @__PURE__ */ __name((config) => {
366
+ import { asAddress as asAddress3, assertEx as assertEx2 } from "@xylabs/sdk-js";
367
+ var tryGetBridgeFeesAddress = (config) => {
315
368
  const address = asAddress3(config.feesAddress);
316
369
  return address;
317
- }, "tryGetBridgeFeesAddress");
370
+ };
318
371
 
319
372
  // src/services/evm/getFeeStructure.ts
320
- var getFeeStructure = /* @__PURE__ */ __name((config) => {
373
+ var getFeeStructure = (config) => {
321
374
  const { feeFixed, feeRateBasisPoints } = config;
322
- return {
323
- feeFixed,
324
- feeRateBasisPoints
325
- };
326
- }, "getFeeStructure");
375
+ return { feeFixed, feeRateBasisPoints };
376
+ };
327
377
 
328
378
  // src/services/evm/getMaxBridgeAmount.ts
329
- var getMaxBridgeAmount = /* @__PURE__ */ __name((config) => {
379
+ var getMaxBridgeAmount = (config) => {
330
380
  const { maxBridgeAmount } = config;
331
381
  return maxBridgeAmount;
332
- }, "getMaxBridgeAmount");
382
+ };
333
383
 
334
384
  // src/services/evm/getMinBridgeAmount.ts
335
- var getMinBridgeAmount = /* @__PURE__ */ __name((config) => {
385
+ var getMinBridgeAmount = (config) => {
336
386
  const { minBridgeAmount } = config;
337
387
  return minBridgeAmount;
338
- }, "getMinBridgeAmount");
388
+ };
339
389
 
340
390
  // src/services/evm/getRemoteChainId.ts
341
- import { assertEx as assertEx6 } from "@xylabs/sdk-js";
342
- var getRemoteChainId = /* @__PURE__ */ __name((config) => {
343
- const remoteChainId = assertEx6(asChainId(config.remoteChainId), () => "Invalid remote chain ID in config");
391
+ import { assertEx as assertEx3 } from "@xylabs/sdk-js";
392
+ var getRemoteChainId = (config) => {
393
+ const remoteChainId = assertEx3(asChainId(config.remoteChainId), () => "Invalid remote chain ID in config");
344
394
  return remoteChainId;
345
- }, "getRemoteChainId");
395
+ };
346
396
 
347
397
  // src/services/evm/getRemoteTokenAddress.ts
348
- import { assertEx as assertEx7 } from "@xylabs/sdk-js";
349
- var getRemoteTokenAddress = /* @__PURE__ */ __name((config) => {
398
+ import { assertEx as assertEx4 } from "@xylabs/sdk-js";
399
+ var getRemoteTokenAddress = (config) => {
350
400
  const token = asToken(config.remoteTokenAddress);
351
- return assertEx7(token, () => "Remote token address is not defined in bridge configuration");
352
- }, "getRemoteTokenAddress");
401
+ return assertEx4(token, () => "Remote token address is not defined in bridge configuration");
402
+ };
353
403
 
354
404
  // src/services/evm/getBridgeWalletAccount.ts
355
405
  import { isDefined as isDefined3 } from "@xylabs/sdk-js";
356
406
  import { resolveWalletForActor } from "@xyo-network/chain-orchestration";
357
407
  var accountServiceSingleton;
358
- var getBridgeWalletAccount = /* @__PURE__ */ __name(async (config) => {
408
+ var getBridgeWalletAccount = async (config) => {
359
409
  if (accountServiceSingleton) return accountServiceSingleton;
360
410
  const accountPath = typeof config.accountPath === "string" ? config.accountPath : void 0;
361
411
  const account = await resolveWalletForActor(config.name, accountPath);
362
412
  accountServiceSingleton = account;
363
413
  return accountServiceSingleton;
364
- }, "getBridgeWalletAccount");
414
+ };
365
415
 
366
416
  // src/services/evm/getTransferAddresses.ts
367
- var getTransferAddresses = /* @__PURE__ */ __name(async (config) => {
417
+ var getTransferAddresses = async (config) => {
368
418
  const escrowAddress = tryGetBridgeEscrowAddress(config) ?? (await getBridgeWalletAccount(config)).address;
369
419
  const feesAddress = tryGetBridgeFeesAddress(config) ?? (await getBridgeWalletAccount(config)).address;
370
- return {
371
- escrowAddress,
372
- feesAddress
373
- };
374
- }, "getTransferAddresses");
420
+ return { escrowAddress, feesAddress };
421
+ };
375
422
 
376
423
  // src/services/evm/getXl1ChainId.ts
377
- import { assertEx as assertEx8, isDefined as isDefined4 } from "@xylabs/sdk-js";
378
- var getXl1ChainId = /* @__PURE__ */ __name((config) => {
424
+ import { assertEx as assertEx5, isDefined as isDefined4 } from "@xylabs/sdk-js";
425
+ var getXl1ChainId = (config) => {
379
426
  const xl1ChainId = config.xl1ChainId;
380
427
  if (isDefined4(xl1ChainId)) {
381
- return assertEx8(asChainId(xl1ChainId), () => "Invalid xl1ChainId in bridge config");
428
+ return assertEx5(asChainId(xl1ChainId), () => "Invalid xl1ChainId in bridge config");
382
429
  }
383
- return assertEx8(asChainId(config.chain.id), () => "Invalid chain.id in config");
384
- }, "getXl1ChainId");
430
+ return assertEx5(asChainId(config.chain.id), () => "Invalid chain.id in config");
431
+ };
385
432
 
386
433
  // src/services/evm/getXl1TokenAddress.ts
387
434
  import { isDefined as isDefined5 } from "@xylabs/sdk-js";
388
- var getXl1TokenAddress = /* @__PURE__ */ __name((config) => {
435
+ var getXl1TokenAddress = (config) => {
389
436
  const token = asToken(config.xl1TokenAddress);
390
437
  if (isDefined5(token)) return token;
391
438
  return getXl1ChainId(config);
392
- }, "getXl1TokenAddress");
439
+ };
393
440
 
394
441
  // src/services/evm/getBridgeSettings.ts
395
- var getBridgeSettings = /* @__PURE__ */ __name(async (config) => {
442
+ var getBridgeSettings = async (config) => {
396
443
  const { feeFixed, feeRateBasisPoints } = getFeeStructure(config);
397
444
  const { feesAddress, escrowAddress } = await getTransferAddresses(config);
398
445
  const maxBridgeAmount = getMaxBridgeAmount(config);
@@ -413,111 +460,479 @@ var getBridgeSettings = /* @__PURE__ */ __name(async (config) => {
413
460
  xl1TokenAddress,
414
461
  xl1ChainId
415
462
  };
416
- }, "getBridgeSettings");
463
+ };
417
464
 
418
465
  // src/services/evm/getRemoteConfirmationDepth.ts
419
- import { isDefined as isDefined6 } from "@xylabs/sdk-js";
420
- var HARDHAT_CHAIN_ID = "0x7a69";
421
- var ETHEREUM_MAINNET_CHAIN_ID = "0x1";
466
+ import { isDefined as isDefined6, toHex } from "@xylabs/sdk-js";
467
+ var HARDHAT_CHAIN_ID = toHex("0x7a69");
468
+ var ETHEREUM_MAINNET_CHAIN_ID = toHex("0x1");
422
469
  var FALLBACK_CONFIRMATION_DEPTH = 32;
423
- var DEFAULT_CONFIRMATION_DEPTH_BY_CHAIN_ID = {
424
- [HARDHAT_CHAIN_ID]: 0,
425
- [ETHEREUM_MAINNET_CHAIN_ID]: 32
426
- };
470
+ var DEFAULT_CONFIRMATION_DEPTH_BY_CHAIN_ID = /* @__PURE__ */ new Map([
471
+ [HARDHAT_CHAIN_ID, 0],
472
+ [ETHEREUM_MAINNET_CHAIN_ID, 32]
473
+ ]);
427
474
  function getRemoteConfirmationDepth(config) {
428
475
  if (isDefined6(config.remoteConfirmationDepth)) return config.remoteConfirmationDepth;
429
- const chainId = getRemoteChainId(config).toLowerCase();
430
- return DEFAULT_CONFIRMATION_DEPTH_BY_CHAIN_ID[chainId] ?? FALLBACK_CONFIRMATION_DEPTH;
476
+ const chainId = toHex(getRemoteChainId(config));
477
+ return DEFAULT_CONFIRMATION_DEPTH_BY_CHAIN_ID.get(chainId) ?? FALLBACK_CONFIRMATION_DEPTH;
431
478
  }
432
- __name(getRemoteConfirmationDepth, "getRemoteConfirmationDepth");
433
479
 
434
480
  // src/services/evm/getScannerIntervalMs.ts
435
481
  function getScannerIntervalMs(config) {
436
482
  return config.scannerIntervalMs;
437
483
  }
438
- __name(getScannerIntervalMs, "getScannerIntervalMs");
439
-
440
- // src/services/util/calculateBridgeFees.ts
441
- import { hexToBigInt as hexToBigInt2, toHex as toHex2 } from "@xylabs/sdk-js";
442
- var calculateBridgeFees = /* @__PURE__ */ __name((srcAmount, feeStructure) => {
443
- const { feeFixed, feeRateBasisPoints } = feeStructure;
444
- const srcAmountBigInt = hexToBigInt2(srcAmount);
445
- const feeVariableBigInt = srcAmountBigInt * BigInt(feeRateBasisPoints) / 10000n;
446
- const feeVariable = toHex2(feeVariableBigInt);
447
- return {
484
+
485
+ // src/services/evm/resolveDeployBlock.ts
486
+ import { getAddress } from "ethers";
487
+ async function contractExistsAt(provider, address, blockNumber) {
488
+ const code = await provider.getCode(getAddress(address), blockNumber);
489
+ return code !== "0x" && code.length > 2;
490
+ }
491
+ async function resolveDeployBlockByBinarySearch(provider, address) {
492
+ const head = await provider.getBlockNumber();
493
+ if (!await contractExistsAt(provider, address, head)) {
494
+ throw new Error(`resolveDeployBlockByBinarySearch: no contract code at ${address} at head=${head}`);
495
+ }
496
+ let low = 0;
497
+ let high = head;
498
+ while (low < high) {
499
+ const mid = Math.floor((low + high) / 2);
500
+ if (await contractExistsAt(provider, address, mid)) {
501
+ high = mid;
502
+ } else {
503
+ low = mid + 1;
504
+ }
505
+ }
506
+ return low;
507
+ }
508
+ async function resolveDeployBlock(opts) {
509
+ const {
510
+ configuredDeployBlock,
511
+ contractAddress,
512
+ provider
513
+ } = opts;
514
+ if (configuredDeployBlock !== void 0 && configuredDeployBlock >= 0) return configuredDeployBlock;
515
+ return resolveDeployBlockByBinarySearch(provider, contractAddress);
516
+ }
517
+
518
+ // src/services/queue/workers/util/buildAcceptedSnapshot.ts
519
+ import { hexToBigInt, toHex as toHex2 } from "@xylabs/sdk-js";
520
+ import { buildEthToXl1BridgePayloads, calculateBridgeFees } from "@xyo-network/chain-bridge-shared";
521
+ import { PayloadBuilder } from "@xyo-network/sdk-js";
522
+ import {
523
+ BridgeDestinationObservationFieldsZod,
524
+ BridgeDestinationObservationSchema,
525
+ BridgeSourceObservationFieldsZod,
526
+ BridgeSourceObservationSchema
527
+ } from "@xyo-network/xl1-sdk";
528
+ function buildAcceptedSnapshot(options2) {
529
+ const {
530
+ amount,
531
+ bridgeAccountAddress,
532
+ bridgeId,
533
+ destAddress,
534
+ evmChainId,
535
+ evmContractAddress,
536
+ evmSrcAddress,
537
+ evmTokenAddress,
538
+ evmTxHash,
448
539
  feeFixed,
449
- feeVariable,
450
- srcAmount
451
- };
452
- }, "calculateBridgeFees");
453
-
454
- // src/services/util/calculateMaxBridgeAmount.ts
455
- import { hexToBigInt as hexToBigInt3, toHex as toHex3 } from "@xylabs/sdk-js";
456
- var calculateMaxBridgeAmount = /* @__PURE__ */ __name((balance, feeStructure) => {
457
- const { feeFixed, feeRateBasisPoints } = feeStructure;
458
- const balanceBigInt = hexToBigInt3(balance);
459
- const feeFixedBigInt = hexToBigInt3(feeFixed);
460
- if (balanceBigInt <= feeFixedBigInt) return toHex3(0n);
461
- const maxAmount = (balanceBigInt - feeFixedBigInt) * 10000n / (10000n + BigInt(feeRateBasisPoints));
462
- return toHex3(maxAmount);
463
- }, "calculateMaxBridgeAmount");
464
-
465
- // src/services/util/createBridgeTransfer.ts
466
- import { hexToBigInt as hexToBigInt4 } from "@xylabs/sdk-js";
467
- import { createTransferPayload as createTransferPayload2 } from "@xyo-network/xl1-sdk";
468
- var createBridgeTransfer = /* @__PURE__ */ __name((sender, srcAmount, escrowAddress, feesAddress, context) => {
469
- const { feeFixed, feeVariable } = context;
470
- const escrowAmount = hexToBigInt4(srcAmount);
471
- const feesAmount = hexToBigInt4(feeFixed) + hexToBigInt4(feeVariable);
472
- const transfers = escrowAddress === feesAddress ? {
473
- [feesAddress]: escrowAmount + feesAmount
474
- } : {
475
- [escrowAddress]: escrowAmount,
476
- [feesAddress]: feesAmount
540
+ feeRateBasisPoints,
541
+ feesAddress,
542
+ xl1ChainId,
543
+ xl1TokenAddress
544
+ } = options2;
545
+ const acceptedFees = calculateBridgeFees(toHex2(amount), { feeFixed, feeRateBasisPoints });
546
+ const feesAmount = hexToBigInt(acceptedFees.feeFixed) + hexToBigInt(acceptedFees.feeVariable);
547
+ const { intent: acceptedIntent } = buildEthToXl1BridgePayloads({
548
+ amount,
549
+ bridgeAccountAddress,
550
+ bridgeId,
551
+ destAddress,
552
+ evmChainId,
553
+ evmContractAddress,
554
+ evmSrcAddress,
555
+ evmTokenAddress,
556
+ feesAddress,
557
+ feesAmount,
558
+ xl1ChainId,
559
+ xl1TokenAddress
560
+ });
561
+ const sourceFields = BridgeSourceObservationFieldsZod.parse({
562
+ ...acceptedIntent,
563
+ srcConfirmation: evmTxHash
564
+ });
565
+ const acceptedSourceObservation = new PayloadBuilder({ schema: BridgeSourceObservationSchema }).fields(sourceFields).build();
566
+ return {
567
+ acceptedFees,
568
+ acceptedIntent,
569
+ acceptedSourceObservation
477
570
  };
478
- const transfer = createTransferPayload2(sender, transfers, context);
479
- return transfer;
480
- }, "createBridgeTransfer");
571
+ }
572
+ function buildAcceptedDestinationObservation(intent, destConfirmation) {
573
+ const fields = BridgeDestinationObservationFieldsZod.parse({
574
+ ...intent,
575
+ destConfirmation
576
+ });
577
+ return new PayloadBuilder({ schema: BridgeDestinationObservationSchema }).fields(fields).build();
578
+ }
481
579
 
482
- // src/services/util/generateBridgeEstimate.ts
483
- import { toAddress as toAddress2 } from "@xylabs/sdk-js";
484
- import { PayloadBuilder as PayloadBuilder4 } from "@xyo-network/sdk-js";
485
- import { BridgeIntentSchema as BridgeIntentSchema2 } from "@xyo-network/xl1-sdk";
486
- import { v4 } from "uuid";
487
- var generateBridgeEstimate = /* @__PURE__ */ __name(async (srcAddress, srcAmount, destAddress, config, nonceOverride) => {
488
- const { escrowAddress, feeFixed, feeRateBasisPoints, feesAddress, remoteChainId, remoteTokenAddress, xl1ChainId, xl1TokenAddress } = await getBridgeSettings(config);
489
- const sender = toAddress2(srcAddress);
490
- const fees = calculateBridgeFees(srcAmount, {
491
- feeFixed,
492
- feeRateBasisPoints
580
+ // src/services/queue/workers/util/buildEthToXl1ReserveTx.ts
581
+ import { toHex as toHex3 } from "@xylabs/sdk-js";
582
+ import { buildEthToXl1BridgePayloads as buildEthToXl1BridgePayloads2 } from "@xyo-network/chain-bridge-shared";
583
+ import { PayloadBuilder as PayloadBuilder2 } from "@xyo-network/sdk-js";
584
+ import { BridgeSourceObservationSchema as BridgeSourceObservationSchema2, buildTransaction } from "@xyo-network/xl1-sdk";
585
+ async function buildEthToXl1ReserveTx(options2) {
586
+ const {
587
+ amount,
588
+ bridgeAccount,
589
+ bridgeId,
590
+ destAddress,
591
+ evmChainId,
592
+ evmContractAddress,
593
+ evmSrcAddress,
594
+ evmTokenAddress,
595
+ evmTxHash,
596
+ exp,
597
+ feesAddress,
598
+ feesAmount,
599
+ nbf,
600
+ xl1ChainId,
601
+ xl1TokenAddress
602
+ } = options2;
603
+ const { intent, transfer } = buildEthToXl1BridgePayloads2({
604
+ amount,
605
+ bridgeAccountAddress: bridgeAccount.address,
606
+ bridgeId,
607
+ destAddress,
608
+ evmChainId,
609
+ evmContractAddress,
610
+ evmSrcAddress,
611
+ evmTokenAddress,
612
+ feesAddress,
613
+ feesAmount,
614
+ xl1ChainId,
615
+ xl1TokenAddress
493
616
  });
494
- const nonce = nonceOverride ?? v4();
495
- const bridgeIntentFields = {
496
- // Source
497
- src: xl1ChainId,
498
- srcAddress: sender,
499
- srcAmount,
500
- srcToken: xl1TokenAddress,
501
- // Destination
502
- dest: remoteChainId,
617
+ const destAmountHex = toHex3(amount - feesAmount);
618
+ const srcAmountHex = toHex3(amount);
619
+ const sourceObservation = new PayloadBuilder2({ schema: BridgeSourceObservationSchema2 }).fields({
620
+ dest: xl1ChainId,
503
621
  destAddress,
504
- destAmount: srcAmount,
505
- destToken: remoteTokenAddress,
506
- nonce
622
+ destAmount: destAmountHex,
623
+ destToken: xl1TokenAddress,
624
+ src: evmChainId,
625
+ srcAddress: evmSrcAddress,
626
+ srcAmount: srcAmountHex,
627
+ srcConfirmation: evmTxHash,
628
+ srcToken: evmTokenAddress
629
+ }).build();
630
+ return buildTransaction(
631
+ xl1ChainId,
632
+ [transfer],
633
+ [intent, sourceObservation],
634
+ bridgeAccount,
635
+ nbf,
636
+ exp
637
+ );
638
+ }
639
+
640
+ // src/services/queue/workers/util/resolveEvmBlockTagAtDepth.ts
641
+ async function resolveEvmBlockTagAtDepth(provider, depth, deployBlock) {
642
+ if (depth === "finalized") return "finalized";
643
+ if (depth === 0) return "latest";
644
+ const head = await provider.getBlockNumber();
645
+ return Math.max(head - depth, deployBlock);
646
+ }
647
+
648
+ // src/services/queue/workers/util/submitEthTransaction.ts
649
+ import {
650
+ assertEx as assertEx6,
651
+ hexToBigInt as hexToBigInt2,
652
+ toEthAddress
653
+ } from "@xylabs/sdk-js";
654
+ import { PayloadBuilder as PayloadBuilder3 } from "@xyo-network/sdk-js";
655
+ import { isBridgeIntent } from "@xyo-network/xl1-sdk";
656
+ var submitEthTransaction = async (tx, offChainPayloads, bridge, wallet) => {
657
+ const xl1Transaction = assertEx6(tx[0], () => "No corresponding XL1 transaction found");
658
+ const allPayloads = [...tx[1], ...offChainPayloads];
659
+ const bridgeIntent = assertEx6(allPayloads.find(isBridgeIntent), () => "No bridge intent found");
660
+ const srcAddress = toEthAddress(bridgeIntent.srcAddress);
661
+ const destAddress = toEthAddress(bridgeIntent.destAddress);
662
+ const amount = hexToBigInt2(bridgeIntent.destAmount);
663
+ const nonce = hexToBigInt2(await PayloadBuilder3.hash(xl1Transaction));
664
+ const bridgeTx = await bridge.connect(wallet).bridgeFromRemote(srcAddress, destAddress, amount, nonce);
665
+ const receipt = await bridgeTx.wait(1);
666
+ return receipt?.hash;
667
+ };
668
+
669
+ // src/services/queue/workers/util/submitXl1Transaction.ts
670
+ var submitXl1Transaction = async (preparedTx, offChain = [], gateway) => {
671
+ const result = await gateway.addTransactionToChain(preparedTx, offChain);
672
+ return result;
673
+ };
674
+
675
+ // src/services/queue/workers/util/verifyEthBridgeEvent.ts
676
+ import { asHex as asHex2, toAddress } from "@xylabs/sdk-js";
677
+ import { ZeroAddress } from "ethers";
678
+ async function verifyEthBridgeEvent(id, bridge, provider, confirmationDepth, deployBlock) {
679
+ const blockTag = await resolveEvmBlockTagAtDepth(provider, confirmationDepth, deployBlock);
680
+ const data = await bridge.bridgesToRemote(id, { blockTag });
681
+ if (data.srcAddress === ZeroAddress) {
682
+ return null;
683
+ }
684
+ const filter = bridge.filters.BridgedToRemote(id);
685
+ const events = await bridge.queryFilter(filter, deployBlock, blockTag);
686
+ const event = events[0];
687
+ if (event === void 0) {
688
+ return null;
689
+ }
690
+ return {
691
+ amount: data.amount,
692
+ destAddress: toAddress(data.destAddress),
693
+ destToken: toAddress(data.destToken),
694
+ evmTxHash: asHex2(event.transactionHash, true),
695
+ observedAt: Date.now(),
696
+ srcAddress: toAddress(data.srcAddress)
507
697
  };
508
- const bridgeIntent = new PayloadBuilder4({
509
- schema: BridgeIntentSchema2
510
- }).fields(bridgeIntentFields).build();
511
- const transfer = createBridgeTransfer(sender, srcAmount, escrowAddress, feesAddress, fees);
512
- return [
513
- bridgeIntent,
514
- transfer
515
- ];
516
- }, "generateBridgeEstimate");
698
+ }
699
+
700
+ // src/services/queue/workers/EthEventVerification.ts
701
+ var name = "Verify ETH Bridge Event at Depth";
702
+ var queueName = "eth-event-verify";
703
+ var createWorker = (connection2, telemetry2, services) => {
704
+ const svc = assertEx7(services, () => "services not provided");
705
+ const {
706
+ account,
707
+ bridge,
708
+ bridgeFlowMetrics,
709
+ bridgeFulfillmentMap,
710
+ config,
711
+ evmBridgeDeployBlock,
712
+ logger,
713
+ provider,
714
+ remoteConfirmationDepth
715
+ } = svc;
716
+ const worker = new Worker(
717
+ queueName,
718
+ async (job) => {
719
+ await spanAsync4("bridge:worker:eth-event-verify", async () => {
720
+ const { bridgeId, identity } = job.data;
721
+ const id = BigInt(bridgeId);
722
+ const existing = await bridgeFulfillmentMap.get(identity);
723
+ if (existing?.canonical) {
724
+ await job.log(`[${identity}] canonical already set; verification skipped`);
725
+ return;
726
+ }
727
+ const state = existing ?? { identity, previousAttempts: [] };
728
+ await job.log(`[${identity}] verifying BridgedToRemote(${id}) at depth ${remoteConfirmationDepth}`);
729
+ const data = await verifyEthBridgeEvent(id, bridge, provider, remoteConfirmationDepth, evmBridgeDeployBlock);
730
+ if (isNull(data)) {
731
+ await job.log(`[${identity}] non-canonical at confirmation depth \u2014 orphaned by reorg or never reached canonical state`);
732
+ throw new UnrecoverableError(`[${identity}] bridgesToRemote slot empty at confirmation depth ${remoteConfirmationDepth}`);
733
+ }
734
+ state.canonical = data;
735
+ const { feeFixed, feeRateBasisPoints } = getFeeStructure(config);
736
+ const { feesAddress } = await getTransferAddresses(config);
737
+ const snapshot = buildAcceptedSnapshot({
738
+ amount: data.amount,
739
+ bridgeAccountAddress: account.address,
740
+ bridgeId: id,
741
+ destAddress: data.destAddress,
742
+ evmChainId: config.remoteChainId,
743
+ evmContractAddress: config.remoteBridgeContractAddress,
744
+ evmSrcAddress: data.srcAddress,
745
+ evmTokenAddress: data.destToken,
746
+ evmTxHash: data.evmTxHash,
747
+ feeFixed,
748
+ feeRateBasisPoints,
749
+ feesAddress,
750
+ xl1ChainId: getXl1ChainId(config),
751
+ xl1TokenAddress: getXl1TokenAddress(config)
752
+ });
753
+ state.acceptedIntent = snapshot.acceptedIntent;
754
+ state.acceptedFees = snapshot.acceptedFees;
755
+ state.acceptedSourceObservation = snapshot.acceptedSourceObservation;
756
+ await bridgeFulfillmentMap.set(identity, state);
757
+ await job.log(
758
+ `[${identity}] verified: src=${data.srcAddress} dest=${data.destAddress} amount=${data.amount} evmTxHash=${data.evmTxHash} snapshot: feeFixed=${snapshot.acceptedFees.feeFixed} feeVariable=${snapshot.acceptedFees.feeVariable}`
759
+ );
760
+ }, { logger, timeBudgetLimit: 5e3 });
761
+ },
762
+ {
763
+ connection: connection2,
764
+ telemetry: telemetry2,
765
+ prefix
766
+ }
767
+ );
768
+ worker.on("failed", (job, err) => {
769
+ logger.error(`[eth-verify] job ${job?.id} failed: ${err.message}`);
770
+ if (job === void 0) return;
771
+ const attemptsAllowed = job.opts.attempts ?? 1;
772
+ if (job.attemptsMade >= attemptsAllowed) {
773
+ bridgeFlowMetrics.recordTerminalFailure({ direction: "inbound", reason: bucketFailureReason(err.message) });
774
+ }
775
+ });
776
+ worker.on("error", (err) => {
777
+ logger.error(`[eth-verify] worker error: ${err.message}`);
778
+ });
779
+ };
780
+ var EthEventVerification = {
781
+ createWorker,
782
+ name,
783
+ queueName
784
+ };
785
+
786
+ // src/services/queue/workers/EthToXl1BridgeParent.ts
787
+ import { assertEx as assertEx8, spanAsync as spanAsync5 } from "@xylabs/sdk-js";
788
+ import { Worker as Worker2 } from "bullmq";
789
+ var name2 = "Bridge Ethereum to XL1";
790
+ var queueName2 = "eth-to-xl1-bridge";
791
+ var createWorker2 = (connection2, telemetry2, services) => {
792
+ const logger = assertEx8(services?.logger, () => "logger service not provided");
793
+ const worker = new Worker2(
794
+ queueName2,
795
+ async (job) => {
796
+ return await spanAsync5("bridge:worker:eth-to-xl1-bridge", async () => {
797
+ await job.log(`[${job.name}] start`);
798
+ await job.log(`[${job.name}] done`);
799
+ return {};
800
+ }, { logger, timeBudgetLimit: 5e3 });
801
+ },
802
+ {
803
+ connection: connection2,
804
+ telemetry: telemetry2,
805
+ prefix
806
+ }
807
+ );
808
+ worker.on("failed", (job, err) => {
809
+ logger.error(`[eth-to-xl1-parent] job ${job?.id} failed: ${err.message}`);
810
+ });
811
+ worker.on("error", (err) => {
812
+ logger.error(`[eth-to-xl1-parent] worker error: ${err.message}`);
813
+ });
814
+ };
815
+ var EthToXl1BridgeParent = {
816
+ createWorker: createWorker2,
817
+ name: name2,
818
+ queueName: queueName2
819
+ };
820
+
821
+ // src/services/queue/workers/EthTransactionMonitor.ts
822
+ import {
823
+ assertEx as assertEx9,
824
+ hexToBigInt as hexToBigInt3,
825
+ spanAsync as spanAsync6
826
+ } from "@xylabs/sdk-js";
827
+ import { calculateBridgeFees as calculateBridgeFees2 } from "@xyo-network/chain-bridge-shared";
828
+ import { PayloadBuilder as PayloadBuilder4 } from "@xyo-network/sdk-js";
829
+ import { isBridgeIntent as isBridgeIntent2 } from "@xyo-network/xl1-sdk";
830
+ import { Worker as Worker3 } from "bullmq";
831
+ var name3 = "Monitor Submitted ETH Transaction";
832
+ var queueName3 = "eth-tx-monitor";
833
+ var createWorker3 = (connection2, telemetry2, services) => {
834
+ const provider = assertEx9(services?.provider, () => "provider service not provided");
835
+ const stateMap = assertEx9(services?.ethTxStateMap, () => "ethTxStateMap service not provided");
836
+ const logger = assertEx9(services?.logger, () => "logger service not provided");
837
+ const config = assertEx9(services?.config, () => "config service not provided");
838
+ const bridgeFlowMetrics = assertEx9(services?.bridgeFlowMetrics, () => "bridgeFlowMetrics service not provided");
839
+ const worker = new Worker3(
840
+ queueName3,
841
+ async (job) => {
842
+ return await spanAsync6("bridge:worker:eth-tx-monitor", async () => {
843
+ const { tx } = job.data;
844
+ const hash = await PayloadBuilder4.hash(tx[0]);
845
+ const state = assertEx9(await stateMap.get(hash), () => "State not found");
846
+ const submissionHash = assertEx9(state?.submissionHash, () => "submissionHash not found");
847
+ const receipt = assertEx9(await provider.getTransactionReceipt(submissionHash), () => "Transaction receipt not found");
848
+ await job.log(`[${hash}] confirmed ETH tx ${submissionHash} in block ${receipt.blockNumber}`);
849
+ const { blockHash, blockNumber } = receipt;
850
+ state.confirmationHash = blockHash;
851
+ await stateMap.set(hash, state);
852
+ const bridgeIntent = tx[1].find(isBridgeIntent2);
853
+ const feeAmount = (() => {
854
+ if (bridgeIntent === void 0) return 0n;
855
+ const fees = calculateBridgeFees2(bridgeIntent.srcAmount, getFeeStructure(config));
856
+ return hexToBigInt3(fees.feeFixed) + hexToBigInt3(fees.feeVariable);
857
+ })();
858
+ const latencySeconds = (Date.now() - job.timestamp) / 1e3;
859
+ bridgeFlowMetrics.recordSuccess({
860
+ direction: "outbound",
861
+ feeAmount,
862
+ latencySeconds,
863
+ token: getXl1TokenAddress(config)
864
+ });
865
+ return {
866
+ blockHash,
867
+ blockNumber,
868
+ submissionHash
869
+ };
870
+ }, { logger, timeBudgetLimit: 2e3 });
871
+ },
872
+ {
873
+ connection: connection2,
874
+ telemetry: telemetry2,
875
+ prefix
876
+ }
877
+ );
878
+ worker.on("failed", (job, err) => {
879
+ logger.error(`[eth-monitor] job ${job?.id} failed: ${err.message}`);
880
+ if (job === void 0) return;
881
+ const attemptsAllowed = job.opts.attempts ?? 1;
882
+ if (job.attemptsMade < attemptsAllowed) {
883
+ bridgeFlowMetrics.recordAttemptExpiration({ direction: "outbound" });
884
+ } else {
885
+ bridgeFlowMetrics.recordTerminalFailure({ direction: "outbound", reason: bucketFailureReason(err.message) });
886
+ }
887
+ });
888
+ worker.on("error", (err) => {
889
+ logger.error(`[eth-monitor] worker error: ${err.message}`);
890
+ });
891
+ };
892
+ var EthTransactionMonitor = {
893
+ createWorker: createWorker3,
894
+ name: name3,
895
+ queueName: queueName3
896
+ };
897
+
898
+ // src/services/queue/workers/EthTransactionPreparation.ts
899
+ import {
900
+ assertEx as assertEx15,
901
+ hexToBigInt as hexToBigInt9,
902
+ spanAsync as spanAsync7
903
+ } from "@xylabs/sdk-js";
904
+ import { PayloadBuilder as PayloadBuilder7 } from "@xyo-network/sdk-js";
905
+ import { isBridgeIntent as isBridgeIntent5 } from "@xyo-network/xl1-sdk";
906
+ import { Worker as Worker4 } from "bullmq";
907
+ import { getAddress as getAddress2 } from "ethers";
908
+
909
+ // src/services/validation/validateAmountMeetsMinBridgeAmount.ts
910
+ import { hexToBigInt as hexToBigInt4 } from "@xylabs/sdk-js";
911
+ function validateAmountMeetsMinBridgeAmount({
912
+ amount,
913
+ minBridgeAmount
914
+ }) {
915
+ return amount >= hexToBigInt4(minBridgeAmount);
916
+ }
917
+
918
+ // src/services/validation/validateBridgeEstimateExact.ts
919
+ import { hexToBigInt as hexToBigInt5, isUndefined } from "@xylabs/sdk-js";
920
+ import { PayloadBuilder as PayloadBuilder5 } from "@xyo-network/sdk-js";
921
+
922
+ // src/services/util/generateBridgeEstimate.ts
923
+ import { generateBridgeEstimate as generateBridgeEstimateShared } from "@xyo-network/chain-bridge-shared";
924
+ var generateBridgeEstimate = async (srcAddress, srcAmount, destAddress, config, nonceOverride) => {
925
+ const settings = await getBridgeSettings(config);
926
+ return generateBridgeEstimateShared(srcAddress, srcAmount, destAddress, settings, nonceOverride);
927
+ };
517
928
 
518
929
  // src/services/validation/validateBridgeEstimateExact.ts
519
- var validateBridgeEstimateExact = /* @__PURE__ */ __name(async (intent, transfer, config) => {
520
- const { srcAddress, srcAmount, destAddress } = intent;
930
+ var validateBridgeEstimateExact = async (intent, transfer, config) => {
931
+ const {
932
+ srcAddress,
933
+ srcAmount,
934
+ destAddress
935
+ } = intent;
521
936
  if (hexToBigInt5(srcAmount) < hexToBigInt5(getMinBridgeAmount(config))) return false;
522
937
  if (hexToBigInt5(srcAmount) > hexToBigInt5(getMaxBridgeAmount(config))) return false;
523
938
  const [calculatedIntent, calculatedTransfer] = await generateBridgeEstimate(srcAddress, srcAmount, destAddress, config);
@@ -529,72 +944,65 @@ var validateBridgeEstimateExact = /* @__PURE__ */ __name(async (intent, transfer
529
944
  const { epoch: actualTransferEpoch, ...actualTransferStatic } = transfer;
530
945
  if (await PayloadBuilder5.dataHash(expectedTransferStatic) !== await PayloadBuilder5.dataHash(actualTransferStatic)) return false;
531
946
  return true;
532
- }, "validateBridgeEstimateExact");
947
+ };
533
948
 
534
949
  // src/services/validation/validateBridgeTransaction.ts
535
950
  import { asAddress as asAddress4 } from "@xylabs/sdk-js";
536
- import { addressesContains, BoundWitnessValidator, payloadHashesContainsAll, payloadSchemasContainsAll } from "@xyo-network/boundwitness-validator";
951
+ import {
952
+ addressesContains,
953
+ BoundWitnessValidator,
954
+ payloadHashesContainsAll,
955
+ payloadSchemasContainsAll
956
+ } from "@xyo-network/boundwitness-validator";
537
957
  import { PayloadBuilder as PayloadBuilder6 } from "@xyo-network/sdk-js";
538
- import { BridgeIntentSchema as BridgeIntentSchema3, TransferSchema } from "@xyo-network/xl1-sdk";
539
- var validateBridgeTransaction = /* @__PURE__ */ __name(async (signedTxBw, intent, transfer, config) => {
958
+ import { BridgeIntentSchema, TransferSchema } from "@xyo-network/xl1-sdk";
959
+ var validateBridgeTransaction = async (signedTxBw, intent, transfer, config) => {
540
960
  const { srcAddress } = intent;
541
961
  const chainId = getXl1ChainId(config);
542
962
  if (signedTxBw.chain !== chainId) return false;
543
963
  if (signedTxBw.payload_hashes.length != 2) return false;
544
- if (!payloadSchemasContainsAll(signedTxBw, [
545
- BridgeIntentSchema3,
546
- TransferSchema
547
- ])) return false;
548
- const hashes = await PayloadBuilder6.hashes([
549
- intent,
550
- transfer
551
- ]);
964
+ if (!payloadSchemasContainsAll(signedTxBw, [BridgeIntentSchema, TransferSchema])) return false;
965
+ const hashes = await PayloadBuilder6.hashes([intent, transfer]);
552
966
  if (!payloadHashesContainsAll(signedTxBw, hashes)) return false;
553
967
  const errors = await new BoundWitnessValidator(signedTxBw).validate();
554
968
  if (errors.length > 0) return false;
555
969
  const sender = asAddress4(srcAddress, true);
556
970
  if (!addressesContains(signedTxBw, sender)) return false;
557
971
  return true;
558
- }, "validateBridgeTransaction");
972
+ };
559
973
 
560
974
  // src/services/validation/validateSufficientLiquiditySourceAllowance.ts
561
- import { assertEx as assertEx9, hexToBigInt as hexToBigInt6 } from "@xylabs/sdk-js";
562
- import { isBridgeIntent as isBridgeIntent2 } from "@xyo-network/xl1-sdk";
563
- var validateSufficientLiquiditySourceAllowance = /* @__PURE__ */ __name(async (tx, offChainPayloads, bridgeableToken, bridge, logger) => {
564
- const allPayloads = [
565
- ...tx[1],
566
- ...offChainPayloads
567
- ];
568
- const bridgeIntent = assertEx9(allPayloads.find(isBridgeIntent2), () => "No bridge intent found");
975
+ import { assertEx as assertEx10, hexToBigInt as hexToBigInt6 } from "@xylabs/sdk-js";
976
+ import { isBridgeIntent as isBridgeIntent3 } from "@xyo-network/xl1-sdk";
977
+ var validateSufficientLiquiditySourceAllowance = async (tx, offChainPayloads, bridgeableToken, bridge, logger) => {
978
+ const allPayloads = [...tx[1], ...offChainPayloads];
979
+ const bridgeIntent = assertEx10(allPayloads.find(isBridgeIntent3), () => "No bridge intent found");
569
980
  const amount = hexToBigInt6(bridgeIntent.destAmount);
570
981
  const liquiditySourceAddress = await bridge.liquiditySource();
571
982
  const bridgeAddress = await bridge.getAddress();
572
983
  const remainingAllowance = await bridgeableToken.allowance(liquiditySourceAddress, bridgeAddress);
573
984
  await logger?.log(`Remaining allowance: ${remainingAllowance.toString()}`);
574
985
  return remainingAllowance >= amount;
575
- }, "validateSufficientLiquiditySourceAllowance");
986
+ };
576
987
 
577
988
  // src/services/validation/validateSufficientLiquiditySourceBalance.ts
578
- import { assertEx as assertEx10, hexToBigInt as hexToBigInt7 } from "@xylabs/sdk-js";
579
- import { isBridgeIntent as isBridgeIntent3 } from "@xyo-network/xl1-sdk";
580
- var validateSufficientLiquiditySourceBalance = /* @__PURE__ */ __name(async (tx, offChainPayloads, bridgeableToken, bridge, logger) => {
581
- const allPayloads = [
582
- ...tx[1],
583
- ...offChainPayloads
584
- ];
585
- const bridgeIntent = assertEx10(allPayloads.find(isBridgeIntent3), () => "No bridge intent found");
989
+ import { assertEx as assertEx11, hexToBigInt as hexToBigInt7 } from "@xylabs/sdk-js";
990
+ import { isBridgeIntent as isBridgeIntent4 } from "@xyo-network/xl1-sdk";
991
+ var validateSufficientLiquiditySourceBalance = async (tx, offChainPayloads, bridgeableToken, bridge, logger) => {
992
+ const allPayloads = [...tx[1], ...offChainPayloads];
993
+ const bridgeIntent = assertEx11(allPayloads.find(isBridgeIntent4), () => "No bridge intent found");
586
994
  const amount = hexToBigInt7(bridgeIntent.destAmount);
587
995
  const liquiditySourceAddress = await bridge.liquiditySource();
588
996
  const balance = await bridgeableToken.balanceOf(liquiditySourceAddress);
589
997
  await logger?.log(`Remaining balance: ${balance.toString()}`);
590
998
  return balance >= amount;
591
- }, "validateSufficientLiquiditySourceBalance");
999
+ };
592
1000
 
593
1001
  // src/services/validation/validateSufficientRunnerEthBalanceForGas.ts
594
- import { assertEx as assertEx11 } from "@xylabs/sdk-js";
1002
+ import { assertEx as assertEx12 } from "@xylabs/sdk-js";
595
1003
  var DEFAULT_GAS_BUFFER_BPS = 2000n;
596
- var validateSufficientRunnerEthBalanceForGas = /* @__PURE__ */ __name(async (preparedTx, wallet, logger, bufferBps = DEFAULT_GAS_BUFFER_BPS) => {
597
- const provider = assertEx11(wallet.provider, () => "Wallet provider is not defined");
1004
+ var validateSufficientRunnerEthBalanceForGas = async (preparedTx, wallet, logger, bufferBps = DEFAULT_GAS_BUFFER_BPS) => {
1005
+ const provider = assertEx12(wallet.provider, () => "Wallet provider is not defined");
598
1006
  const feeData = await provider.getFeeData();
599
1007
  const perGas = feeData.maxFeePerGas ?? feeData.gasPrice;
600
1008
  if (perGas == null) {
@@ -610,91 +1018,112 @@ var validateSufficientRunnerEthBalanceForGas = /* @__PURE__ */ __name(async (pre
610
1018
  const baseRequired = estGas * perGas + txValue;
611
1019
  const required = baseRequired * (10000n + bufferBps) / 10000n;
612
1020
  const balance = await provider.getBalance(await wallet.getAddress());
613
- await logger?.log(`[gas] runner=${await wallet.getAddress()} balance=${balance.toString()} estGas=${estGas.toString()} perGas=${perGas.toString()} value=${txValue.toString()} requiredWithBuffer=${required.toString()} bufferBps=${bufferBps.toString()}`);
1021
+ await logger?.log(
1022
+ `[gas] runner=${await wallet.getAddress()} balance=${balance.toString()} estGas=${estGas.toString()} perGas=${perGas.toString()} value=${txValue.toString()} requiredWithBuffer=${required.toString()} bufferBps=${bufferBps.toString()}`
1023
+ );
614
1024
  return balance >= required;
615
- }, "validateSufficientRunnerEthBalanceForGas");
1025
+ };
616
1026
 
617
1027
  // src/services/validation/validateSufficientXl1ReserveBalance.ts
618
- import { assertEx as assertEx12 } from "@xylabs/sdk-js";
619
- async function validateSufficientXl1ReserveBalance({ amount, bridgeAccount, gateway, logger }) {
620
- const viewer = assertEx12(gateway.connection.viewer, () => "Gateway connection does not have a viewer");
1028
+ import { assertEx as assertEx13 } from "@xylabs/sdk-js";
1029
+ import { AttoXL1ConvertFactor } from "@xyo-network/xl1-sdk";
1030
+ var RESERVE_FEE_BUFFER = 1n * AttoXL1ConvertFactor.xl1;
1031
+ async function validateSufficientXl1ReserveBalance({
1032
+ amount,
1033
+ bridgeAccount,
1034
+ gateway,
1035
+ logger
1036
+ }) {
1037
+ const viewer = assertEx13(gateway.connection.viewer, () => "Gateway connection does not have a viewer");
621
1038
  const balance = await viewer.account.balance.accountBalance(bridgeAccount.address);
622
- await logger?.log(`XL1 reserve account ${bridgeAccount.address} balance: ${balance.toString()}; required: ${amount.toString()}`);
623
- return balance >= amount;
1039
+ const required = amount + RESERVE_FEE_BUFFER;
1040
+ await logger?.log(
1041
+ `XL1 reserve account ${bridgeAccount.address} balance: ${balance.toString()}; required: ${required.toString()} (amount=${amount.toString()} + buffer=${RESERVE_FEE_BUFFER.toString()})`
1042
+ );
1043
+ return balance >= required;
624
1044
  }
625
- __name(validateSufficientXl1ReserveBalance, "validateSufficientXl1ReserveBalance");
626
1045
 
627
1046
  // src/services/validation/validateSufficientXL1SourceAddressBalance.ts
628
- import { asAddress as asAddress5, assertEx as assertEx13, hexToBigInt as hexToBigInt8 } from "@xylabs/sdk-js";
629
- var validateSufficientXL1SourceAddressBalance = /* @__PURE__ */ __name(async (bridgeIntent, gateway, config, logger) => {
630
- const viewer = assertEx13(gateway.connection.viewer, () => "Gateway connection does not have a viewer");
631
- const { srcAddress, srcAmount, destAddress } = bridgeIntent;
1047
+ import {
1048
+ asAddress as asAddress5,
1049
+ assertEx as assertEx14,
1050
+ hexToBigInt as hexToBigInt8
1051
+ } from "@xylabs/sdk-js";
1052
+ var validateSufficientXL1SourceAddressBalance = async (bridgeIntent, gateway, config, logger) => {
1053
+ const viewer = assertEx14(gateway.connection.viewer, () => "Gateway connection does not have a viewer");
1054
+ const {
1055
+ srcAddress,
1056
+ srcAmount,
1057
+ destAddress
1058
+ } = bridgeIntent;
632
1059
  const srcAddressBranded = asAddress5(srcAddress, () => `Invalid source address in bridge intent: ${srcAddress}`);
633
1060
  const [_, calculatedTransfer] = await generateBridgeEstimate(srcAddress, srcAmount, destAddress, config);
634
1061
  const totalAmount = Object.values(calculatedTransfer.transfers).reduce((acc, transfer) => acc + hexToBigInt8(transfer), 0n);
635
1062
  const accountBalance = await viewer.account.balance.accountBalance(srcAddressBranded);
636
1063
  await logger?.log(`Account balance for ${srcAddressBranded}: ${accountBalance.toString()}`);
637
1064
  return accountBalance >= totalAmount;
638
- }, "validateSufficientXL1SourceAddressBalance");
1065
+ };
639
1066
 
640
1067
  // src/services/queue/workers/EthTransactionPreparation.ts
641
1068
  var name4 = "Prepare ETH Transaction";
642
1069
  var queueName4 = "eth-tx-prepare";
643
- var createWorker4 = /* @__PURE__ */ __name((connection2, telemetry2, services) => {
644
- const bridge = assertEx14(services?.bridge, () => "bridge service not provided");
645
- const bridgeableToken = assertEx14(services?.bridgeableToken, () => "bridgeableToken service not provided");
646
- const stateMap = assertEx14(services?.ethTxStateMap, () => "ethTxStateMap service not provided");
647
- const wallet = assertEx14(services?.wallet, () => "wallet service not provided");
648
- const worker = new Worker4(queueName4, async (job) => {
649
- const { tx, offChainPayloads } = job.data;
650
- const hash = await PayloadBuilder7.hash(tx[0]);
651
- await job.log(`[${hash}] preparing ETH transaction`);
652
- await job.log(`[${hash}] validating liquiditySource has sufficient allowance`);
653
- if (!await validateSufficientLiquiditySourceAllowance(tx, offChainPayloads, bridgeableToken, bridge, job)) {
654
- throw new Error("Liquidity source does not have sufficient allowance for the bridge to execute the transaction");
655
- }
656
- await job.log(`[${hash}] validated liquiditySource has sufficient allowance`);
657
- await job.log(`[${hash}] validating liquiditySource has sufficient balance`);
658
- if (!await validateSufficientLiquiditySourceBalance(tx, offChainPayloads, bridgeableToken, bridge, job)) {
659
- throw new Error("Liquidity source does not have sufficient balance for the bridge to execute the transaction");
660
- }
661
- await job.log(`[${hash}] validated liquiditySource has sufficient balance`);
662
- await job.log(`[${hash}] building ETH transaction`);
663
- const allPayloads = [
664
- ...tx[1],
665
- ...offChainPayloads
666
- ];
667
- const bridgeIntent = assertEx14(allPayloads.find(isBridgeIntent4), () => "No bridge intent found");
668
- const amount = hexToBigInt9(bridgeIntent.destAmount);
669
- const srcAddress = getAddress(bridgeIntent.srcAddress);
670
- const destAddress = getAddress(bridgeIntent.destAddress);
671
- const nonce = hexToBigInt9(await PayloadBuilder7.hash(tx[0]));
672
- const preparedTx = await bridge.getFunction("bridgeFromRemote").populateTransaction(srcAddress, destAddress, amount, nonce);
673
- await job.log(`[${hash}] built ETH transaction`);
674
- await job.log(`[${hash}] validating tx runner has sufficient ETH for gas`);
675
- if (!await validateSufficientRunnerEthBalanceForGas(preparedTx, wallet, job)) {
676
- throw new Error("Transaction runner does not have sufficient ETH to cover estimated gas (with buffer)");
1070
+ var createWorker4 = (connection2, telemetry2, services) => {
1071
+ const bridge = assertEx15(services?.bridge, () => "bridge service not provided");
1072
+ const bridgeableToken = assertEx15(services?.bridgeableToken, () => "bridgeableToken service not provided");
1073
+ const stateMap = assertEx15(services?.ethTxStateMap, () => "ethTxStateMap service not provided");
1074
+ const wallet = assertEx15(services?.wallet, () => "wallet service not provided");
1075
+ const logger = assertEx15(services?.logger, () => "logger service not provided");
1076
+ const worker = new Worker4(
1077
+ queueName4,
1078
+ async (job) => {
1079
+ return await spanAsync7("bridge:worker:eth-tx-prepare", async () => {
1080
+ const { tx, offChainPayloads } = job.data;
1081
+ const hash = await PayloadBuilder7.hash(tx[0]);
1082
+ await job.log(`[${hash}] preparing ETH transaction`);
1083
+ await job.log(`[${hash}] validating liquiditySource has sufficient allowance`);
1084
+ if (!await validateSufficientLiquiditySourceAllowance(tx, offChainPayloads, bridgeableToken, bridge, job)) {
1085
+ throw new Error("Liquidity source does not have sufficient allowance for the bridge to execute the transaction");
1086
+ }
1087
+ await job.log(`[${hash}] validated liquiditySource has sufficient allowance`);
1088
+ await job.log(`[${hash}] validating liquiditySource has sufficient balance`);
1089
+ if (!await validateSufficientLiquiditySourceBalance(tx, offChainPayloads, bridgeableToken, bridge, job)) {
1090
+ throw new Error("Liquidity source does not have sufficient balance for the bridge to execute the transaction");
1091
+ }
1092
+ await job.log(`[${hash}] validated liquiditySource has sufficient balance`);
1093
+ await job.log(`[${hash}] building ETH transaction`);
1094
+ const allPayloads = [...tx[1], ...offChainPayloads];
1095
+ const bridgeIntent = assertEx15(allPayloads.find(isBridgeIntent5), () => "No bridge intent found");
1096
+ const amount = hexToBigInt9(bridgeIntent.destAmount);
1097
+ const srcAddress = getAddress2(bridgeIntent.srcAddress);
1098
+ const destAddress = getAddress2(bridgeIntent.destAddress);
1099
+ const nonce = hexToBigInt9(await PayloadBuilder7.hash(tx[0]));
1100
+ const preparedTx = await bridge.getFunction("bridgeFromRemote").populateTransaction(srcAddress, destAddress, amount, nonce);
1101
+ await job.log(`[${hash}] built ETH transaction`);
1102
+ await job.log(`[${hash}] validating tx runner has sufficient ETH for gas`);
1103
+ if (!await validateSufficientRunnerEthBalanceForGas(preparedTx, wallet, job)) {
1104
+ throw new Error("Transaction runner does not have sufficient ETH to cover estimated gas (with buffer)");
1105
+ }
1106
+ await job.log(`[${hash}] validated tx runner has sufficient ETH for gas`);
1107
+ await job.log(`[${hash}] storing ETH preparedTx`);
1108
+ await stateMap.set(hash, { preparedTx });
1109
+ await job.log(`[${hash}] stored ETH preparedTx`);
1110
+ await job.log(`[${hash}] prepared ETH transaction`);
1111
+ return {};
1112
+ }, { logger, timeBudgetLimit: 1e3 });
1113
+ },
1114
+ {
1115
+ connection: connection2,
1116
+ telemetry: telemetry2,
1117
+ prefix
677
1118
  }
678
- await job.log(`[${hash}] validated tx runner has sufficient ETH for gas`);
679
- await job.log(`[${hash}] storing ETH preparedTx`);
680
- await stateMap.set(hash, {
681
- preparedTx
682
- });
683
- await job.log(`[${hash}] stored ETH preparedTx`);
684
- await job.log(`[${hash}] prepared ETH transaction`);
685
- return {};
686
- }, {
687
- connection: connection2,
688
- telemetry: telemetry2,
689
- prefix
690
- });
1119
+ );
691
1120
  worker.on("failed", (job, err) => {
692
- console.error(`[${name4}] Job ${job?.id} failed:`, err.message);
1121
+ logger.error(`[eth-prep] job ${job?.id} failed: ${err.message}`);
693
1122
  });
694
1123
  worker.on("error", (err) => {
695
- console.error(`[${name4}] Worker error:`, err);
1124
+ logger.error(`[eth-prep] worker error: ${err.message}`);
696
1125
  });
697
- }, "createWorker");
1126
+ };
698
1127
  var EthTransactionPreparation = {
699
1128
  createWorker: createWorker4,
700
1129
  name: name4,
@@ -702,45 +1131,52 @@ var EthTransactionPreparation = {
702
1131
  };
703
1132
 
704
1133
  // src/services/queue/workers/EthTransactionSubmission.ts
705
- import { assertEx as assertEx15, isDefined as isDefined7 } from "@xylabs/sdk-js";
1134
+ import {
1135
+ assertEx as assertEx16,
1136
+ isDefined as isDefined7,
1137
+ spanAsync as spanAsync8
1138
+ } from "@xylabs/sdk-js";
706
1139
  import { PayloadBuilder as PayloadBuilder8 } from "@xyo-network/sdk-js";
707
1140
  import { Worker as Worker5 } from "bullmq";
708
1141
  var name5 = "Submit ETH Transaction";
709
1142
  var queueName5 = "eth-tx-submit";
710
- var createWorker5 = /* @__PURE__ */ __name((connection2, telemetry2, services) => {
711
- const bridge = assertEx15(services?.bridge, () => "bridge service not provided");
712
- const wallet = assertEx15(services?.wallet, () => "wallet service not provided");
713
- const stateMap = assertEx15(services?.ethTxStateMap, () => "ethTxStateMap service not provided");
714
- const worker = new Worker5(queueName5, async (job) => {
715
- const { tx, offChainPayloads } = job.data;
716
- const hash = await PayloadBuilder8.hash(tx[0]);
717
- const state = assertEx15(await stateMap.get(hash), () => `[${hash}] state not found`);
718
- const { submissionHash: existingSubmissionHash } = state;
719
- if (isDefined7(existingSubmissionHash)) {
720
- await job.log(`[${hash}] Tx already submitted with submission response hash ${existingSubmissionHash}`);
721
- return {
722
- submissionHash: existingSubmissionHash
723
- };
1143
+ var createWorker5 = (connection2, telemetry2, services) => {
1144
+ const bridge = assertEx16(services?.bridge, () => "bridge service not provided");
1145
+ const wallet = assertEx16(services?.wallet, () => "wallet service not provided");
1146
+ const stateMap = assertEx16(services?.ethTxStateMap, () => "ethTxStateMap service not provided");
1147
+ const logger = assertEx16(services?.logger, () => "logger service not provided");
1148
+ const worker = new Worker5(
1149
+ queueName5,
1150
+ async (job) => {
1151
+ return await spanAsync8("bridge:worker:eth-tx-submit", async () => {
1152
+ const { tx, offChainPayloads } = job.data;
1153
+ const hash = await PayloadBuilder8.hash(tx[0]);
1154
+ const state = assertEx16(await stateMap.get(hash), () => `[${hash}] state not found`);
1155
+ const { submissionHash: existingSubmissionHash } = state;
1156
+ if (isDefined7(existingSubmissionHash)) {
1157
+ await job.log(`[${hash}] Tx already submitted with submission response hash ${existingSubmissionHash}`);
1158
+ return { submissionHash: existingSubmissionHash };
1159
+ }
1160
+ await job.log(`[${hash}] Submitting ETH tx`);
1161
+ const submissionHash = assertEx16(await submitEthTransaction(tx, offChainPayloads, bridge, wallet), () => `[${hash}] submissionHash not found in receipt`);
1162
+ await job.log(`[${hash}] Submitted ETH tx and received submission response hash ${submissionHash}`);
1163
+ return { submissionHash };
1164
+ }, { logger, timeBudgetLimit: 5e3 });
1165
+ },
1166
+ {
1167
+ connection: connection2,
1168
+ telemetry: telemetry2,
1169
+ concurrency: 1,
1170
+ prefix
724
1171
  }
725
- await job.log(`[${hash}] Submitting ETH tx`);
726
- const submissionHash = assertEx15(await submitEthTransaction(tx, offChainPayloads, bridge, wallet), () => `[${hash}] submissionHash not found in receipt`);
727
- await job.log(`[${hash}] Submitted ETH tx and received submission response hash ${submissionHash}`);
728
- return {
729
- submissionHash
730
- };
731
- }, {
732
- connection: connection2,
733
- telemetry: telemetry2,
734
- concurrency: 1,
735
- prefix
736
- });
1172
+ );
737
1173
  worker.on("failed", (job, err) => {
738
- console.error(`[${name5}] Job ${job?.id} failed:`, err.message);
1174
+ logger.error(`[eth-submit] job ${job?.id} failed: ${err.message}`);
739
1175
  });
740
1176
  worker.on("error", (err) => {
741
- console.error(`[${name5}] Worker error:`, err);
1177
+ logger.error(`[eth-submit] worker error: ${err.message}`);
742
1178
  });
743
- }, "createWorker");
1179
+ };
744
1180
  var EthTransactionSubmission = {
745
1181
  createWorker: createWorker5,
746
1182
  name: name5,
@@ -748,48 +1184,55 @@ var EthTransactionSubmission = {
748
1184
  };
749
1185
 
750
1186
  // src/services/queue/workers/EthTransactionSubmissionStorage.ts
751
- import { assertEx as assertEx16, isDefined as isDefined8 } from "@xylabs/sdk-js";
1187
+ import {
1188
+ assertEx as assertEx17,
1189
+ isDefined as isDefined8,
1190
+ spanAsync as spanAsync9
1191
+ } from "@xylabs/sdk-js";
752
1192
  import { PayloadBuilder as PayloadBuilder9 } from "@xyo-network/sdk-js";
753
1193
  import { Worker as Worker6 } from "bullmq";
754
1194
  var name6 = "Store ETH Transaction Submission";
755
1195
  var queueName6 = "eth-tx-store-submission";
756
- var createWorker6 = /* @__PURE__ */ __name((connection2, telemetry2, services) => {
757
- const stateMap = assertEx16(services?.ethTxStateMap, () => "ethTxStateMap service not provided");
758
- const worker = new Worker6(queueName6, async (job) => {
759
- const { tx } = job.data;
760
- const hash = await PayloadBuilder9.hash(tx[0]);
761
- const state = assertEx16(await stateMap.get(hash), () => `[${hash}] state not found`);
762
- const { submissionHash: existingSubmissionHash } = state;
763
- if (isDefined8(existingSubmissionHash)) {
764
- await job.log(`[${hash}] submissionHash already stored as ${existingSubmissionHash}`);
765
- return {
766
- submissionHash: existingSubmissionHash
767
- };
1196
+ var createWorker6 = (connection2, telemetry2, services) => {
1197
+ const stateMap = assertEx17(services?.ethTxStateMap, () => "ethTxStateMap service not provided");
1198
+ const logger = assertEx17(services?.logger, () => "logger service not provided");
1199
+ const worker = new Worker6(
1200
+ queueName6,
1201
+ async (job) => {
1202
+ return await spanAsync9("bridge:worker:eth-tx-store-submission", async () => {
1203
+ const { tx } = job.data;
1204
+ const hash = await PayloadBuilder9.hash(tx[0]);
1205
+ const state = assertEx17(await stateMap.get(hash), () => `[${hash}] state not found`);
1206
+ const { submissionHash: existingSubmissionHash } = state;
1207
+ if (isDefined8(existingSubmissionHash)) {
1208
+ await job.log(`[${hash}] submissionHash already stored as ${existingSubmissionHash}`);
1209
+ return { submissionHash: existingSubmissionHash };
1210
+ }
1211
+ const childrenValues = await job.getChildrenValues();
1212
+ const jobKey = `${prefix}:${EthTransactionSubmission.queueName}:${hash}`;
1213
+ const childValues = childrenValues?.[jobKey];
1214
+ const submissionHash = childValues?.submissionHash;
1215
+ const resolvedSubmissionHash = assertEx17(submissionHash, () => `[${hash}] child submissionHash not found in children values`);
1216
+ await job.log(`[${hash}] Storing ETH submissionHash`);
1217
+ state.submissionHash = resolvedSubmissionHash;
1218
+ await stateMap.set(hash, state);
1219
+ await job.log(`[${hash}] Stored ETH submissionHash`);
1220
+ return { submissionHash: resolvedSubmissionHash };
1221
+ }, { logger, timeBudgetLimit: 500 });
1222
+ },
1223
+ {
1224
+ connection: connection2,
1225
+ telemetry: telemetry2,
1226
+ prefix
768
1227
  }
769
- const childrenValues = await job.getChildrenValues();
770
- const jobKey = `${prefix}:${EthTransactionSubmission.queueName}:${hash}`;
771
- const childValues = childrenValues?.[jobKey];
772
- const submissionHash = childValues?.submissionHash;
773
- const resolvedSubmissionHash = assertEx16(submissionHash, () => `[${hash}] child submissionHash not found in children values`);
774
- await job.log(`[${hash}] Storing ETH submissionHash`);
775
- state.submissionHash = resolvedSubmissionHash;
776
- await stateMap.set(hash, state);
777
- await job.log(`[${hash}] Stored ETH submissionHash`);
778
- return {
779
- submissionHash: resolvedSubmissionHash
780
- };
781
- }, {
782
- connection: connection2,
783
- telemetry: telemetry2,
784
- prefix
785
- });
1228
+ );
786
1229
  worker.on("failed", (job, err) => {
787
- console.error(`[${name6}] Job ${job?.id} failed:`, err.message);
1230
+ logger.error(`[eth-submit-store] job ${job?.id} failed: ${err.message}`);
788
1231
  });
789
1232
  worker.on("error", (err) => {
790
- console.error(`[${name6}] Worker error:`, err);
1233
+ logger.error(`[eth-submit-store] worker error: ${err.message}`);
791
1234
  });
792
- }, "createWorker");
1235
+ };
793
1236
  var EthTransactionSubmissionStorage = {
794
1237
  createWorker: createWorker6,
795
1238
  name: name6,
@@ -797,23 +1240,58 @@ var EthTransactionSubmissionStorage = {
797
1240
  };
798
1241
 
799
1242
  // src/services/queue/workers/Xl1ReserveTxFulfillment.ts
800
- import { assertEx as assertEx17, delay, isDefined as isDefined9, isNull as isNull2 } from "@xylabs/sdk-js";
1243
+ import {
1244
+ assertEx as assertEx18,
1245
+ delay,
1246
+ hexToBigInt as hexToBigInt10,
1247
+ isDefined as isDefined9,
1248
+ isNull as isNull2,
1249
+ spanAsync as spanAsync10
1250
+ } from "@xylabs/sdk-js";
801
1251
  import { PayloadBuilder as PayloadBuilder10 } from "@xyo-network/sdk-js";
802
1252
  import { asXL1BlockNumber } from "@xyo-network/xl1-sdk";
803
- import { Worker as Worker7 } from "bullmq";
1253
+ import { UnrecoverableError as UnrecoverableError2, Worker as Worker7 } from "bullmq";
804
1254
  var name7 = "XL1 Reserve Transfer Fulfillment";
805
1255
  var queueName7 = "eth-to-xl1-fulfill";
806
1256
  var EXP_BLOCKS_AHEAD = 1e3;
807
1257
  var POLL_INTERVAL_MS = 5e3;
808
1258
  var CONCURRENCY = 32;
1259
+ async function markFulfilled(ctx, attempt) {
1260
+ const {
1261
+ bridgeFlowMetrics,
1262
+ fulfillmentMap,
1263
+ identity,
1264
+ state,
1265
+ xl1TokenAddress
1266
+ } = ctx;
1267
+ state.fulfilled = attempt;
1268
+ state.currentAttempt = void 0;
1269
+ const intent = assertEx18(state.acceptedIntent, () => `[${identity}] acceptedIntent missing on fulfillment \u2014 Stage 1 did not snapshot`);
1270
+ state.acceptedDestinationObservation = buildAcceptedDestinationObservation(intent, attempt.txHash);
1271
+ await fulfillmentMap.set(identity, state);
1272
+ const observedAt = state.canonical?.observedAt;
1273
+ const latencySeconds = observedAt === void 0 ? void 0 : (attempt.submittedAt - observedAt) / 1e3;
1274
+ const acceptedFees = state.acceptedFees;
1275
+ const feeAmount = acceptedFees === void 0 ? 0n : hexToBigInt10(acceptedFees.feeFixed) + hexToBigInt10(acceptedFees.feeVariable);
1276
+ bridgeFlowMetrics.recordSuccess({
1277
+ direction: "inbound",
1278
+ feeAmount,
1279
+ latencySeconds,
1280
+ token: xl1TokenAddress
1281
+ });
1282
+ }
809
1283
  async function tryResumeCurrentAttempt(ctx) {
810
- const { fulfillmentMap, identity, job, state, viewer } = ctx;
811
- const attempt = assertEx17(state.currentAttempt, () => "tryResumeCurrentAttempt called without currentAttempt");
1284
+ const {
1285
+ fulfillmentMap,
1286
+ identity,
1287
+ job,
1288
+ state,
1289
+ viewer
1290
+ } = ctx;
1291
+ const attempt = assertEx18(state.currentAttempt, () => "tryResumeCurrentAttempt called without currentAttempt");
812
1292
  const found = await viewer.transaction.byHash(attempt.txHash);
813
1293
  if (isDefined9(found) && !isNull2(found)) {
814
- state.fulfilled = attempt;
815
- state.currentAttempt = void 0;
816
- await fulfillmentMap.set(identity, state);
1294
+ await markFulfilled(ctx, attempt);
817
1295
  await job.log(`[${identity}] tx ${attempt.txHash} included on resume`);
818
1296
  return;
819
1297
  }
@@ -825,19 +1303,35 @@ async function tryResumeCurrentAttempt(ctx) {
825
1303
  await job.log(`[${identity}] resumed attempt expired (head=${head}); will build fresh`);
826
1304
  }
827
1305
  }
828
- __name(tryResumeCurrentAttempt, "tryResumeCurrentAttempt");
829
1306
  async function buildAndSubmitFreshAttempt(ctx) {
830
- const { account, bridgeId, contractAddress, evmChainId, fulfillmentMap, gateway, identity, job, state, viewer, xl1ChainId, xl1TokenAddress } = ctx;
831
- const canonical = assertEx17(state.canonical, () => "buildAndSubmitFreshAttempt requires canonical");
1307
+ const {
1308
+ account,
1309
+ bridgeId,
1310
+ config,
1311
+ contractAddress,
1312
+ evmChainId,
1313
+ fulfillmentMap,
1314
+ gateway,
1315
+ identity,
1316
+ job,
1317
+ state,
1318
+ viewer,
1319
+ xl1ChainId,
1320
+ xl1TokenAddress
1321
+ } = ctx;
1322
+ const canonical = assertEx18(state.canonical, () => `[${identity}] buildAndSubmitFreshAttempt requires canonical`);
1323
+ const acceptedFees = assertEx18(state.acceptedFees, () => `[${identity}] acceptedFees missing \u2014 Stage 1 did not snapshot`);
1324
+ const feesAmount = hexToBigInt10(acceptedFees.feeFixed) + hexToBigInt10(acceptedFees.feeVariable);
1325
+ const { feesAddress } = await getTransferAddresses(config);
832
1326
  const sufficient = await validateSufficientXl1ReserveBalance({
833
1327
  amount: canonical.amount,
834
1328
  bridgeAccount: account,
835
1329
  gateway
836
1330
  });
837
1331
  if (!sufficient) {
838
- const msg = `[${identity}] XL1 reserve below required ${canonical.amount.toString()}; will retry`;
1332
+ const msg = `[${identity}] XL1 reserve below required ${canonical.amount.toString()}; terminal \u2014 refill and retry`;
839
1333
  await job.log(msg);
840
- throw new Error(msg);
1334
+ throw new UnrecoverableError2(msg);
841
1335
  }
842
1336
  const head = await viewer.currentBlockNumber();
843
1337
  const nbf = asXL1BlockNumber(head, true);
@@ -853,6 +1347,8 @@ async function buildAndSubmitFreshAttempt(ctx) {
853
1347
  evmTokenAddress: canonical.destToken,
854
1348
  evmTxHash: canonical.evmTxHash,
855
1349
  exp,
1350
+ feesAddress,
1351
+ feesAmount,
856
1352
  nbf,
857
1353
  xl1ChainId,
858
1354
  xl1TokenAddress
@@ -866,18 +1362,24 @@ async function buildAndSubmitFreshAttempt(ctx) {
866
1362
  };
867
1363
  await fulfillmentMap.set(identity, state);
868
1364
  await submitXl1Transaction(tx, [], gateway);
869
- await job.log(`[${identity}] attempt ${state.previousAttempts.length + 1} submitted: txHash=${txHash} nbf=${head} exp=${head + EXP_BLOCKS_AHEAD}`);
1365
+ await job.log(
1366
+ `[${identity}] attempt ${state.previousAttempts.length + 1} submitted: txHash=${txHash} nbf=${head} exp=${head + EXP_BLOCKS_AHEAD}`
1367
+ );
870
1368
  }
871
- __name(buildAndSubmitFreshAttempt, "buildAndSubmitFreshAttempt");
872
1369
  async function pollUntilIncludedOrExpired(ctx) {
873
- const { fulfillmentMap, identity, job, state, viewer } = ctx;
874
- const attempt = assertEx17(state.currentAttempt, () => "pollUntilIncludedOrExpired requires currentAttempt");
1370
+ const {
1371
+ bridgeFlowMetrics,
1372
+ fulfillmentMap,
1373
+ identity,
1374
+ job,
1375
+ state,
1376
+ viewer
1377
+ } = ctx;
1378
+ const attempt = assertEx18(state.currentAttempt, () => "pollUntilIncludedOrExpired requires currentAttempt");
875
1379
  while (true) {
876
1380
  const found = await viewer.transaction.byHash(attempt.txHash);
877
1381
  if (isDefined9(found) && !isNull2(found)) {
878
- state.fulfilled = attempt;
879
- state.currentAttempt = void 0;
880
- await fulfillmentMap.set(identity, state);
1382
+ await markFulfilled(ctx, attempt);
881
1383
  await job.log(`[${identity}] tx ${attempt.txHash} included`);
882
1384
  return;
883
1385
  }
@@ -886,6 +1388,7 @@ async function pollUntilIncludedOrExpired(ctx) {
886
1388
  state.previousAttempts.push(attempt);
887
1389
  state.currentAttempt = void 0;
888
1390
  await fulfillmentMap.set(identity, state);
1391
+ bridgeFlowMetrics.recordAttemptExpiration({ direction: "inbound" });
889
1392
  const msg = `[${identity}] attempt ${state.previousAttempts.length} expired (head=${head}, exp=${attempt.exp})`;
890
1393
  await job.log(msg);
891
1394
  throw new Error(msg);
@@ -893,72 +1396,89 @@ async function pollUntilIncludedOrExpired(ctx) {
893
1396
  await delay(POLL_INTERVAL_MS);
894
1397
  }
895
1398
  }
896
- __name(pollUntilIncludedOrExpired, "pollUntilIncludedOrExpired");
897
- var createWorker7 = /* @__PURE__ */ __name((connection2, telemetry2, services) => {
898
- const svc = assertEx17(services, () => "services not provided");
899
- const { account, bridgeFulfillmentMap, gateway } = svc;
900
- const worker = new Worker7(queueName7, async (job) => {
901
- const { bridgeId, contractAddress, evmChainId, identity, xl1ChainId, xl1TokenAddress } = job.data;
902
- const initialState = await bridgeFulfillmentMap.get(identity);
903
- if (initialState?.fulfilled) {
904
- await job.log(`[${identity}] already fulfilled \u2014 skipping`);
905
- return;
906
- }
907
- const state = assertEx17(initialState, () => `[${identity}] no fulfillment state \u2014 Stage 1 did not run`);
908
- assertEx17(state.canonical, () => `[${identity}] canonical missing \u2014 Stage 1 did not write canonical`);
909
- if (state.failed) {
910
- state.failed = void 0;
911
- await bridgeFulfillmentMap.set(identity, state);
912
- }
913
- const viewer = assertEx17(gateway.connection.viewer, () => `[${identity}] gateway viewer not available`);
914
- const ctx = {
915
- fulfillmentMap: bridgeFulfillmentMap,
916
- identity,
917
- job,
918
- state,
919
- viewer
920
- };
921
- if (state.currentAttempt) {
922
- await tryResumeCurrentAttempt(ctx);
923
- if (state.fulfilled) return;
1399
+ var createWorker7 = (connection2, telemetry2, services) => {
1400
+ const svc = assertEx18(services, () => "services not provided");
1401
+ const {
1402
+ account,
1403
+ bridgeFlowMetrics,
1404
+ bridgeFulfillmentMap,
1405
+ config,
1406
+ gateway,
1407
+ logger
1408
+ } = svc;
1409
+ const worker = new Worker7(
1410
+ queueName7,
1411
+ async (job) => {
1412
+ await spanAsync10("bridge:worker:eth-to-xl1-fulfill", async () => {
1413
+ const {
1414
+ bridgeId,
1415
+ contractAddress,
1416
+ evmChainId,
1417
+ identity,
1418
+ xl1ChainId,
1419
+ xl1TokenAddress
1420
+ } = job.data;
1421
+ const initialState = await bridgeFulfillmentMap.get(identity);
1422
+ if (initialState?.fulfilled) {
1423
+ await job.log(`[${identity}] already fulfilled \u2014 skipping`);
1424
+ return;
1425
+ }
1426
+ const state = assertEx18(initialState, () => `[${identity}] no fulfillment state \u2014 Stage 1 did not run`);
1427
+ const canonical = assertEx18(state.canonical, () => `[${identity}] canonical missing \u2014 Stage 1 did not write canonical`);
1428
+ const minBridgeAmount = getMinBridgeAmount(config);
1429
+ if (!validateAmountMeetsMinBridgeAmount({ amount: canonical.amount, minBridgeAmount })) {
1430
+ await job.log(`[${identity}] amount ${canonical.amount} below minBridgeAmount ${minBridgeAmount}; terminal`);
1431
+ throw new UnrecoverableError2(`[${identity}] below_min_bridge_amount: amount=${canonical.amount} minBridgeAmount=${minBridgeAmount}`);
1432
+ }
1433
+ const viewer = assertEx18(gateway.connection.viewer, () => `[${identity}] gateway viewer not available`);
1434
+ const ctx = {
1435
+ bridgeFlowMetrics,
1436
+ fulfillmentMap: bridgeFulfillmentMap,
1437
+ identity,
1438
+ job,
1439
+ state,
1440
+ viewer,
1441
+ xl1TokenAddress
1442
+ };
1443
+ if (state.currentAttempt) {
1444
+ await tryResumeCurrentAttempt(ctx);
1445
+ if (state.fulfilled) return;
1446
+ }
1447
+ if (!state.currentAttempt) {
1448
+ await buildAndSubmitFreshAttempt({
1449
+ ...ctx,
1450
+ account,
1451
+ bridgeId: BigInt(bridgeId),
1452
+ config,
1453
+ contractAddress,
1454
+ evmChainId,
1455
+ gateway,
1456
+ xl1ChainId,
1457
+ xl1TokenAddress
1458
+ });
1459
+ }
1460
+ await pollUntilIncludedOrExpired(ctx);
1461
+ }, { logger });
1462
+ },
1463
+ {
1464
+ concurrency: CONCURRENCY,
1465
+ connection: connection2,
1466
+ prefix,
1467
+ telemetry: telemetry2
924
1468
  }
925
- if (!state.currentAttempt) {
926
- await buildAndSubmitFreshAttempt({
927
- ...ctx,
928
- account,
929
- bridgeId: BigInt(bridgeId),
930
- contractAddress,
931
- evmChainId,
932
- gateway,
933
- xl1ChainId,
934
- xl1TokenAddress
935
- });
1469
+ );
1470
+ worker.on("failed", (job, err) => {
1471
+ logger.error(`[xl1-fulfill] job ${job?.id} failed: ${err.message}`);
1472
+ if (job === void 0) return;
1473
+ const attemptsAllowed = job.opts.attempts ?? 1;
1474
+ if (job.attemptsMade >= attemptsAllowed) {
1475
+ bridgeFlowMetrics.recordTerminalFailure({ direction: "inbound", reason: bucketFailureReason(err.message) });
936
1476
  }
937
- await pollUntilIncludedOrExpired(ctx);
938
- }, {
939
- concurrency: CONCURRENCY,
940
- connection: connection2,
941
- prefix,
942
- telemetry: telemetry2
943
- });
944
- worker.on("failed", async (job, err) => {
945
- if (!isDefined9(job)) return;
946
- const attemptsAllowed = job.opts.attempts ?? Infinity;
947
- if (job.attemptsMade < attemptsAllowed) return;
948
- const identity = job.data?.identity;
949
- if (!isDefined9(identity)) return;
950
- const state = await bridgeFulfillmentMap.get(identity);
951
- if (!isDefined9(state)) return;
952
- state.failed = {
953
- at: Date.now(),
954
- reason: `attempts exhausted (${job.attemptsMade}/${attemptsAllowed}): ${err.message}`
955
- };
956
- await bridgeFulfillmentMap.set(identity, state);
957
1477
  });
958
1478
  worker.on("error", (err) => {
959
- console.error(`[${name7}] Worker error:`, err);
1479
+ logger.error(`[xl1-fulfill] worker error: ${err.message}`);
960
1480
  });
961
- }, "createWorker");
1481
+ };
962
1482
  var Xl1ReserveTxFulfillment = {
963
1483
  createWorker: createWorker7,
964
1484
  name: name7,
@@ -966,26 +1486,34 @@ var Xl1ReserveTxFulfillment = {
966
1486
  };
967
1487
 
968
1488
  // src/services/queue/workers/Xl1ToEthBridgeParent.ts
1489
+ import { assertEx as assertEx19, spanAsync as spanAsync11 } from "@xylabs/sdk-js";
969
1490
  import { Worker as Worker8 } from "bullmq";
970
1491
  var name8 = "Bridge XL1 to Ethereum";
971
1492
  var queueName8 = "xl1-to-eth-bridge";
972
- var createWorker8 = /* @__PURE__ */ __name((connection2, telemetry2) => {
973
- const worker = new Worker8(queueName8, async (job) => {
974
- await job.log(`[${job.name}] start`);
975
- await job.log(`[${job.name}] done`);
976
- return {};
977
- }, {
978
- connection: connection2,
979
- telemetry: telemetry2,
980
- prefix
981
- });
1493
+ var createWorker8 = (connection2, telemetry2, services) => {
1494
+ const logger = assertEx19(services?.logger, () => "logger service not provided");
1495
+ const worker = new Worker8(
1496
+ queueName8,
1497
+ async (job) => {
1498
+ return await spanAsync11("bridge:worker:xl1-to-eth-bridge", async () => {
1499
+ await job.log(`[${job.name}] start`);
1500
+ await job.log(`[${job.name}] done`);
1501
+ return {};
1502
+ }, { logger, timeBudgetLimit: 5e3 });
1503
+ },
1504
+ {
1505
+ connection: connection2,
1506
+ telemetry: telemetry2,
1507
+ prefix
1508
+ }
1509
+ );
982
1510
  worker.on("failed", (job, err) => {
983
- console.error(`[${name8}] Job ${job?.id} failed:`, err.message);
1511
+ logger.error(`[xl1-to-eth-parent] job ${job?.id} failed: ${err.message}`);
984
1512
  });
985
1513
  worker.on("error", (err) => {
986
- console.error(`[${name8}] Worker error:`, err);
1514
+ logger.error(`[xl1-to-eth-parent] worker error: ${err.message}`);
987
1515
  });
988
- }, "createWorker");
1516
+ };
989
1517
  var Xl1ToEthBridgeParent = {
990
1518
  createWorker: createWorker8,
991
1519
  name: name8,
@@ -993,48 +1521,60 @@ var Xl1ToEthBridgeParent = {
993
1521
  };
994
1522
 
995
1523
  // src/services/queue/workers/Xl1TransactionMonitor.ts
996
- import { assertEx as assertEx18, isDefined as isDefined10, isNull as isNull3 } from "@xylabs/sdk-js";
1524
+ import {
1525
+ assertEx as assertEx20,
1526
+ isDefined as isDefined10,
1527
+ isNull as isNull3,
1528
+ spanAsync as spanAsync12
1529
+ } from "@xylabs/sdk-js";
997
1530
  import { PayloadBuilder as PayloadBuilder11 } from "@xyo-network/sdk-js";
998
- import { UnrecoverableError as UnrecoverableError2, Worker as Worker9 } from "bullmq";
1531
+ import { UnrecoverableError as UnrecoverableError3, Worker as Worker9 } from "bullmq";
999
1532
  var name9 = "Monitor Submitted XL1 Transaction";
1000
1533
  var queueName9 = "xl1-tx-monitor";
1001
- var createWorker9 = /* @__PURE__ */ __name((connection2, telemetry2, services) => {
1002
- const gateway = assertEx18(services?.gateway, () => "gateway service not provided");
1003
- const stateMap = assertEx18(services?.xl1TxStateMap, () => "xl1TxStateMap service not provided");
1004
- const viewer = assertEx18(gateway.connection.viewer, () => "viewer not defined on gateway");
1005
- const worker = new Worker9(queueName9, async (job) => {
1006
- const { tx } = job.data;
1007
- const hash = await PayloadBuilder11.hash(tx[0]);
1008
- const state = assertEx18(await stateMap.get(hash), () => `[${hash}] state not found`);
1009
- const submissionHash = assertEx18(state.submissionHash, () => `[${hash}] submissionHash not found`);
1010
- await job.log(`[${hash}] Checking for XL1 transaction inclusion on chain`);
1011
- const foundTx = await viewer.transaction.byHash(submissionHash);
1012
- if (isDefined10(foundTx) && !isNull3(foundTx)) {
1013
- await job.log(`[${hash}] Found transaction on chain`);
1014
- const submissionHash2 = await PayloadBuilder11.hash(foundTx[0]);
1015
- return {
1016
- submissionHash: submissionHash2
1017
- };
1018
- }
1019
- const currentBlockNumber = await viewer.currentBlockNumber();
1020
- if (tx[0].exp < currentBlockNumber) {
1021
- await job.log(`[${hash}] Transaction expired at block ${tx[0].exp}, current block ${currentBlockNumber}`);
1022
- throw new UnrecoverableError2(`[${hash}] Transaction expired and will never be included`);
1534
+ var createWorker9 = (connection2, telemetry2, services) => {
1535
+ const gateway = assertEx20(services?.gateway, () => "gateway service not provided");
1536
+ const stateMap = assertEx20(services?.xl1TxStateMap, () => "xl1TxStateMap service not provided");
1537
+ const viewer = assertEx20(gateway.connection.viewer, () => "viewer not defined on gateway");
1538
+ const logger = assertEx20(services?.logger, () => "logger service not provided");
1539
+ const worker = new Worker9(
1540
+ queueName9,
1541
+ async (job) => {
1542
+ return await spanAsync12("bridge:worker:xl1-tx-monitor", async () => {
1543
+ const { tx } = job.data;
1544
+ const hash = await PayloadBuilder11.hash(tx[0]);
1545
+ const state = assertEx20(await stateMap.get(hash), () => `[${hash}] state not found`);
1546
+ const submissionHash = assertEx20(state.submissionHash, () => `[${hash}] submissionHash not found`);
1547
+ await job.log(`[${hash}] Checking for XL1 transaction inclusion on chain`);
1548
+ const foundTx = await viewer.transaction.byHash(submissionHash);
1549
+ if (isDefined10(foundTx) && !isNull3(foundTx)) {
1550
+ await job.log(`[${hash}] Found transaction on chain`);
1551
+ const submissionHash2 = await PayloadBuilder11.hash(foundTx[0]);
1552
+ return { submissionHash: submissionHash2 };
1553
+ }
1554
+ const currentBlockNumber = await viewer.currentBlockNumber();
1555
+ if (tx[0].exp < currentBlockNumber) {
1556
+ await job.log(
1557
+ `[${hash}] Transaction expired at block ${tx[0].exp}, current block ${currentBlockNumber}`
1558
+ );
1559
+ throw new UnrecoverableError3(`[${hash}] Transaction expired and will never be included`);
1560
+ }
1561
+ await job.log(`[${hash}] Transaction not yet included, retrying later`);
1562
+ throw new Error(`[${hash}] Transaction not yet included`);
1563
+ }, { logger, timeBudgetLimit: 2e3 });
1564
+ },
1565
+ {
1566
+ connection: connection2,
1567
+ telemetry: telemetry2,
1568
+ prefix
1023
1569
  }
1024
- await job.log(`[${hash}] Transaction not yet included, retrying later`);
1025
- throw new Error(`[${hash}] Transaction not yet included`);
1026
- }, {
1027
- connection: connection2,
1028
- telemetry: telemetry2,
1029
- prefix
1030
- });
1570
+ );
1031
1571
  worker.on("failed", (job, err) => {
1032
- console.error(`[${name9}] Job ${job?.id} failed:`, err.message);
1572
+ logger.error(`[xl1-monitor] job ${job?.id} failed: ${err.message}`);
1033
1573
  });
1034
1574
  worker.on("error", (err) => {
1035
- console.error(`[${name9}] Worker error:`, err);
1575
+ logger.error(`[xl1-monitor] worker error: ${err.message}`);
1036
1576
  });
1037
- }, "createWorker");
1577
+ };
1038
1578
  var Xl1TransactionMonitor = {
1039
1579
  createWorker: createWorker9,
1040
1580
  name: name9,
@@ -1042,40 +1582,42 @@ var Xl1TransactionMonitor = {
1042
1582
  };
1043
1583
 
1044
1584
  // src/services/queue/workers/Xl1TransactionPreparation.ts
1045
- import { assertEx as assertEx19 } from "@xylabs/sdk-js";
1585
+ import { assertEx as assertEx21, spanAsync as spanAsync13 } from "@xylabs/sdk-js";
1046
1586
  import { PayloadBuilder as PayloadBuilder12 } from "@xyo-network/sdk-js";
1047
1587
  import { Worker as Worker10 } from "bullmq";
1048
1588
  var name10 = "Prepare XL1 Transaction";
1049
1589
  var queueName10 = "xl1-tx-prepare";
1050
- var createWorker10 = /* @__PURE__ */ __name((connection2, telemetry2, services) => {
1051
- const stateMap = assertEx19(services?.xl1TxStateMap, () => "xl1TxStateMap service not provided");
1052
- const worker = new Worker10(queueName10, async (job) => {
1053
- const { tx, offChainPayloads = [] } = job.data;
1054
- const hash = await PayloadBuilder12.hash(tx[0]);
1055
- await job.log(`[${hash}] preparing XL1 transaction`);
1056
- const preparedTx = tx;
1057
- await job.log(`[${hash}] storing XL1 preparedTx`);
1058
- await stateMap.set(hash, {
1059
- offChainPayloads,
1060
- preparedTx
1061
- });
1062
- await job.log(`[${hash}] stored XL1 preparedTx`);
1063
- await job.log(`[${hash}] prepared XL1 transaction`);
1064
- return {
1065
- preparedTx
1066
- };
1067
- }, {
1068
- connection: connection2,
1069
- telemetry: telemetry2,
1070
- prefix
1071
- });
1590
+ var createWorker10 = (connection2, telemetry2, services) => {
1591
+ const stateMap = assertEx21(services?.xl1TxStateMap, () => "xl1TxStateMap service not provided");
1592
+ const logger = assertEx21(services?.logger, () => "logger service not provided");
1593
+ const worker = new Worker10(
1594
+ queueName10,
1595
+ async (job) => {
1596
+ return await spanAsync13("bridge:worker:xl1-tx-prepare", async () => {
1597
+ const { tx, offChainPayloads = [] } = job.data;
1598
+ const hash = await PayloadBuilder12.hash(tx[0]);
1599
+ await job.log(`[${hash}] preparing XL1 transaction`);
1600
+ const preparedTx = tx;
1601
+ await job.log(`[${hash}] storing XL1 preparedTx`);
1602
+ await stateMap.set(hash, { offChainPayloads, preparedTx });
1603
+ await job.log(`[${hash}] stored XL1 preparedTx`);
1604
+ await job.log(`[${hash}] prepared XL1 transaction`);
1605
+ return { preparedTx };
1606
+ }, { logger, timeBudgetLimit: 1e3 });
1607
+ },
1608
+ {
1609
+ connection: connection2,
1610
+ telemetry: telemetry2,
1611
+ prefix
1612
+ }
1613
+ );
1072
1614
  worker.on("failed", (job, err) => {
1073
- console.error(`[${name10}] Job ${job?.id} failed:`, err.message);
1615
+ logger.error(`[xl1-prep] job ${job?.id} failed: ${err.message}`);
1074
1616
  });
1075
1617
  worker.on("error", (err) => {
1076
- console.error(`[${name10}] Worker error:`, err);
1618
+ logger.error(`[xl1-prep] worker error: ${err.message}`);
1077
1619
  });
1078
- }, "createWorker");
1620
+ };
1079
1621
  var Xl1TransactionPreparation = {
1080
1622
  createWorker: createWorker10,
1081
1623
  name: name10,
@@ -1083,44 +1625,55 @@ var Xl1TransactionPreparation = {
1083
1625
  };
1084
1626
 
1085
1627
  // src/services/queue/workers/Xl1TransactionSubmission.ts
1086
- import { assertEx as assertEx20, isDefined as isDefined11 } from "@xylabs/sdk-js";
1628
+ import {
1629
+ assertEx as assertEx22,
1630
+ isDefined as isDefined11,
1631
+ spanAsync as spanAsync14
1632
+ } from "@xylabs/sdk-js";
1087
1633
  import { PayloadBuilder as PayloadBuilder13 } from "@xyo-network/sdk-js";
1088
1634
  import { Worker as Worker11 } from "bullmq";
1089
1635
  var name11 = "Submit XL1 Transaction";
1090
1636
  var queueName11 = "xl1-tx-submit";
1091
- var createWorker11 = /* @__PURE__ */ __name((connection2, telemetry2, services) => {
1092
- const gateway = assertEx20(services?.gateway, () => "gateway service not provided");
1093
- const stateMap = assertEx20(services?.xl1TxStateMap, () => "xl1TxStateMap service not provided");
1094
- const worker = new Worker11(queueName11, async (job) => {
1095
- const { tx } = job.data;
1096
- const hash = await PayloadBuilder13.hash(tx[0]);
1097
- const state = assertEx20(await stateMap.get(hash), () => `[${hash}] state not found`);
1098
- const { preparedTx, offChainPayloads = [], submissionHash: existingSubmissionHash } = state;
1099
- if (isDefined11(existingSubmissionHash)) {
1100
- await job.log(`[${hash}] Tx already submitted with submission response hash ${existingSubmissionHash}`);
1101
- return {
1102
- submissionHash: existingSubmissionHash
1103
- };
1637
+ var createWorker11 = (connection2, telemetry2, services) => {
1638
+ const gateway = assertEx22(services?.gateway, () => "gateway service not provided");
1639
+ const stateMap = assertEx22(services?.xl1TxStateMap, () => "xl1TxStateMap service not provided");
1640
+ const logger = assertEx22(services?.logger, () => "logger service not provided");
1641
+ const worker = new Worker11(
1642
+ queueName11,
1643
+ async (job) => {
1644
+ return await spanAsync14("bridge:worker:xl1-tx-submit", async () => {
1645
+ const { tx } = job.data;
1646
+ const hash = await PayloadBuilder13.hash(tx[0]);
1647
+ const state = assertEx22(await stateMap.get(hash), () => `[${hash}] state not found`);
1648
+ const {
1649
+ preparedTx,
1650
+ offChainPayloads = [],
1651
+ submissionHash: existingSubmissionHash
1652
+ } = state;
1653
+ if (isDefined11(existingSubmissionHash)) {
1654
+ await job.log(`[${hash}] Tx already submitted with submission response hash ${existingSubmissionHash}`);
1655
+ return { submissionHash: existingSubmissionHash };
1656
+ }
1657
+ const txToSubmit = assertEx22(preparedTx, () => `[${hash}] preparedTx not found`);
1658
+ await job.log(`[${hash}] Submitting XL1 tx`);
1659
+ const [submissionHash] = await submitXl1Transaction(txToSubmit, offChainPayloads, gateway);
1660
+ await job.log(`[${hash}] Submitted XL1 tx`);
1661
+ return { submissionHash };
1662
+ }, { logger, timeBudgetLimit: 5e3 });
1663
+ },
1664
+ {
1665
+ connection: connection2,
1666
+ telemetry: telemetry2,
1667
+ prefix
1104
1668
  }
1105
- const txToSubmit = assertEx20(preparedTx, () => `[${hash}] preparedTx not found`);
1106
- await job.log(`[${hash}] Submitting XL1 tx`);
1107
- const [submissionHash] = await submitXl1Transaction(txToSubmit, offChainPayloads, gateway);
1108
- await job.log(`[${hash}] Submitted XL1 tx`);
1109
- return {
1110
- submissionHash
1111
- };
1112
- }, {
1113
- connection: connection2,
1114
- telemetry: telemetry2,
1115
- prefix
1116
- });
1669
+ );
1117
1670
  worker.on("failed", (job, err) => {
1118
- console.error(`[${name11}] Job ${job?.id} failed:`, err.message);
1671
+ logger.error(`[xl1-submit] job ${job?.id} failed: ${err.message}`);
1119
1672
  });
1120
1673
  worker.on("error", (err) => {
1121
- console.error(`[${name11}] Worker error:`, err);
1674
+ logger.error(`[xl1-submit] worker error: ${err.message}`);
1122
1675
  });
1123
- }, "createWorker");
1676
+ };
1124
1677
  var Xl1TransactionSubmission = {
1125
1678
  createWorker: createWorker11,
1126
1679
  name: name11,
@@ -1128,48 +1681,55 @@ var Xl1TransactionSubmission = {
1128
1681
  };
1129
1682
 
1130
1683
  // src/services/queue/workers/Xl1TransactionSubmissionStorage.ts
1131
- import { assertEx as assertEx21, isDefined as isDefined12 } from "@xylabs/sdk-js";
1684
+ import {
1685
+ assertEx as assertEx23,
1686
+ isDefined as isDefined12,
1687
+ spanAsync as spanAsync15
1688
+ } from "@xylabs/sdk-js";
1132
1689
  import { PayloadBuilder as PayloadBuilder14 } from "@xyo-network/sdk-js";
1133
1690
  import { Worker as Worker12 } from "bullmq";
1134
1691
  var name12 = "Store XL1 Transaction Submission";
1135
1692
  var queueName12 = "xl1-tx-store-submission";
1136
- var createWorker12 = /* @__PURE__ */ __name((connection2, telemetry2, services) => {
1137
- const stateMap = assertEx21(services?.xl1TxStateMap, () => "xl1TxStateMap service not provided");
1138
- const worker = new Worker12(queueName12, async (job) => {
1139
- const { tx } = job.data;
1140
- const hash = await PayloadBuilder14.hash(tx[0]);
1141
- const state = assertEx21(await stateMap.get(hash), () => `[${hash}] state not found`);
1142
- const { submissionHash: existingSubmissionHash } = state;
1143
- if (isDefined12(existingSubmissionHash)) {
1144
- await job.log(`[${hash}] submissionHash already stored as ${existingSubmissionHash}`);
1145
- return {
1146
- submissionHash: existingSubmissionHash
1147
- };
1693
+ var createWorker12 = (connection2, telemetry2, services) => {
1694
+ const stateMap = assertEx23(services?.xl1TxStateMap, () => "xl1TxStateMap service not provided");
1695
+ const logger = assertEx23(services?.logger, () => "logger service not provided");
1696
+ const worker = new Worker12(
1697
+ queueName12,
1698
+ async (job) => {
1699
+ return await spanAsync15("bridge:worker:xl1-tx-store-submission", async () => {
1700
+ const { tx } = job.data;
1701
+ const hash = await PayloadBuilder14.hash(tx[0]);
1702
+ const state = assertEx23(await stateMap.get(hash), () => `[${hash}] state not found`);
1703
+ const { submissionHash: existingSubmissionHash } = state;
1704
+ if (isDefined12(existingSubmissionHash)) {
1705
+ await job.log(`[${hash}] submissionHash already stored as ${existingSubmissionHash}`);
1706
+ return { submissionHash: existingSubmissionHash };
1707
+ }
1708
+ const childrenValues = await job.getChildrenValues();
1709
+ const jobKey = `${prefix}:${Xl1TransactionSubmission.queueName}:${hash}`;
1710
+ const childValues = childrenValues?.[jobKey];
1711
+ const submissionHash = childValues?.submissionHash;
1712
+ const resolvedSubmissionHash = assertEx23(submissionHash, () => `[${hash}] child submissionHash not found in children values`);
1713
+ await job.log(`[${hash}] Storing XL1 submissionHash`);
1714
+ state.submissionHash = resolvedSubmissionHash;
1715
+ await stateMap.set(hash, state);
1716
+ await job.log(`[${hash}] Stored XL1 submissionHash`);
1717
+ return { submissionHash: resolvedSubmissionHash };
1718
+ }, { logger, timeBudgetLimit: 500 });
1719
+ },
1720
+ {
1721
+ connection: connection2,
1722
+ telemetry: telemetry2,
1723
+ prefix
1148
1724
  }
1149
- const childrenValues = await job.getChildrenValues();
1150
- const jobKey = `${prefix}:${Xl1TransactionSubmission.queueName}:${hash}`;
1151
- const childValues = childrenValues?.[jobKey];
1152
- const submissionHash = childValues?.submissionHash;
1153
- const resolvedSubmissionHash = assertEx21(submissionHash, () => `[${hash}] child submissionHash not found in children values`);
1154
- await job.log(`[${hash}] Storing XL1 submissionHash`);
1155
- state.submissionHash = resolvedSubmissionHash;
1156
- await stateMap.set(hash, state);
1157
- await job.log(`[${hash}] Stored XL1 submissionHash`);
1158
- return {
1159
- submissionHash: resolvedSubmissionHash
1160
- };
1161
- }, {
1162
- connection: connection2,
1163
- telemetry: telemetry2,
1164
- prefix
1165
- });
1725
+ );
1166
1726
  worker.on("failed", (job, err) => {
1167
- console.error(`[${name12}] Job ${job?.id} failed:`, err.message);
1727
+ logger.error(`[xl1-submit-store] job ${job?.id} failed: ${err.message}`);
1168
1728
  });
1169
1729
  worker.on("error", (err) => {
1170
- console.error(`[${name12}] Worker error:`, err);
1730
+ logger.error(`[xl1-submit-store] worker error: ${err.message}`);
1171
1731
  });
1172
- }, "createWorker");
1732
+ };
1173
1733
  var Xl1TransactionSubmissionStorage = {
1174
1734
  createWorker: createWorker12,
1175
1735
  name: name12,
@@ -1177,26 +1737,26 @@ var Xl1TransactionSubmissionStorage = {
1177
1737
  };
1178
1738
 
1179
1739
  // src/services/queue/workers/createWorkers.ts
1180
- var createWorkers = /* @__PURE__ */ __name((connection2, telemetry2, services) => {
1740
+ var createWorkers = (connection2, telemetry2, services) => {
1181
1741
  EthEventVerification.createWorker(connection2, telemetry2, services);
1182
- EthToXl1BridgeParent.createWorker(connection2, telemetry2);
1742
+ EthToXl1BridgeParent.createWorker(connection2, telemetry2, services);
1183
1743
  EthTransactionMonitor.createWorker(connection2, telemetry2, services);
1184
1744
  EthTransactionPreparation.createWorker(connection2, telemetry2, services);
1185
1745
  EthTransactionSubmission.createWorker(connection2, telemetry2, services);
1186
1746
  EthTransactionSubmissionStorage.createWorker(connection2, telemetry2, services);
1187
1747
  Xl1ReserveTxFulfillment.createWorker(connection2, telemetry2, services);
1188
- Xl1ToEthBridgeParent.createWorker(connection2, telemetry2);
1748
+ Xl1ToEthBridgeParent.createWorker(connection2, telemetry2, services);
1189
1749
  Xl1TransactionMonitor.createWorker(connection2, telemetry2, services);
1190
1750
  Xl1TransactionPreparation.createWorker(connection2, telemetry2, services);
1191
1751
  Xl1TransactionSubmission.createWorker(connection2, telemetry2, services);
1192
1752
  Xl1TransactionSubmissionStorage.createWorker(connection2, telemetry2, services);
1193
- }, "createWorkers");
1753
+ };
1194
1754
 
1195
1755
  // src/services/queue/flows/createEthToXl1BridgeJob/getJobIdForEthToXl1BridgeJob.ts
1756
+ import { buildBridgeIdentity } from "@xyo-network/chain-bridge-shared";
1196
1757
  function getJobIdForEthToXl1BridgeJob(context) {
1197
- return `evm:${context.evmChainId.toLowerCase()}:${context.contractAddress.toLowerCase()}:${context.bridgeId.toString()}`;
1758
+ return buildBridgeIdentity(context);
1198
1759
  }
1199
- __name(getJobIdForEthToXl1BridgeJob, "getJobIdForEthToXl1BridgeJob");
1200
1760
 
1201
1761
  // src/services/queue/flows/createEthToXl1BridgeJob/createEthToXl1BridgeJob.ts
1202
1762
  var STAGE_2_RETRY = {
@@ -1206,10 +1766,8 @@ var STAGE_2_RETRY = {
1206
1766
  type: "fixed"
1207
1767
  }
1208
1768
  };
1209
- var STAGE_1_RETRY = {
1210
- attempts: 1
1211
- };
1212
- var createEthToXl1BridgeJob = /* @__PURE__ */ __name(async (flowProducer2, context) => {
1769
+ var STAGE_1_RETRY = { attempts: 1 };
1770
+ var createEthToXl1BridgeJob = async (flowProducer2, context) => {
1213
1771
  const jobId = getJobIdForEthToXl1BridgeJob(context);
1214
1772
  const identity = jobId;
1215
1773
  const stageJobData = {
@@ -1224,175 +1782,121 @@ var createEthToXl1BridgeJob = /* @__PURE__ */ __name(async (flowProducer2, conte
1224
1782
  name: EthToXl1BridgeParent.name,
1225
1783
  queueName: EthToXl1BridgeParent.queueName,
1226
1784
  data: stageJobData,
1227
- opts: {
1228
- jobId
1229
- },
1785
+ opts: { jobId },
1230
1786
  children: [
1231
1787
  {
1232
1788
  name: Xl1ReserveTxFulfillment.name,
1233
1789
  queueName: Xl1ReserveTxFulfillment.queueName,
1234
1790
  data: stageJobData,
1235
- opts: {
1236
- jobId,
1237
- ...STAGE_2_RETRY
1238
- },
1791
+ opts: { jobId, ...STAGE_2_RETRY },
1239
1792
  children: [
1240
1793
  {
1241
1794
  name: EthEventVerification.name,
1242
1795
  queueName: EthEventVerification.queueName,
1243
1796
  data: stageJobData,
1244
- opts: {
1245
- jobId,
1246
- ...STAGE_1_RETRY
1247
- }
1797
+ opts: { jobId, ...STAGE_1_RETRY }
1248
1798
  }
1249
1799
  ]
1250
1800
  }
1251
1801
  ]
1252
1802
  });
1253
- }, "createEthToXl1BridgeJob");
1803
+ };
1254
1804
 
1255
1805
  // src/services/queue/flows/createXl1ToEthBridgeJob/getJobIdForXl1ToEthBridgeJob.ts
1256
1806
  import { PayloadBuilder as PayloadBuilder15 } from "@xyo-network/sdk-js";
1257
- var getJobIdForXl1ToEthBridgeJob = /* @__PURE__ */ __name(async (tx) => {
1807
+ var getJobIdForXl1ToEthBridgeJob = async (tx) => {
1258
1808
  const jobId = await PayloadBuilder15.hash(tx[0]);
1259
1809
  return jobId;
1260
- }, "getJobIdForXl1ToEthBridgeJob");
1810
+ };
1261
1811
 
1262
1812
  // src/services/queue/flows/createXl1ToEthBridgeJob/createXl1ToEthBridgeJob.ts
1263
- var createXl1ToEthBridgeJob = /* @__PURE__ */ __name(async (flowProducer2, tx, offChainPayloads = []) => {
1813
+ var createXl1ToEthBridgeJob = async (flowProducer2, tx, offChainPayloads = []) => {
1264
1814
  const jobId = await getJobIdForXl1ToEthBridgeJob(tx);
1265
1815
  const flow = await flowProducer2.add({
1266
1816
  // Step 0 (runs first as parent job)
1267
1817
  name: Xl1ToEthBridgeParent.name,
1268
1818
  queueName: Xl1ToEthBridgeParent.queueName,
1269
- data: {
1270
- tx,
1271
- offChainPayloads
1272
- },
1273
- opts: {
1274
- jobId
1275
- },
1819
+ data: { tx, offChainPayloads },
1820
+ opts: { jobId },
1276
1821
  children: [
1277
1822
  {
1278
1823
  // Step 8
1279
1824
  name: EthTransactionMonitor.name,
1280
1825
  queueName: EthTransactionMonitor.queueName,
1281
- data: {
1282
- tx
1283
- },
1826
+ data: { tx },
1284
1827
  opts: {
1285
1828
  jobId,
1286
1829
  attempts: 60,
1287
- backoff: {
1288
- type: "fixed",
1289
- delay: 5e3
1290
- }
1830
+ backoff: { type: "fixed", delay: 5e3 }
1291
1831
  },
1292
1832
  children: [
1293
1833
  {
1294
1834
  // Step 7
1295
1835
  name: EthTransactionSubmissionStorage.name,
1296
1836
  queueName: EthTransactionSubmissionStorage.queueName,
1297
- data: {
1298
- tx
1299
- },
1837
+ data: { tx },
1300
1838
  opts: {
1301
1839
  jobId,
1302
1840
  attempts: 60,
1303
- backoff: {
1304
- type: "fixed",
1305
- delay: 5e3
1306
- }
1841
+ backoff: { type: "fixed", delay: 5e3 }
1307
1842
  },
1308
1843
  children: [
1309
1844
  {
1310
1845
  // Step 6
1311
1846
  name: EthTransactionSubmission.name,
1312
1847
  queueName: EthTransactionSubmission.queueName,
1313
- data: {
1314
- tx,
1315
- offChainPayloads
1316
- },
1317
- opts: {
1318
- jobId
1319
- },
1848
+ data: { tx, offChainPayloads },
1849
+ opts: { jobId },
1320
1850
  children: [
1321
1851
  {
1322
1852
  // Step 5
1323
1853
  name: EthTransactionPreparation.name,
1324
1854
  queueName: EthTransactionPreparation.queueName,
1325
- data: {
1326
- tx,
1327
- offChainPayloads
1328
- },
1855
+ data: { tx, offChainPayloads },
1329
1856
  opts: {
1330
1857
  jobId,
1331
1858
  attempts: 60,
1332
- backoff: {
1333
- type: "fixed",
1334
- delay: 5e3
1335
- }
1859
+ backoff: { type: "fixed", delay: 5e3 }
1336
1860
  },
1337
1861
  children: [
1338
1862
  {
1339
1863
  // Step 4
1340
1864
  name: Xl1TransactionMonitor.name,
1341
1865
  queueName: Xl1TransactionMonitor.queueName,
1342
- data: {
1343
- tx
1344
- },
1866
+ data: { tx },
1345
1867
  opts: {
1346
1868
  jobId,
1347
1869
  attempts: 60,
1348
- backoff: {
1349
- type: "fixed",
1350
- delay: 5e3
1351
- }
1870
+ backoff: { type: "fixed", delay: 5e3 }
1352
1871
  },
1353
1872
  children: [
1354
1873
  {
1355
1874
  // Step 3
1356
1875
  name: Xl1TransactionSubmissionStorage.name,
1357
1876
  queueName: Xl1TransactionSubmissionStorage.queueName,
1358
- data: {
1359
- tx
1360
- },
1877
+ data: { tx },
1361
1878
  opts: {
1362
1879
  jobId,
1363
1880
  attempts: 60,
1364
- backoff: {
1365
- type: "fixed",
1366
- delay: 5e3
1367
- }
1881
+ backoff: { type: "fixed", delay: 5e3 }
1368
1882
  },
1369
1883
  children: [
1370
1884
  {
1371
1885
  // Step 2
1372
1886
  name: Xl1TransactionSubmission.name,
1373
1887
  queueName: Xl1TransactionSubmission.queueName,
1374
- data: {
1375
- tx
1376
- },
1377
- opts: {
1378
- jobId
1379
- },
1888
+ data: { tx },
1889
+ opts: { jobId },
1380
1890
  children: [
1381
1891
  {
1382
1892
  // Step 1 (runs first as deepest child)
1383
1893
  name: Xl1TransactionPreparation.name,
1384
1894
  queueName: Xl1TransactionPreparation.queueName,
1385
- data: {
1386
- tx,
1387
- offChainPayloads
1388
- },
1895
+ data: { tx, offChainPayloads },
1389
1896
  opts: {
1390
1897
  jobId,
1391
1898
  attempts: 60,
1392
- backoff: {
1393
- type: "fixed",
1394
- delay: 5e3
1395
- }
1899
+ backoff: { type: "fixed", delay: 5e3 }
1396
1900
  }
1397
1901
  }
1398
1902
  ]
@@ -1412,44 +1916,41 @@ var createXl1ToEthBridgeJob = /* @__PURE__ */ __name(async (flowProducer2, tx, o
1412
1916
  ]
1413
1917
  });
1414
1918
  return flow;
1415
- }, "createXl1ToEthBridgeJob");
1919
+ };
1416
1920
 
1417
1921
  // src/services/queue/flows/createXl1ToEthBridgeJob/getXl1ToEthBridgeJob.ts
1418
- var getXl1ToEthBridgeJob = /* @__PURE__ */ __name(async (flowProducer2, tx) => {
1922
+ var getXl1ToEthBridgeJob = async (flowProducer2, tx) => {
1419
1923
  const id = await getJobIdForXl1ToEthBridgeJob(tx);
1420
- const flow = await flowProducer2.getFlow({
1421
- queueName: Xl1ToEthBridgeParent.queueName,
1422
- id
1423
- });
1924
+ const flow = await flowProducer2.getFlow({ queueName: Xl1ToEthBridgeParent.queueName, id });
1424
1925
  return flow;
1425
- }, "getXl1ToEthBridgeJob");
1926
+ };
1426
1927
 
1427
1928
  // src/services/queue/getEthToXl1Queues.ts
1428
1929
  import { Queue } from "bullmq";
1429
1930
  var ethToXl1Queues;
1430
- var getEthToXl1Queues = /* @__PURE__ */ __name((config) => {
1931
+ var getEthToXl1Queues = (config) => {
1431
1932
  if (ethToXl1Queues) return ethToXl1Queues;
1432
1933
  const connection2 = getConnection(config);
1433
1934
  ethToXl1Queues = {
1434
- ethEventVerification: new Queue(EthEventVerification.queueName, {
1435
- connection: connection2,
1436
- prefix
1437
- }),
1438
- ethToXl1BridgeParent: new Queue(EthToXl1BridgeParent.queueName, {
1439
- connection: connection2,
1440
- prefix
1441
- }),
1442
- xl1ReserveTxFulfillment: new Queue(Xl1ReserveTxFulfillment.queueName, {
1443
- connection: connection2,
1444
- prefix
1445
- })
1935
+ ethEventVerification: new Queue(EthEventVerification.queueName, { connection: connection2, prefix }),
1936
+ ethToXl1BridgeParent: new Queue(EthToXl1BridgeParent.queueName, { connection: connection2, prefix }),
1937
+ xl1ReserveTxFulfillment: new Queue(Xl1ReserveTxFulfillment.queueName, { connection: connection2, prefix })
1446
1938
  };
1447
1939
  return ethToXl1Queues;
1448
- }, "getEthToXl1Queues");
1940
+ };
1449
1941
 
1450
1942
  // src/services/queue/getXl1ToEthQueueJobs.ts
1451
- var getStatusQueueJobs = /* @__PURE__ */ __name(async (queues, jobId) => {
1452
- const [ethTransactionMonitorJob, ethTransactionPreparationJob, ethTransactionSubmissionJob, xl1ToEthBridgeParentJob, xl1TransactionMonitorJob, xl1TransactionPreparationJob, xl1TransactionSubmissionJob, xl1TransactionSubmissionStorageJob] = await Promise.all([
1943
+ var getStatusQueueJobs = async (queues, jobId) => {
1944
+ const [
1945
+ ethTransactionMonitorJob,
1946
+ ethTransactionPreparationJob,
1947
+ ethTransactionSubmissionJob,
1948
+ xl1ToEthBridgeParentJob,
1949
+ xl1TransactionMonitorJob,
1950
+ xl1TransactionPreparationJob,
1951
+ xl1TransactionSubmissionJob,
1952
+ xl1TransactionSubmissionStorageJob
1953
+ ] = await Promise.all([
1453
1954
  queues.ethTransactionMonitor.getJob(jobId),
1454
1955
  queues.ethTransactionPreparation.getJob(jobId),
1455
1956
  queues.ethTransactionSubmission.getJob(jobId),
@@ -1469,54 +1970,137 @@ var getStatusQueueJobs = /* @__PURE__ */ __name(async (queues, jobId) => {
1469
1970
  xl1TransactionSubmissionStorageJob,
1470
1971
  xl1TransactionSubmissionJob
1471
1972
  };
1472
- }, "getStatusQueueJobs");
1973
+ };
1473
1974
 
1474
1975
  // src/services/queue/getXl1ToEthQueues.ts
1475
1976
  import { Queue as Queue2 } from "bullmq";
1476
1977
  var xl1ToEthQueues;
1477
- var getXl1ToEthQueues = /* @__PURE__ */ __name((config) => {
1978
+ var getXl1ToEthQueues = (config) => {
1478
1979
  if (xl1ToEthQueues) return xl1ToEthQueues;
1479
1980
  const connection2 = getConnection(config);
1480
1981
  xl1ToEthQueues = {
1481
- ethTransactionMonitor: new Queue2(EthTransactionMonitor.queueName, {
1482
- connection: connection2,
1483
- prefix
1484
- }),
1485
- ethTransactionPreparation: new Queue2(EthTransactionPreparation.queueName, {
1486
- connection: connection2,
1487
- prefix
1488
- }),
1489
- ethTransactionSubmission: new Queue2(EthTransactionSubmission.queueName, {
1490
- connection: connection2,
1491
- prefix
1492
- }),
1493
- xl1ToEthBridgeParent: new Queue2(Xl1ToEthBridgeParent.queueName, {
1494
- connection: connection2,
1495
- prefix
1496
- }),
1497
- xl1TransactionMonitor: new Queue2(Xl1TransactionMonitor.queueName, {
1498
- connection: connection2,
1499
- prefix
1500
- }),
1501
- xl1TransactionPreparation: new Queue2(Xl1TransactionPreparation.queueName, {
1502
- connection: connection2,
1503
- prefix
1504
- }),
1505
- xl1TransactionSubmission: new Queue2(Xl1TransactionSubmission.queueName, {
1506
- connection: connection2,
1507
- prefix
1508
- }),
1509
- xl1TransactionSubmissionStorage: new Queue2(Xl1TransactionSubmissionStorage.queueName, {
1510
- connection: connection2,
1511
- prefix
1512
- })
1982
+ ethTransactionMonitor: new Queue2(EthTransactionMonitor.queueName, { connection: connection2, prefix }),
1983
+ ethTransactionPreparation: new Queue2(EthTransactionPreparation.queueName, { connection: connection2, prefix }),
1984
+ ethTransactionSubmission: new Queue2(EthTransactionSubmission.queueName, { connection: connection2, prefix }),
1985
+ xl1ToEthBridgeParent: new Queue2(Xl1ToEthBridgeParent.queueName, { connection: connection2, prefix }),
1986
+ xl1TransactionMonitor: new Queue2(Xl1TransactionMonitor.queueName, { connection: connection2, prefix }),
1987
+ xl1TransactionPreparation: new Queue2(Xl1TransactionPreparation.queueName, { connection: connection2, prefix }),
1988
+ xl1TransactionSubmission: new Queue2(Xl1TransactionSubmission.queueName, { connection: connection2, prefix }),
1989
+ xl1TransactionSubmissionStorage: new Queue2(Xl1TransactionSubmissionStorage.queueName, { connection: connection2, prefix })
1513
1990
  };
1514
1991
  return xl1ToEthQueues;
1515
- }, "getXl1ToEthQueues");
1992
+ };
1993
+
1994
+ // src/services/queue/retryFailedJobs.ts
1995
+ var DEFAULT_LIMIT = 100;
1996
+ function hasAnyFilter(filters) {
1997
+ return filters.bridgeIds !== void 0 && filters.bridgeIds.length > 0 || filters.since !== void 0 || filters.until !== void 0 || filters.reasonContains !== void 0 || filters.srcAddress !== void 0;
1998
+ }
1999
+ var AVAILABLE_BULK_FILTERS = [
2000
+ "bridgeIds",
2001
+ "since",
2002
+ "until",
2003
+ "reasonContains",
2004
+ "srcAddress"
2005
+ ];
2006
+ async function isFilterMatch(job, id, filters, srcAddressLookup) {
2007
+ const {
2008
+ bridgeIds,
2009
+ reasonContains,
2010
+ since,
2011
+ srcAddress,
2012
+ until
2013
+ } = filters;
2014
+ if (bridgeIds !== void 0 && !bridgeIds.includes(id)) return false;
2015
+ if (since !== void 0 || until !== void 0) {
2016
+ const finishedOn = job.finishedOn;
2017
+ if (finishedOn === void 0) return false;
2018
+ if (since !== void 0 && finishedOn < since) return false;
2019
+ if (until !== void 0 && finishedOn > until) return false;
2020
+ }
2021
+ if (reasonContains !== void 0 && !(job.failedReason ?? "").includes(reasonContains)) {
2022
+ return false;
2023
+ }
2024
+ if (srcAddress !== void 0) {
2025
+ if (srcAddressLookup === void 0) return false;
2026
+ const found = await srcAddressLookup(id);
2027
+ if (found === void 0 || found.toLowerCase() !== srcAddress.toLowerCase()) return false;
2028
+ }
2029
+ return true;
2030
+ }
2031
+ async function retryFailedJobs(opts) {
2032
+ const {
2033
+ filters,
2034
+ queue,
2035
+ srcAddressLookup
2036
+ } = opts;
2037
+ const { dryRun = false, limit = DEFAULT_LIMIT } = filters;
2038
+ const failedJobs = await queue.getFailed(0, Math.max(limit - 1, 0));
2039
+ const retried = [];
2040
+ const skipped = [];
2041
+ for (const job of failedJobs) {
2042
+ const id = job.id;
2043
+ if (id === void 0) continue;
2044
+ const matches = await isFilterMatch(job, id, filters, srcAddressLookup);
2045
+ if (!matches) {
2046
+ skipped.push({ id, reason: "filter-mismatch" });
2047
+ continue;
2048
+ }
2049
+ const state = await job.getState();
2050
+ if (state !== "failed") {
2051
+ skipped.push({ id, reason: "not-in-failed-state" });
2052
+ continue;
2053
+ }
2054
+ if (!dryRun) await job.retry();
2055
+ retried.push({ failedReason: job.failedReason, id });
2056
+ }
2057
+ const total = retried.length + skipped.length;
2058
+ return {
2059
+ counts: {
2060
+ retried: retried.length,
2061
+ skipped: skipped.length,
2062
+ total
2063
+ },
2064
+ retried,
2065
+ skipped
2066
+ };
2067
+ }
2068
+
2069
+ // src/services/queue/retrySingleFailedJob.ts
2070
+ async function retrySingleFailedJob(opts) {
2071
+ const {
2072
+ dryRun = false,
2073
+ jobId,
2074
+ queue
2075
+ } = opts;
2076
+ const job = await queue.getJob(jobId);
2077
+ if (job === void 0) {
2078
+ return { bridgeId: jobId, status: "not-found" };
2079
+ }
2080
+ const state = await job.getState();
2081
+ if (state !== "failed") {
2082
+ return { bridgeId: jobId, status: "not-in-failed-state" };
2083
+ }
2084
+ const failedReason = job.failedReason;
2085
+ if (!dryRun) {
2086
+ await job.retry();
2087
+ }
2088
+ return {
2089
+ bridgeId: jobId,
2090
+ failedReason,
2091
+ status: "retried"
2092
+ };
2093
+ }
1516
2094
 
1517
2095
  // src/services/queue/scanner/createEnqueueEthToXl1Bridge.ts
1518
2096
  function createEnqueueEthToXl1Bridge(options2) {
1519
- const { evmChainId, evmContractAddress, flowProducer: flowProducer2, xl1ChainId, xl1TokenAddress } = options2;
2097
+ const {
2098
+ evmChainId,
2099
+ evmContractAddress,
2100
+ flowProducer: flowProducer2,
2101
+ xl1ChainId,
2102
+ xl1TokenAddress
2103
+ } = options2;
1520
2104
  return async (bridgeId, jobLog) => {
1521
2105
  await createEthToXl1BridgeJob(flowProducer2, {
1522
2106
  bridgeId,
@@ -1528,7 +2112,6 @@ function createEnqueueEthToXl1Bridge(options2) {
1528
2112
  await jobLog?.(`[bridge-scanner] bridgeId ${bridgeId} enqueued`);
1529
2113
  };
1530
2114
  }
1531
- __name(createEnqueueEthToXl1Bridge, "createEnqueueEthToXl1Bridge");
1532
2115
 
1533
2116
  // src/services/queue/scanner/EvmBridgeScanner.ts
1534
2117
  import { isUndefined as isUndefined2 } from "@xylabs/sdk-js";
@@ -1537,22 +2120,33 @@ import { isUndefined as isUndefined2 } from "@xylabs/sdk-js";
1537
2120
  function getEvmBridgeCursorKey(chainId, contractAddress) {
1538
2121
  return `${chainId.toLowerCase()}:${contractAddress.toLowerCase()}`;
1539
2122
  }
1540
- __name(getEvmBridgeCursorKey, "getEvmBridgeCursorKey");
1541
2123
 
1542
2124
  // src/services/queue/scanner/EvmBridgeScanner.ts
1543
2125
  function createEvmBridgeScanner(options2) {
1544
- const { bridge, bridgeAddress, chainId, confirmationDepth, cursors, enqueue, provider } = options2;
2126
+ const {
2127
+ bridge,
2128
+ bridgeAddress,
2129
+ chainId,
2130
+ confirmationDepth,
2131
+ cursors,
2132
+ deployBlock,
2133
+ enqueue,
2134
+ provider
2135
+ } = options2;
1545
2136
  const cursorKey = getEvmBridgeCursorKey(chainId, bridgeAddress);
1546
2137
  return {
1547
2138
  async scan(options3) {
1548
2139
  const jobLog = options3?.jobLog;
1549
- const blockTag = await resolveEvmBlockTagAtDepth(provider, confirmationDepth);
1550
- const confirmedHigh = await bridge.nextBridgeToId({
1551
- blockTag
1552
- });
2140
+ const blockTag = await resolveEvmBlockTagAtDepth(provider, confirmationDepth, deployBlock);
2141
+ const confirmedHigh = await bridge.nextBridgeToId({ blockTag });
1553
2142
  const cursor = await cursors.get(cursorKey);
1554
2143
  const lastProcessedId = isUndefined2(cursor) ? 0n : BigInt(cursor.lastProcessedId);
2144
+ const priorProcessedBlock = isUndefined2(cursor?.lastProcessedBlock) ? deployBlock : Number(cursor.lastProcessedBlock);
2145
+ const nextProcessedBlock = typeof blockTag === "number" ? Math.max(priorProcessedBlock, blockTag) : priorProcessedBlock;
1555
2146
  if (confirmedHigh <= lastProcessedId) {
2147
+ if (nextProcessedBlock !== priorProcessedBlock || isUndefined2(cursor)) {
2148
+ await cursors.set(cursorKey, { lastProcessedBlock: nextProcessedBlock.toString(), lastProcessedId: lastProcessedId.toString() });
2149
+ }
1556
2150
  return {
1557
2151
  confirmedHigh,
1558
2152
  enqueued: 0,
@@ -1564,9 +2158,7 @@ function createEvmBridgeScanner(options2) {
1564
2158
  await enqueue(id, jobLog);
1565
2159
  enqueued++;
1566
2160
  }
1567
- await cursors.set(cursorKey, {
1568
- lastProcessedId: confirmedHigh.toString()
1569
- });
2161
+ await cursors.set(cursorKey, { lastProcessedBlock: nextProcessedBlock.toString(), lastProcessedId: confirmedHigh.toString() });
1570
2162
  return {
1571
2163
  confirmedHigh,
1572
2164
  enqueued,
@@ -1575,16 +2167,21 @@ function createEvmBridgeScanner(options2) {
1575
2167
  }
1576
2168
  };
1577
2169
  }
1578
- __name(createEvmBridgeScanner, "createEvmBridgeScanner");
1579
2170
 
1580
2171
  // src/services/queue/scanner/EvmBridgeScannerRunner.ts
2172
+ import { spanAsync as spanAsync16 } from "@xylabs/sdk-js";
1581
2173
  import { Queue as Queue3, Worker as Worker13 } from "bullmq";
1582
2174
  var QUEUE_NAME = "eth-to-xl1-scanner";
1583
2175
  var REPEATABLE_JOB_NAME = "scan";
1584
2176
  var REPEATABLE_JOB_ID = "eth-to-xl1-scanner-tick";
1585
2177
  function createEvmBridgeScannerRunner(options2) {
1586
- const { connection: connection2, intervalMs, scanner, telemetry: telemetry2 } = options2;
1587
- const logger = options2.logger ?? console;
2178
+ const {
2179
+ connection: connection2,
2180
+ intervalMs,
2181
+ logger,
2182
+ scanner,
2183
+ telemetry: telemetry2
2184
+ } = options2;
1588
2185
  let queue;
1589
2186
  let worker;
1590
2187
  return {
@@ -1595,27 +2192,27 @@ function createEvmBridgeScannerRunner(options2) {
1595
2192
  telemetry: telemetry2
1596
2193
  });
1597
2194
  worker = new Worker13(QUEUE_NAME, async (job) => {
1598
- await job.log("[scanner] tick start");
1599
- const result = await scanner.scan({
1600
- jobLog: /* @__PURE__ */ __name((msg) => job.log(msg), "jobLog")
1601
- });
1602
- await job.log(`[scanner] tick complete: enqueued=${result.enqueued} confirmedHigh=${result.confirmedHigh.toString()} lastProcessedId=${result.lastProcessedId.toString()}`);
2195
+ await spanAsync16("bridge:scanner:tick", async () => {
2196
+ await job.log("[scanner] tick start");
2197
+ const result = await scanner.scan({ jobLog: (msg) => job.log(msg) });
2198
+ await job.log(
2199
+ `[scanner] tick complete: enqueued=${result.enqueued} confirmedHigh=${result.confirmedHigh.toString()} lastProcessedId=${result.lastProcessedId.toString()}`
2200
+ );
2201
+ }, { logger, timeBudgetLimit: 2e3 });
1603
2202
  }, {
1604
2203
  connection: connection2,
1605
2204
  prefix,
1606
2205
  telemetry: telemetry2
1607
2206
  });
1608
2207
  worker.on("failed", (job, err) => {
1609
- logger.error(`[scanner] tick ${job?.id} failed:`, err.message);
2208
+ logger.error(`[scanner] tick ${job?.id} failed: ${err.message}`);
1610
2209
  });
1611
2210
  worker.on("error", (err) => {
1612
- logger.error("[scanner] worker error:", err);
2211
+ logger.error(`[scanner] worker error: ${err.message}`);
1613
2212
  });
1614
2213
  await queue.add(REPEATABLE_JOB_NAME, {}, {
1615
2214
  jobId: REPEATABLE_JOB_ID,
1616
- repeat: {
1617
- every: intervalMs
1618
- }
2215
+ repeat: { every: intervalMs }
1619
2216
  });
1620
2217
  },
1621
2218
  async stop() {
@@ -1626,11 +2223,16 @@ function createEvmBridgeScannerRunner(options2) {
1626
2223
  }
1627
2224
  };
1628
2225
  }
1629
- __name(createEvmBridgeScannerRunner, "createEvmBridgeScannerRunner");
1630
2226
 
1631
2227
  // src/services/queue/scanner/buildEvmBridgeScannerRunner.ts
1632
2228
  function buildEvmBridgeScannerRunner(options2) {
1633
- const { config, connection: connection2, flowProducer: flowProducer2, logger, services, telemetry: telemetry2 } = options2;
2229
+ const {
2230
+ config,
2231
+ connection: connection2,
2232
+ flowProducer: flowProducer2,
2233
+ services,
2234
+ telemetry: telemetry2
2235
+ } = options2;
1634
2236
  const evmChainId = getRemoteChainId(config);
1635
2237
  const evmContractAddress = config.remoteBridgeContractAddress;
1636
2238
  const xl1ChainId = getXl1ChainId(config);
@@ -1649,111 +2251,106 @@ function buildEvmBridgeScannerRunner(options2) {
1649
2251
  chainId: evmChainId,
1650
2252
  confirmationDepth: services.remoteConfirmationDepth,
1651
2253
  cursors: services.evmBridgeCursorMap,
2254
+ deployBlock: services.evmBridgeDeployBlock,
1652
2255
  enqueue,
1653
2256
  provider: services.provider
1654
2257
  });
1655
2258
  return createEvmBridgeScannerRunner({
1656
2259
  connection: connection2,
1657
2260
  intervalMs,
1658
- logger,
2261
+ logger: services.logger,
1659
2262
  scanner,
1660
2263
  telemetry: telemetry2
1661
2264
  });
1662
2265
  }
1663
- __name(buildEvmBridgeScannerRunner, "buildEvmBridgeScannerRunner");
1664
2266
 
1665
2267
  // src/services/queue/telemetry.ts
1666
2268
  import { isDefined as isDefined13 } from "@xylabs/sdk-js";
1667
2269
  import { BullMQOtel } from "bullmq-otel";
1668
2270
  var telemetry;
1669
- var options = {
1670
- enableMetrics: true
1671
- };
1672
- var getTelemetry = /* @__PURE__ */ __name(() => {
2271
+ var options = { enableMetrics: true };
2272
+ var getTelemetry = () => {
1673
2273
  if (isDefined13(telemetry)) return telemetry;
1674
2274
  telemetry = new BullMQOtel(options);
1675
2275
  return telemetry;
1676
- }, "getTelemetry");
2276
+ };
1677
2277
 
1678
2278
  // src/server/addFlowProducer.ts
1679
- var addFlowProducer = /* @__PURE__ */ __name((app, config) => {
2279
+ var addFlowProducer = (app, config) => {
1680
2280
  const connection2 = getConnection(config);
1681
2281
  const telemetry2 = getTelemetry();
1682
2282
  const flowProducer2 = getFlowProducer(connection2, telemetry2);
1683
2283
  app.flowProducer = flowProducer2;
1684
2284
  return app;
1685
- }, "addFlowProducer");
2285
+ };
1686
2286
 
1687
2287
  // src/server/instrumentation.ts
1688
2288
  import { registerInstrumentations } from "@opentelemetry/instrumentation";
1689
2289
  import { ExpressInstrumentation } from "@opentelemetry/instrumentation-express";
1690
2290
  import { HttpInstrumentation } from "@opentelemetry/instrumentation-http";
1691
- var addInstrumentation = /* @__PURE__ */ __name(() => {
1692
- const instrumentations = [
1693
- new HttpInstrumentation(),
1694
- new ExpressInstrumentation()
1695
- ];
1696
- registerInstrumentations({
1697
- instrumentations
1698
- });
1699
- }, "addInstrumentation");
2291
+ var addInstrumentation = () => {
2292
+ const instrumentations = [new HttpInstrumentation(), new ExpressInstrumentation()];
2293
+ registerInstrumentations({ instrumentations });
2294
+ };
1700
2295
 
1701
2296
  // src/server/routes/livez/get.ts
1702
2297
  import { setRawResponseFormat } from "@xylabs/express";
1703
2298
  import { ReasonPhrases } from "http-status-codes";
1704
2299
  var message = ReasonPhrases.OK;
1705
- var handler = /* @__PURE__ */ __name((_req, res) => {
2300
+ var handler = (_req, res) => {
1706
2301
  setRawResponseFormat(res);
1707
- res.status(200).send({
1708
- message
1709
- });
1710
- }, "handler");
2302
+ res.status(200).send({ message });
2303
+ };
1711
2304
  var getLivez = handler;
1712
2305
 
1713
2306
  // src/server/routes/readyz/get.ts
1714
2307
  import { setRawResponseFormat as setRawResponseFormat2 } from "@xylabs/express";
1715
2308
  import { ReasonPhrases as ReasonPhrases2 } from "http-status-codes";
1716
2309
  var message2 = ReasonPhrases2.OK;
1717
- var handler2 = /* @__PURE__ */ __name((_req, res) => {
2310
+ var handler2 = (_req, res) => {
1718
2311
  setRawResponseFormat2(res);
1719
- res.status(200).send({
1720
- message: message2
1721
- });
1722
- }, "handler");
2312
+ res.status(200).send({ message: message2 });
2313
+ };
1723
2314
  var getReadyz = handler2;
1724
2315
 
1725
2316
  // src/server/routes/startupz/get.ts
1726
2317
  import { setRawResponseFormat as setRawResponseFormat3 } from "@xylabs/express";
1727
2318
  import { ReasonPhrases as ReasonPhrases3 } from "http-status-codes";
1728
2319
  var message3 = ReasonPhrases3.OK;
1729
- var handler3 = /* @__PURE__ */ __name((_req, res) => {
2320
+ var handler3 = (_req, res) => {
1730
2321
  setRawResponseFormat3(res);
1731
- res.status(200).send({
1732
- message: message3
1733
- });
1734
- }, "handler");
2322
+ res.status(200).send({ message: message3 });
2323
+ };
1735
2324
  var getStartupz = handler3;
1736
2325
 
1737
2326
  // src/server/routes/addProbeRoutes.ts
1738
- var addProbeRoutes = /* @__PURE__ */ __name((app) => {
2327
+ var addProbeRoutes = (app) => {
1739
2328
  app.get("/livez", getLivez);
1740
2329
  app.get("/readyz", getReadyz);
1741
2330
  app.get("/startupz", getStartupz);
1742
- }, "addProbeRoutes");
2331
+ };
1743
2332
 
1744
2333
  // src/server/routes/bridge/routeDefinitions/routes/bridgeConfig.ts
1745
2334
  import { requestHandlerValidator } from "@xylabs/express";
1746
- import { BridgeSettingsZod } from "@xyo-network/chain-orchestration";
1747
- var BridgeConfigResponseZod = BridgeSettingsZod;
1748
- var validateRequest = requestHandlerValidator({
1749
- response: BridgeConfigResponseZod
1750
- });
1751
- var makeBridgeConfigRoute = /* @__PURE__ */ __name((config) => {
2335
+ import { BridgeConfigResponseZod } from "@xyo-network/chain-bridge-shared";
2336
+ var validateRequest = requestHandlerValidator({ response: BridgeConfigResponseZod });
2337
+ var makeBridgeConfigRoute = (config) => {
1752
2338
  return {
1753
2339
  method: "get",
1754
2340
  path: "/bridge/chains/:chainId/config",
1755
2341
  handlers: validateRequest(async (_, res) => {
1756
- const { escrowAddress, feeFixed, feeRateBasisPoints, feesAddress, maxBridgeAmount, minBridgeAmount, remoteChainId, remoteTokenAddress, xl1ChainId, xl1TokenAddress } = await getBridgeSettings(config);
2342
+ const {
2343
+ escrowAddress,
2344
+ feeFixed,
2345
+ feeRateBasisPoints,
2346
+ feesAddress,
2347
+ maxBridgeAmount,
2348
+ minBridgeAmount,
2349
+ remoteChainId,
2350
+ remoteTokenAddress,
2351
+ xl1ChainId,
2352
+ xl1TokenAddress
2353
+ } = await getBridgeSettings(config);
1757
2354
  const sanitizedConfig = {
1758
2355
  escrowAddress,
1759
2356
  feeFixed,
@@ -1769,95 +2366,199 @@ var makeBridgeConfigRoute = /* @__PURE__ */ __name((config) => {
1769
2366
  res.json(sanitizedConfig);
1770
2367
  })
1771
2368
  };
1772
- }, "makeBridgeConfigRoute");
2369
+ };
1773
2370
 
1774
- // src/server/routes/bridge/routeDefinitions/routes/bridgeFromRemoteStatus.ts
2371
+ // src/server/routes/bridge/routeDefinitions/routes/bridgeFromRemoteEstimate.ts
1775
2372
  import { requestHandlerValidator as requestHandlerValidator2 } from "@xylabs/express";
1776
- import { isDefined as isDefined14, toHex as toHex4 } from "@xylabs/sdk-js";
1777
- import { PayloadZodStrictOfSchema } from "@xyo-network/sdk-js";
1778
- import { BridgeDestinationObservationFieldsZod, BridgeDestinationObservationSchema, BridgeIntentFieldsZod, BridgeIntentSchema as BridgeIntentSchema4, BridgeSourceObservationFieldsZod, BridgeSourceObservationSchema as BridgeSourceObservationSchema2 } from "@xyo-network/xl1-sdk";
1779
- import { z } from "zod";
2373
+ import {
2374
+ assertEx as assertEx24,
2375
+ hexToBigInt as hexToBigInt11,
2376
+ toAddress as toAddress2
2377
+ } from "@xylabs/sdk-js";
2378
+ import {
2379
+ BridgeFromRemoteEstimateBodyZod,
2380
+ BridgeFromRemoteEstimateResponseZod,
2381
+ buildEthToXl1BridgePayloads as buildEthToXl1BridgePayloads3,
2382
+ calculateBridgeFees as calculateBridgeFees3
2383
+ } from "@xyo-network/chain-bridge-shared";
2384
+ import { buildUnsignedTransaction, toXL1BlockNumber } from "@xyo-network/xl1-sdk";
2385
+ import { z as z2 } from "zod/mini";
1780
2386
 
1781
2387
  // src/server/routes/bridge/routeDefinitions/pathParams/ChainIdPathParam.ts
1782
- import { asHex as asHex3, HexZod, isUndefined as isUndefined3 } from "@xylabs/sdk-js";
1783
- var getRemoteChainIdZod = /* @__PURE__ */ __name((config) => {
2388
+ import {
2389
+ asHex as asHex3,
2390
+ HexZod,
2391
+ isDefined as isDefined14
2392
+ } from "@xylabs/sdk-js";
2393
+ import { z } from "zod/mini";
2394
+ var getRemoteChainIdZod = (config) => {
1784
2395
  const remoteChainId = getRemoteChainId(config);
1785
- return HexZod.superRefine((val, ctx) => {
2396
+ return HexZod.check(z.refine((val) => {
1786
2397
  const chainId = asHex3(val);
1787
- if (isUndefined3(chainId)) {
1788
- ctx.addIssue("Not a valid chain id");
1789
- return;
1790
- }
1791
- if (chainId !== remoteChainId) {
1792
- ctx.addIssue(`Only ${remoteChainId} is supported`);
1793
- }
2398
+ return isDefined14(chainId) && chainId === remoteChainId;
2399
+ }, { error: `Only ${remoteChainId} is supported` }));
2400
+ };
2401
+
2402
+ // src/server/routes/bridge/routeDefinitions/routes/bridgeFromRemoteEstimate.ts
2403
+ var makeBridgeFromRemoteEstimateRoute = (config) => {
2404
+ const params = z2.object({ chainId: getRemoteChainIdZod(config) });
2405
+ const validateRequest2 = requestHandlerValidator2({
2406
+ params,
2407
+ body: BridgeFromRemoteEstimateBodyZod,
2408
+ response: BridgeFromRemoteEstimateResponseZod
1794
2409
  });
1795
- }, "getRemoteChainIdZod");
2410
+ return {
2411
+ method: "post",
2412
+ path: "/bridge/chains/:chainId/bridgeFromRemote/estimate",
2413
+ handlers: validateRequest2(async (req, res) => {
2414
+ const services = req.app.services;
2415
+ const {
2416
+ account,
2417
+ bridge,
2418
+ gateway
2419
+ } = services;
2420
+ const {
2421
+ srcAddress,
2422
+ srcAmount,
2423
+ destAddress
2424
+ } = req.body;
2425
+ const { maxBridgeAmount, minBridgeAmount } = await getBridgeSettings(config);
2426
+ if (hexToBigInt11(srcAmount) < hexToBigInt11(minBridgeAmount) || hexToBigInt11(srcAmount) > hexToBigInt11(maxBridgeAmount)) {
2427
+ res.status(400).send();
2428
+ return;
2429
+ }
2430
+ const fees = calculateBridgeFees3(srcAmount, getFeeStructure(config));
2431
+ const feesAmount = hexToBigInt11(fees.feeFixed) + hexToBigInt11(fees.feeVariable);
2432
+ const { feesAddress } = await getTransferAddresses(config);
2433
+ const currentNextId = await bridge.nextBridgeToId({ blockTag: "latest" });
2434
+ const projectedBridgeId = currentNextId + 1n;
2435
+ const xl1ChainId = getXl1ChainId(config);
2436
+ const xl1TokenAddress = getXl1TokenAddress(config);
2437
+ const evmChainId = config.remoteChainId;
2438
+ const evmContractAddress = config.remoteBridgeContractAddress;
2439
+ const evmTokenAddress = getRemoteTokenAddress(config);
2440
+ const viewer = assertEx24(gateway.connection.viewer, () => new Error("Viewer not available on gateway connection"));
2441
+ const currentBlockNumber = await viewer.currentBlockNumber();
2442
+ const nbf = toXL1BlockNumber(currentBlockNumber, true);
2443
+ const exp = toXL1BlockNumber(currentBlockNumber + 1e3, true);
2444
+ const { intent, transfer } = buildEthToXl1BridgePayloads3({
2445
+ amount: hexToBigInt11(srcAmount),
2446
+ bridgeAccountAddress: account.address,
2447
+ bridgeId: projectedBridgeId,
2448
+ destAddress: toAddress2(destAddress),
2449
+ evmChainId,
2450
+ evmContractAddress,
2451
+ evmSrcAddress: toAddress2(srcAddress),
2452
+ evmTokenAddress,
2453
+ feesAddress,
2454
+ feesAmount,
2455
+ xl1ChainId,
2456
+ xl1TokenAddress
2457
+ });
2458
+ const [txBw] = await buildUnsignedTransaction(xl1ChainId, [transfer], [intent], nbf, exp, account.address);
2459
+ res.json([txBw, intent, transfer]);
2460
+ })
2461
+ };
2462
+ };
1796
2463
 
1797
- // src/server/routes/bridge/routeDefinitions/routes/bridgeFromRemoteStatus.ts
1798
- var BridgeIntentResponseZod = PayloadZodStrictOfSchema(BridgeIntentSchema4).extend(BridgeIntentFieldsZod.shape);
1799
- var BridgeSourceResponseZod = PayloadZodStrictOfSchema(BridgeSourceObservationSchema2).extend(BridgeSourceObservationFieldsZod.shape);
1800
- var BridgeDestinationResponseZod = PayloadZodStrictOfSchema(BridgeDestinationObservationSchema).extend(BridgeDestinationObservationFieldsZod.shape);
1801
- var BridgeFromRemoteStatusResponseZod = z.union([
1802
- z.tuple([]),
1803
- z.tuple([
1804
- BridgeIntentResponseZod
1805
- ]),
1806
- z.tuple([
1807
- BridgeIntentResponseZod,
1808
- BridgeSourceResponseZod
1809
- ]),
1810
- z.tuple([
1811
- BridgeIntentResponseZod,
1812
- BridgeSourceResponseZod,
1813
- BridgeDestinationResponseZod
1814
- ])
1815
- ]);
1816
- function buildIntentAndSource(ctx) {
1817
- const { canonical, config, nonce } = ctx;
1818
- const amountHex = toHex4(canonical.amount);
1819
- const xl1ChainId = getXl1ChainId(config);
1820
- const xl1TokenAddress = getXl1TokenAddress(config);
1821
- const evmChainId = config.remoteChainId;
1822
- const evmTokenAddress = getRemoteTokenAddress(config);
1823
- const intentFields = BridgeIntentFieldsZod.parse({
1824
- dest: xl1ChainId,
1825
- destAddress: canonical.destAddress,
1826
- destAmount: amountHex,
1827
- destToken: xl1TokenAddress,
1828
- nonce,
1829
- src: evmChainId,
1830
- srcAddress: canonical.srcAddress,
1831
- srcAmount: amountHex,
1832
- srcToken: evmTokenAddress
2464
+ // src/server/routes/bridge/routeDefinitions/routes/bridgeFromRemoteRetry.ts
2465
+ import { requestHandlerValidator as requestHandlerValidator3 } from "@xylabs/express";
2466
+ import { BridgeRetryBodyZod, BridgeRetryResponseZod } from "@xyo-network/chain-bridge-shared";
2467
+ import { z as z3 } from "zod/mini";
2468
+ var makeBridgeFromRemoteRetryRoute = (config) => {
2469
+ const params = z3.object({
2470
+ chainId: getRemoteChainIdZod(config),
2471
+ nonce: z3.string().check(z3.regex(/^\d+$/, { error: "nonce must be a non-negative integer (the bridge contract's id)" }))
2472
+ });
2473
+ const validateRequest2 = requestHandlerValidator3({
2474
+ params,
2475
+ body: BridgeRetryBodyZod,
2476
+ response: BridgeRetryResponseZod
1833
2477
  });
1834
- const intent = {
1835
- schema: BridgeIntentSchema4,
1836
- ...intentFields
2478
+ return {
2479
+ method: "post",
2480
+ path: "/bridge/chains/:chainId/bridgeFromRemote/retry/:nonce",
2481
+ handlers: validateRequest2(async (req, res) => {
2482
+ const bridgeId = BigInt(req.params.nonce);
2483
+ const identity = getJobIdForEthToXl1BridgeJob({
2484
+ bridgeId,
2485
+ contractAddress: config.remoteBridgeContractAddress,
2486
+ evmChainId: config.remoteChainId
2487
+ });
2488
+ const queues = getEthToXl1Queues(config);
2489
+ const result = await retrySingleFailedJob({
2490
+ dryRun: req.body.dryRun,
2491
+ jobId: identity,
2492
+ queue: queues.xl1ReserveTxFulfillment
2493
+ });
2494
+ if (result.status === "retried" && !req.body.dryRun) {
2495
+ req.app.services.bridgeFlowMetrics.recordRetried({ direction: "inbound", trigger: "api_singular" });
2496
+ }
2497
+ const httpStatus = result.status === "not-found" ? 404 : 200;
2498
+ res.status(httpStatus).json(result);
2499
+ })
1837
2500
  };
1838
- const sourceFields = BridgeSourceObservationFieldsZod.parse({
1839
- ...intentFields,
1840
- srcConfirmation: canonical.evmTxHash
2501
+ };
2502
+
2503
+ // src/server/routes/bridge/routeDefinitions/routes/bridgeFromRemoteRetryFailed.ts
2504
+ import { requestHandlerValidator as requestHandlerValidator4 } from "@xylabs/express";
2505
+ import { BridgeRetryFailedBodyZod, BridgeRetryFailedResponseZod } from "@xyo-network/chain-bridge-shared";
2506
+ import { StatusCodes } from "http-status-codes";
2507
+ import { z as z4 } from "zod/mini";
2508
+ var makeBridgeFromRemoteRetryFailedRoute = (config) => {
2509
+ const params = z4.object({ chainId: getRemoteChainIdZod(config) });
2510
+ const validateRequest2 = requestHandlerValidator4({
2511
+ params,
2512
+ body: BridgeRetryFailedBodyZod,
2513
+ response: BridgeRetryFailedResponseZod
1841
2514
  });
1842
- const source = {
1843
- schema: BridgeSourceObservationSchema2,
1844
- ...sourceFields
2515
+ return {
2516
+ method: "post",
2517
+ path: "/bridge/chains/:chainId/bridgeFromRemote/retryFailed",
2518
+ handlers: validateRequest2(async (req, res) => {
2519
+ const filters = req.body;
2520
+ if (!hasAnyFilter(filters)) {
2521
+ const err = new Error(
2522
+ `At least one filter is required to prevent accidental retry-everything. Available filters: ${AVAILABLE_BULK_FILTERS.join(", ")}.`
2523
+ );
2524
+ err.name = "Bad Request";
2525
+ err.statusCode = StatusCodes.BAD_REQUEST;
2526
+ throw err;
2527
+ }
2528
+ const services = req.app.services;
2529
+ const queues = getEthToXl1Queues(config);
2530
+ const srcAddressLookup = async (jobId) => {
2531
+ const state = await services.bridgeFulfillmentMap.get(jobId);
2532
+ return state?.canonical?.srcAddress;
2533
+ };
2534
+ const result = await retryFailedJobs({
2535
+ filters,
2536
+ queue: queues.xl1ReserveTxFulfillment,
2537
+ srcAddressLookup
2538
+ });
2539
+ if (!filters.dryRun && result.counts.retried > 0) {
2540
+ services.bridgeFlowMetrics.recordRetried({
2541
+ count: result.counts.retried,
2542
+ direction: "inbound",
2543
+ trigger: "api_bulk"
2544
+ });
2545
+ }
2546
+ res.json(result);
2547
+ })
1845
2548
  };
1846
- return [
1847
- intent,
1848
- source
1849
- ];
1850
- }
1851
- __name(buildIntentAndSource, "buildIntentAndSource");
1852
- var makeBridgeFromRemoteStatusRoute = /* @__PURE__ */ __name((config) => {
1853
- const params = z.object({
2549
+ };
2550
+
2551
+ // src/server/routes/bridge/routeDefinitions/routes/bridgeFromRemoteStatus.ts
2552
+ import { requestHandlerValidator as requestHandlerValidator5 } from "@xylabs/express";
2553
+ import { assertEx as assertEx25, isDefined as isDefined15 } from "@xylabs/sdk-js";
2554
+ import { BridgeFromRemoteStatusResponseZod } from "@xyo-network/chain-bridge-shared";
2555
+ import { z as z5 } from "zod/mini";
2556
+ var makeBridgeFromRemoteStatusRoute = (config) => {
2557
+ const params = z5.object({
1854
2558
  chainId: getRemoteChainIdZod(config),
1855
- nonce: z.string().regex(/^\d+$/, "nonce must be a non-negative integer (the bridge contract's id)")
1856
- });
1857
- const validateRequest2 = requestHandlerValidator2({
1858
- params,
1859
- response: BridgeFromRemoteStatusResponseZod
2559
+ nonce: z5.string().check(z5.regex(/^\d+$/, { error: "nonce must be a non-negative integer (the bridge contract's id)" }))
1860
2560
  });
2561
+ const validateRequest2 = requestHandlerValidator5({ params, response: BridgeFromRemoteStatusResponseZod });
1861
2562
  return {
1862
2563
  method: "get",
1863
2564
  path: "/bridge/chains/:chainId/bridgeFromRemote/status/:nonce",
@@ -1872,56 +2573,77 @@ var makeBridgeFromRemoteStatusRoute = /* @__PURE__ */ __name((config) => {
1872
2573
  });
1873
2574
  const services = req.app.services;
1874
2575
  const state = await services.bridgeFulfillmentMap.get(identity);
1875
- if (state?.failed) return res.sendStatus(504);
1876
2576
  if (!state?.canonical) {
1877
2577
  const queues = getEthToXl1Queues(config);
1878
2578
  const parentJob = await queues.ethToXl1BridgeParent.getJob(identity);
1879
- if (!isDefined14(parentJob)) return res.sendStatus(404);
2579
+ if (!isDefined15(parentJob)) return res.sendStatus(404);
1880
2580
  return res.json([]);
1881
2581
  }
1882
- const [intent, source] = buildIntentAndSource({
1883
- canonical: state.canonical,
1884
- config,
1885
- nonce: identity
1886
- });
1887
- if (!state.fulfilled) return res.json([
1888
- intent,
1889
- source
1890
- ]);
1891
- const destinationFields = BridgeDestinationObservationFieldsZod.parse({
1892
- ...intent,
1893
- destConfirmation: state.fulfilled.txHash
1894
- });
1895
- const destination = {
1896
- schema: BridgeDestinationObservationSchema,
1897
- ...destinationFields
1898
- };
1899
- res.json([
1900
- intent,
1901
- source,
1902
- destination
1903
- ]);
2582
+ const intent = assertEx25(state.acceptedIntent, () => `[${identity}] acceptedIntent missing despite canonical \u2014 stale state`);
2583
+ const source = assertEx25(state.acceptedSourceObservation, () => `[${identity}] acceptedSourceObservation missing despite canonical \u2014 stale state`);
2584
+ if (!state.fulfilled) return res.json([intent, source]);
2585
+ const destination = assertEx25(state.acceptedDestinationObservation, () => `[${identity}] acceptedDestinationObservation missing despite fulfilled \u2014 stale state`);
2586
+ res.json([intent, source, destination]);
1904
2587
  })
1905
2588
  };
1906
- }, "makeBridgeFromRemoteStatusRoute");
2589
+ };
1907
2590
 
1908
- // src/server/routes/bridge/routeDefinitions/routes/bridgeToRemote.ts
1909
- import { requestHandlerValidator as requestHandlerValidator3 } from "@xylabs/express";
1910
- import { isDefined as isDefined15 } from "@xylabs/sdk-js";
1911
- import { PayloadBuilder as PayloadBuilder16, PayloadZodLooseOfSchema, PayloadZodStrictOfSchema as PayloadZodStrictOfSchema2 } from "@xyo-network/sdk-js";
1912
- import { BridgeIntentFieldsZod as BridgeIntentFieldsZod2, BridgeIntentSchema as BridgeIntentSchema5, BridgeSourceObservationFieldsZod as BridgeSourceObservationFieldsZod2, BridgeSourceObservationSchema as BridgeSourceObservationSchema3, SignedTransactionBoundWitnessZod, TransferZod } from "@xyo-network/xl1-sdk";
1913
- import { z as z2 } from "zod";
1914
- var BridgeToRemoteBodyZod = z2.tuple([
1915
- SignedTransactionBoundWitnessZod,
1916
- PayloadZodLooseOfSchema(BridgeIntentSchema5).extend(BridgeIntentFieldsZod2.shape),
1917
- TransferZod
1918
- ]);
1919
- var BridgeToRemoteResponseZod = PayloadZodStrictOfSchema2(BridgeSourceObservationSchema3).extend(BridgeSourceObservationFieldsZod2.shape);
1920
- var makeBridgeToRemoteRoute = /* @__PURE__ */ __name((config) => {
1921
- const params = z2.object({
1922
- chainId: getRemoteChainIdZod(config)
2591
+ // src/server/routes/bridge/routeDefinitions/routes/bridgeFromRemoteStatusByTx.ts
2592
+ import { requestHandlerValidator as requestHandlerValidator6 } from "@xylabs/express";
2593
+ import { assertEx as assertEx26 } from "@xylabs/sdk-js";
2594
+ import { BridgeFromRemoteStatusResponseZod as BridgeFromRemoteStatusResponseZod2 } from "@xyo-network/chain-bridge-shared";
2595
+ import { z as z6 } from "zod/mini";
2596
+ async function lookupBridgeFromRemoteStatusByTx(map, evmTxHash) {
2597
+ const needle = evmTxHash.toLowerCase();
2598
+ for await (const [, state] of map) {
2599
+ const canonicalHash = state.canonical?.evmTxHash;
2600
+ if (canonicalHash === void 0) continue;
2601
+ if (canonicalHash.toLowerCase() !== needle) continue;
2602
+ const intent = assertEx26(
2603
+ state.acceptedIntent,
2604
+ () => `[${state.identity}] acceptedIntent missing despite canonical \u2014 stale state`
2605
+ );
2606
+ const source = assertEx26(
2607
+ state.acceptedSourceObservation,
2608
+ () => `[${state.identity}] acceptedSourceObservation missing despite canonical \u2014 stale state`
2609
+ );
2610
+ if (!state.fulfilled) return [intent, source];
2611
+ const destination = assertEx26(
2612
+ state.acceptedDestinationObservation,
2613
+ () => `[${state.identity}] acceptedDestinationObservation missing despite fulfilled \u2014 stale state`
2614
+ );
2615
+ return [intent, source, destination];
2616
+ }
2617
+ return null;
2618
+ }
2619
+ var makeBridgeFromRemoteStatusByTxRoute = (config) => {
2620
+ const params = z6.object({
2621
+ chainId: getRemoteChainIdZod(config),
2622
+ evmTxHash: z6.string().check(z6.regex(/^0x[0-9a-fA-F]{64}$/, { error: "evmTxHash must be a 0x-prefixed 32-byte hex string" }))
1923
2623
  });
1924
- const validateRequest2 = requestHandlerValidator3({
2624
+ const validateRequest2 = requestHandlerValidator6({ params, response: BridgeFromRemoteStatusResponseZod2 });
2625
+ return {
2626
+ method: "get",
2627
+ path: "/bridge/chains/:chainId/bridgeFromRemote/status/byTx/:evmTxHash",
2628
+ handlers: validateRequest2(async (req, res) => {
2629
+ const services = req.app.services;
2630
+ const result = await lookupBridgeFromRemoteStatusByTx(services.bridgeFulfillmentMap, req.params.evmTxHash);
2631
+ if (result === null) return res.sendStatus(404);
2632
+ res.json(result);
2633
+ })
2634
+ };
2635
+ };
2636
+
2637
+ // src/server/routes/bridge/routeDefinitions/routes/bridgeToRemote.ts
2638
+ import { requestHandlerValidator as requestHandlerValidator7 } from "@xylabs/express";
2639
+ import { isDefined as isDefined16 } from "@xylabs/sdk-js";
2640
+ import { BridgeToRemoteBodyZod, BridgeToRemoteResponseZod } from "@xyo-network/chain-bridge-shared";
2641
+ import { PayloadBuilder as PayloadBuilder16 } from "@xyo-network/sdk-js";
2642
+ import { BridgeSourceObservationFieldsZod as BridgeSourceObservationFieldsZod2, BridgeSourceObservationSchema as BridgeSourceObservationSchema3 } from "@xyo-network/xl1-sdk";
2643
+ import { z as z7 } from "zod/mini";
2644
+ var makeBridgeToRemoteRoute = (config) => {
2645
+ const params = z7.object({ chainId: getRemoteChainIdZod(config) });
2646
+ const validateRequest2 = requestHandlerValidator7({
1925
2647
  params,
1926
2648
  body: BridgeToRemoteBodyZod,
1927
2649
  response: BridgeToRemoteResponseZod
@@ -1948,56 +2670,38 @@ var makeBridgeToRemoteRoute = /* @__PURE__ */ __name((config) => {
1948
2670
  res.status(400).send();
1949
2671
  return;
1950
2672
  }
1951
- const singedHydratedTransaction = [
1952
- signedTxBw,
1953
- [
1954
- transfer
1955
- ]
1956
- ];
2673
+ const singedHydratedTransaction = [signedTxBw, [transfer]];
1957
2674
  const existingFlow = await getXl1ToEthBridgeJob(flowProducer2, singedHydratedTransaction);
1958
- if (isDefined15(existingFlow)) {
2675
+ if (isDefined16(existingFlow)) {
1959
2676
  res.status(200).send();
1960
2677
  return;
1961
2678
  }
1962
- await createXl1ToEthBridgeJob(flowProducer2, singedHydratedTransaction, [
1963
- bridgeIntent
1964
- ]);
2679
+ await createXl1ToEthBridgeJob(flowProducer2, singedHydratedTransaction, [bridgeIntent]);
1965
2680
  const srcConfirmation = await PayloadBuilder16.hash(signedTxBw);
1966
- const bridgeCommonFieldsZod = z2.object({}).extend(BridgeSourceObservationFieldsZod2.shape);
2681
+ const bridgeCommonFieldsZod = z7.object(BridgeSourceObservationFieldsZod2.shape);
1967
2682
  const bridgeCommonFields = bridgeCommonFieldsZod.parse(bridgeIntent);
1968
- const bridgeObservationFields = {
1969
- ...bridgeCommonFields,
1970
- srcConfirmation
1971
- };
1972
- const bridgeObservation = new PayloadBuilder16({
1973
- schema: BridgeSourceObservationSchema3
1974
- }).fields(bridgeObservationFields).build();
2683
+ const bridgeObservationFields = { ...bridgeCommonFields, srcConfirmation };
2684
+ const bridgeObservation = new PayloadBuilder16(
2685
+ { schema: BridgeSourceObservationSchema3 }
2686
+ ).fields(bridgeObservationFields).build();
1975
2687
  res.status(202).json(bridgeObservation);
1976
2688
  })
1977
2689
  };
1978
- }, "makeBridgeToRemoteRoute");
2690
+ };
1979
2691
 
1980
2692
  // src/server/routes/bridge/routeDefinitions/routes/bridgeToRemoteEstimate.ts
1981
- import { requestHandlerValidator as requestHandlerValidator4 } from "@xylabs/express";
1982
- import { assertEx as assertEx22, hexToBigInt as hexToBigInt10, toAddress as toAddress3 } from "@xylabs/sdk-js";
1983
- import { PayloadZodStrictOfSchema as PayloadZodStrictOfSchema3 } from "@xyo-network/sdk-js";
1984
- import { BridgeIntentFieldsZod as BridgeIntentFieldsZod3, BridgeIntentSchema as BridgeIntentSchema6, buildUnsignedTransaction, toXL1BlockNumber, TransactionBoundWitnessZod, TransferZod as TransferZod2 } from "@xyo-network/xl1-sdk";
1985
- import { z as z3 } from "zod";
1986
- var BridgeToRemoteEstimateBodyZod = BridgeIntentFieldsZod3.pick({
1987
- destAddress: true,
1988
- srcAddress: true,
1989
- srcAmount: true
1990
- });
1991
- var BridgeToRemoteEstimateResponseZod = z3.tuple([
1992
- TransactionBoundWitnessZod,
1993
- PayloadZodStrictOfSchema3(BridgeIntentSchema6).extend(BridgeIntentFieldsZod3.shape),
1994
- TransferZod2
1995
- ]);
1996
- var makeBridgeToRemoteEstimateRoute = /* @__PURE__ */ __name((config, gateway) => {
1997
- const params = z3.object({
1998
- chainId: getRemoteChainIdZod(config)
1999
- });
2000
- const validateRequest2 = requestHandlerValidator4({
2693
+ import { requestHandlerValidator as requestHandlerValidator8 } from "@xylabs/express";
2694
+ import {
2695
+ assertEx as assertEx27,
2696
+ hexToBigInt as hexToBigInt12,
2697
+ toAddress as toAddress3
2698
+ } from "@xylabs/sdk-js";
2699
+ import { BridgeToRemoteEstimateBodyZod, BridgeToRemoteEstimateResponseZod } from "@xyo-network/chain-bridge-shared";
2700
+ import { buildUnsignedTransaction as buildUnsignedTransaction2, toXL1BlockNumber as toXL1BlockNumber2 } from "@xyo-network/xl1-sdk";
2701
+ import { z as z8 } from "zod/mini";
2702
+ var makeBridgeToRemoteEstimateRoute = (config, gateway) => {
2703
+ const params = z8.object({ chainId: getRemoteChainIdZod(config) });
2704
+ const validateRequest2 = requestHandlerValidator8({
2001
2705
  params,
2002
2706
  body: BridgeToRemoteEstimateBodyZod,
2003
2707
  response: BridgeToRemoteEstimateResponseZod
@@ -2007,53 +2711,46 @@ var makeBridgeToRemoteEstimateRoute = /* @__PURE__ */ __name((config, gateway) =
2007
2711
  path: "/bridge/chains/:chainId/bridgeToRemote/estimate",
2008
2712
  handlers: validateRequest2(async (req, res) => {
2009
2713
  const xl1ChainId = getXl1ChainId(config);
2010
- const { srcAddress, srcAmount, destAddress } = req.body;
2714
+ const {
2715
+ srcAddress,
2716
+ srcAmount,
2717
+ destAddress
2718
+ } = req.body;
2011
2719
  const { maxBridgeAmount, minBridgeAmount } = await getBridgeSettings(config);
2012
- if (hexToBigInt10(srcAmount) < hexToBigInt10(minBridgeAmount) || hexToBigInt10(srcAmount) > hexToBigInt10(maxBridgeAmount)) {
2720
+ if (hexToBigInt12(srcAmount) < hexToBigInt12(minBridgeAmount) || hexToBigInt12(srcAmount) > hexToBigInt12(maxBridgeAmount)) {
2013
2721
  res.status(400).send();
2014
2722
  return;
2015
2723
  }
2016
2724
  const [bridgeIntent, transfer] = await generateBridgeEstimate(srcAddress, srcAmount, destAddress, config);
2017
2725
  const sender = toAddress3(srcAddress);
2018
- const viewer = assertEx22(gateway.connection.viewer, () => new Error("Viewer not available on gateway connection"));
2726
+ const viewer = assertEx27(gateway.connection.viewer, () => new Error("Viewer not available on gateway connection"));
2019
2727
  const currentBlockNumber = await viewer.currentBlockNumber();
2020
- const nbf = toXL1BlockNumber(currentBlockNumber, true);
2021
- const exp = toXL1BlockNumber(currentBlockNumber + 1e3, true);
2022
- const [txBw] = await buildUnsignedTransaction(xl1ChainId, [
2023
- transfer
2024
- ], [
2025
- bridgeIntent
2026
- ], nbf, exp, sender);
2027
- res.json([
2028
- txBw,
2029
- bridgeIntent,
2030
- transfer
2031
- ]);
2728
+ const nbf = toXL1BlockNumber2(currentBlockNumber, true);
2729
+ const exp = toXL1BlockNumber2(currentBlockNumber + 1e3, true);
2730
+ const [txBw] = await buildUnsignedTransaction2(xl1ChainId, [transfer], [bridgeIntent], nbf, exp, sender);
2731
+ res.json([txBw, bridgeIntent, transfer]);
2032
2732
  })
2033
2733
  };
2034
- }, "makeBridgeToRemoteEstimateRoute");
2734
+ };
2035
2735
 
2036
2736
  // src/server/routes/bridge/routeDefinitions/routes/bridgeToRemoteMaxEstimate.ts
2037
- import { requestHandlerValidator as requestHandlerValidator5 } from "@xylabs/express";
2038
- import { assertEx as assertEx23, hexToBigInt as hexToBigInt11, toAddress as toAddress4, toHex as toHex5 } from "@xylabs/sdk-js";
2039
- import { PayloadZodStrictOfSchema as PayloadZodStrictOfSchema4 } from "@xyo-network/sdk-js";
2040
- import { BridgeIntentFieldsZod as BridgeIntentFieldsZod4, BridgeIntentSchema as BridgeIntentSchema7, buildUnsignedTransaction as buildUnsignedTransaction2, toXL1BlockNumber as toXL1BlockNumber2, TransactionBoundWitnessZod as TransactionBoundWitnessZod2, TransferZod as TransferZod3 } from "@xyo-network/xl1-sdk";
2041
- import { z as z4 } from "zod";
2042
- var BridgeToRemoteMaxEstimateBodyZod = BridgeIntentFieldsZod4.pick({
2043
- destAddress: true,
2044
- srcAddress: true,
2045
- srcAmount: true
2046
- });
2047
- var BridgeToRemoteMaxEstimateResponseZod = z4.tuple([
2048
- TransactionBoundWitnessZod2,
2049
- PayloadZodStrictOfSchema4(BridgeIntentSchema7).extend(BridgeIntentFieldsZod4.shape),
2050
- TransferZod3
2051
- ]);
2052
- var makeBridgeToRemoteMaxEstimateRoute = /* @__PURE__ */ __name((config, gateway) => {
2053
- const params = z4.object({
2054
- chainId: getRemoteChainIdZod(config)
2055
- });
2056
- const validateRequest2 = requestHandlerValidator5({
2737
+ import { requestHandlerValidator as requestHandlerValidator9 } from "@xylabs/express";
2738
+ import {
2739
+ assertEx as assertEx28,
2740
+ hexToBigInt as hexToBigInt13,
2741
+ toAddress as toAddress4,
2742
+ toHex as toHex4
2743
+ } from "@xylabs/sdk-js";
2744
+ import {
2745
+ BridgeToRemoteMaxEstimateBodyZod,
2746
+ BridgeToRemoteMaxEstimateResponseZod,
2747
+ calculateMaxBridgeAmount
2748
+ } from "@xyo-network/chain-bridge-shared";
2749
+ import { buildUnsignedTransaction as buildUnsignedTransaction3, toXL1BlockNumber as toXL1BlockNumber3 } from "@xyo-network/xl1-sdk";
2750
+ import { z as z9 } from "zod/mini";
2751
+ var makeBridgeToRemoteMaxEstimateRoute = (config, gateway) => {
2752
+ const params = z9.object({ chainId: getRemoteChainIdZod(config) });
2753
+ const validateRequest2 = requestHandlerValidator9({
2057
2754
  params,
2058
2755
  body: BridgeToRemoteMaxEstimateBodyZod,
2059
2756
  response: BridgeToRemoteMaxEstimateResponseZod
@@ -2062,66 +2759,135 @@ var makeBridgeToRemoteMaxEstimateRoute = /* @__PURE__ */ __name((config, gateway
2062
2759
  method: "post",
2063
2760
  path: "/bridge/chains/:chainId/bridgeToRemote/maxEstimate",
2064
2761
  handlers: validateRequest2(async (req, res) => {
2065
- const { feeFixed, feeRateBasisPoints, maxBridgeAmount: configMax, xl1ChainId } = await getBridgeSettings(config);
2066
- const { srcAddress, srcAmount: balance, destAddress } = req.body;
2067
- const balanceMax = calculateMaxBridgeAmount(balance, {
2762
+ const {
2068
2763
  feeFixed,
2069
- feeRateBasisPoints
2070
- });
2071
- const maxBridgeAmount = toHex5(hexToBigInt11(balanceMax) < hexToBigInt11(configMax) ? balanceMax : configMax);
2764
+ feeRateBasisPoints,
2765
+ maxBridgeAmount: configMax,
2766
+ xl1ChainId
2767
+ } = await getBridgeSettings(config);
2768
+ const {
2769
+ srcAddress,
2770
+ srcAmount: balance,
2771
+ destAddress
2772
+ } = req.body;
2773
+ const balanceMax = calculateMaxBridgeAmount(balance, { feeFixed, feeRateBasisPoints });
2774
+ const maxBridgeAmount = toHex4(hexToBigInt13(balanceMax) < hexToBigInt13(configMax) ? balanceMax : configMax);
2072
2775
  const [bridgeIntent, transfer] = await generateBridgeEstimate(srcAddress, maxBridgeAmount, destAddress, config);
2073
2776
  const sender = toAddress4(srcAddress);
2074
- const viewer = assertEx23(gateway.connection.viewer, () => new Error("Viewer not available on gateway connection"));
2777
+ const viewer = assertEx28(gateway.connection.viewer, () => new Error("Viewer not available on gateway connection"));
2075
2778
  const currentBlockNumber = await viewer.currentBlockNumber();
2076
- const nbf = toXL1BlockNumber2(currentBlockNumber, true);
2077
- const exp = toXL1BlockNumber2(currentBlockNumber + 1e3, true);
2078
- const [txBw] = await buildUnsignedTransaction2(xl1ChainId, [
2079
- transfer
2080
- ], [
2081
- bridgeIntent
2082
- ], nbf, exp, sender);
2083
- res.json([
2084
- txBw,
2085
- bridgeIntent,
2086
- transfer
2087
- ]);
2779
+ const nbf = toXL1BlockNumber3(currentBlockNumber, true);
2780
+ const exp = toXL1BlockNumber3(currentBlockNumber + 1e3, true);
2781
+ const [txBw] = await buildUnsignedTransaction3(xl1ChainId, [transfer], [bridgeIntent], nbf, exp, sender);
2782
+ res.json([txBw, bridgeIntent, transfer]);
2088
2783
  })
2089
2784
  };
2090
- }, "makeBridgeToRemoteMaxEstimateRoute");
2785
+ };
2091
2786
 
2092
- // src/server/routes/bridge/routeDefinitions/routes/bridgeToRemoteStatus.ts
2093
- import { requestHandlerValidator as requestHandlerValidator6 } from "@xylabs/express";
2094
- import { asHex as asHex4, isDefined as isDefined16 } from "@xylabs/sdk-js";
2095
- import { PayloadBuilder as PayloadBuilder17, PayloadZodStrictOfSchema as PayloadZodStrictOfSchema5 } from "@xyo-network/sdk-js";
2096
- import { asBridgeIntent, BridgeDestinationObservationFieldsZod as BridgeDestinationObservationFieldsZod2, BridgeDestinationObservationSchema as BridgeDestinationObservationSchema2, BridgeIntentFieldsZod as BridgeIntentFieldsZod5, BridgeIntentSchema as BridgeIntentSchema8, BridgeSourceObservationFieldsZod as BridgeSourceObservationFieldsZod3, BridgeSourceObservationSchema as BridgeSourceObservationSchema4, isBridgeIntent as isBridgeIntent5 } from "@xyo-network/xl1-sdk";
2097
- import { z as z5 } from "zod";
2098
- var BridgeIntentResponseZod2 = PayloadZodStrictOfSchema5(BridgeIntentSchema8).extend(BridgeIntentFieldsZod5.shape);
2099
- var BridgeSourceResponseZod2 = PayloadZodStrictOfSchema5(BridgeSourceObservationSchema4).extend(BridgeSourceObservationFieldsZod3.shape);
2100
- var BridgeDestinationResponseZod2 = PayloadZodStrictOfSchema5(BridgeDestinationObservationSchema2).extend(BridgeDestinationObservationFieldsZod2.shape);
2101
- var BridgeToRemoteStatusResponseZod = z5.union([
2102
- z5.tuple([]),
2103
- z5.tuple([
2104
- BridgeIntentResponseZod2
2105
- ]),
2106
- z5.tuple([
2107
- BridgeIntentResponseZod2,
2108
- BridgeSourceResponseZod2
2109
- ]),
2110
- z5.tuple([
2111
- BridgeIntentResponseZod2,
2112
- BridgeSourceResponseZod2,
2113
- BridgeDestinationResponseZod2
2114
- ])
2115
- ]);
2116
- var makeBridgeToRemoteStatusRoute = /* @__PURE__ */ __name((config) => {
2117
- const params = z5.object({
2787
+ // src/server/routes/bridge/routeDefinitions/routes/bridgeToRemoteRetry.ts
2788
+ import { requestHandlerValidator as requestHandlerValidator10 } from "@xylabs/express";
2789
+ import { BridgeRetryBodyZod as BridgeRetryBodyZod2, BridgeRetryResponseZod as BridgeRetryResponseZod2 } from "@xyo-network/chain-bridge-shared";
2790
+ import { z as z10 } from "zod/mini";
2791
+ var makeBridgeToRemoteRetryRoute = (config) => {
2792
+ const params = z10.object({
2118
2793
  chainId: getRemoteChainIdZod(config),
2119
- nonce: z5.string().nonempty()
2794
+ nonce: z10.string().check(z10.minLength(1))
2120
2795
  });
2121
- const validateRequest2 = requestHandlerValidator6({
2796
+ const validateRequest2 = requestHandlerValidator10({
2797
+ params,
2798
+ body: BridgeRetryBodyZod2,
2799
+ response: BridgeRetryResponseZod2
2800
+ });
2801
+ return {
2802
+ method: "post",
2803
+ path: "/bridge/chains/:chainId/bridgeToRemote/retry/:nonce",
2804
+ handlers: validateRequest2(async (req, res) => {
2805
+ const jobId = req.params.nonce;
2806
+ const queues = getXl1ToEthQueues(config);
2807
+ const result = await retrySingleFailedJob({
2808
+ dryRun: req.body.dryRun,
2809
+ jobId,
2810
+ queue: queues.ethTransactionMonitor
2811
+ });
2812
+ if (result.status === "retried" && !req.body.dryRun) {
2813
+ req.app.services.bridgeFlowMetrics.recordRetried({ direction: "outbound", trigger: "api_singular" });
2814
+ }
2815
+ const httpStatus = result.status === "not-found" ? 404 : 200;
2816
+ res.status(httpStatus).json(result);
2817
+ })
2818
+ };
2819
+ };
2820
+
2821
+ // src/server/routes/bridge/routeDefinitions/routes/bridgeToRemoteRetryFailed.ts
2822
+ import { requestHandlerValidator as requestHandlerValidator11 } from "@xylabs/express";
2823
+ import { BridgeRetryFailedBodyZod as BridgeRetryFailedBodyZod2, BridgeRetryFailedResponseZod as BridgeRetryFailedResponseZod2 } from "@xyo-network/chain-bridge-shared";
2824
+ import { isBridgeIntent as isBridgeIntent6 } from "@xyo-network/xl1-sdk";
2825
+ import { StatusCodes as StatusCodes2 } from "http-status-codes";
2826
+ import { z as z11 } from "zod/mini";
2827
+ var makeBridgeToRemoteRetryFailedRoute = (config) => {
2828
+ const params = z11.object({ chainId: getRemoteChainIdZod(config) });
2829
+ const validateRequest2 = requestHandlerValidator11({
2122
2830
  params,
2123
- response: BridgeToRemoteStatusResponseZod
2831
+ body: BridgeRetryFailedBodyZod2,
2832
+ response: BridgeRetryFailedResponseZod2
2833
+ });
2834
+ return {
2835
+ method: "post",
2836
+ path: "/bridge/chains/:chainId/bridgeToRemote/retryFailed",
2837
+ handlers: validateRequest2(async (req, res) => {
2838
+ const filters = req.body;
2839
+ if (!hasAnyFilter(filters)) {
2840
+ const err = new Error(
2841
+ `At least one filter is required to prevent accidental retry-everything. Available filters: ${AVAILABLE_BULK_FILTERS.join(", ")}.`
2842
+ );
2843
+ err.name = "Bad Request";
2844
+ err.statusCode = StatusCodes2.BAD_REQUEST;
2845
+ throw err;
2846
+ }
2847
+ const queues = getXl1ToEthQueues(config);
2848
+ const srcAddressLookup = async (jobId) => {
2849
+ const job = await queues.ethTransactionMonitor.getJob(jobId);
2850
+ const data = job?.data;
2851
+ const bridgeIntent = data?.tx[1].find(isBridgeIntent6);
2852
+ return bridgeIntent?.srcAddress;
2853
+ };
2854
+ const result = await retryFailedJobs({
2855
+ filters,
2856
+ queue: queues.ethTransactionMonitor,
2857
+ srcAddressLookup
2858
+ });
2859
+ if (!filters.dryRun && result.counts.retried > 0) {
2860
+ req.app.services.bridgeFlowMetrics.recordRetried({
2861
+ count: result.counts.retried,
2862
+ direction: "outbound",
2863
+ trigger: "api_bulk"
2864
+ });
2865
+ }
2866
+ res.json(result);
2867
+ })
2868
+ };
2869
+ };
2870
+
2871
+ // src/server/routes/bridge/routeDefinitions/routes/bridgeToRemoteStatus.ts
2872
+ import { requestHandlerValidator as requestHandlerValidator12 } from "@xylabs/express";
2873
+ import { asHex as asHex4, isDefined as isDefined17 } from "@xylabs/sdk-js";
2874
+ import { BridgeToRemoteStatusResponseZod } from "@xyo-network/chain-bridge-shared";
2875
+ import { PayloadBuilder as PayloadBuilder17 } from "@xyo-network/sdk-js";
2876
+ import {
2877
+ asBridgeIntent,
2878
+ BridgeDestinationObservationFieldsZod as BridgeDestinationObservationFieldsZod2,
2879
+ BridgeDestinationObservationSchema as BridgeDestinationObservationSchema2,
2880
+ BridgeSourceObservationFieldsZod as BridgeSourceObservationFieldsZod3,
2881
+ BridgeSourceObservationSchema as BridgeSourceObservationSchema4,
2882
+ isBridgeIntent as isBridgeIntent7
2883
+ } from "@xyo-network/xl1-sdk";
2884
+ import { z as z12 } from "zod/mini";
2885
+ var makeBridgeToRemoteStatusRoute = (config) => {
2886
+ const params = z12.object({
2887
+ chainId: getRemoteChainIdZod(config),
2888
+ nonce: z12.string().check(z12.minLength(1))
2124
2889
  });
2890
+ const validateRequest2 = requestHandlerValidator12({ params, response: BridgeToRemoteStatusResponseZod });
2125
2891
  return {
2126
2892
  method: "get",
2127
2893
  path: "/bridge/chains/:chainId/bridgeToRemote/status/:nonce",
@@ -2132,18 +2898,15 @@ var makeBridgeToRemoteStatusRoute = /* @__PURE__ */ __name((config) => {
2132
2898
  const statusQueueJobs = await getStatusQueueJobs(queues, jobId);
2133
2899
  const { tx, offChainPayloads = [] } = statusQueueJobs.xl1ToEthBridgeParentJob?.data ?? {};
2134
2900
  if (!tx) return res.sendStatus(404);
2135
- const allPayloads = [
2136
- ...tx[1],
2137
- ...offChainPayloads
2138
- ];
2139
- const bridgeIntent = allPayloads.find(isBridgeIntent5);
2901
+ const allPayloads = [...tx[1], ...offChainPayloads];
2902
+ const bridgeIntent = allPayloads.find(isBridgeIntent7);
2140
2903
  if (!bridgeIntent) return res.sendStatus(404);
2141
2904
  result[0] = asBridgeIntent(PayloadBuilder17.omitMeta(bridgeIntent));
2142
2905
  const { xl1TransactionMonitorJob } = statusQueueJobs;
2143
2906
  const xl1MonitorState = xl1TransactionMonitorJob ? await xl1TransactionMonitorJob.getState() : void 0;
2144
2907
  if (xl1MonitorState === "completed") {
2145
2908
  const srcConfirmation = xl1TransactionMonitorJob?.returnvalue?.submissionHash;
2146
- if (isDefined16(srcConfirmation)) {
2909
+ if (isDefined17(srcConfirmation)) {
2147
2910
  const schema = BridgeSourceObservationSchema4;
2148
2911
  const bridgeSourceObservationFields = BridgeSourceObservationFieldsZod3.parse(bridgeIntent);
2149
2912
  const observation = {
@@ -2158,7 +2921,7 @@ var makeBridgeToRemoteStatusRoute = /* @__PURE__ */ __name((config) => {
2158
2921
  const ethMonitorState = ethTransactionMonitorJob ? await ethTransactionMonitorJob.getState() : void 0;
2159
2922
  if (ethMonitorState === "completed") {
2160
2923
  const destConfirmation = asHex4(ethTransactionMonitorJob?.returnvalue?.submissionHash);
2161
- if (isDefined16(destConfirmation)) {
2924
+ if (isDefined17(destConfirmation)) {
2162
2925
  const schema = BridgeDestinationObservationSchema2;
2163
2926
  const bridgeDestinationObservationFields = BridgeDestinationObservationFieldsZod2.parse(bridgeIntent);
2164
2927
  const observation = {
@@ -2172,36 +2935,42 @@ var makeBridgeToRemoteStatusRoute = /* @__PURE__ */ __name((config) => {
2172
2935
  res.json(result);
2173
2936
  })
2174
2937
  };
2175
- }, "makeBridgeToRemoteStatusRoute");
2938
+ };
2176
2939
 
2177
2940
  // src/server/routes/bridge/routeDefinitions/getRouteDefinitions.ts
2178
- var getRouteDefinitions = /* @__PURE__ */ __name((config, gateway) => {
2941
+ var getRouteDefinitions = (config, gateway) => {
2179
2942
  return [
2180
2943
  makeBridgeConfigRoute(config),
2181
2944
  makeBridgeToRemoteEstimateRoute(config, gateway),
2182
2945
  makeBridgeToRemoteMaxEstimateRoute(config, gateway),
2183
2946
  makeBridgeToRemoteRoute(config),
2947
+ makeBridgeToRemoteRetryRoute(config),
2948
+ makeBridgeToRemoteRetryFailedRoute(config),
2184
2949
  makeBridgeToRemoteStatusRoute(config),
2185
- makeBridgeFromRemoteStatusRoute(config)
2950
+ makeBridgeFromRemoteEstimateRoute(config),
2951
+ makeBridgeFromRemoteRetryRoute(config),
2952
+ makeBridgeFromRemoteRetryFailedRoute(config),
2953
+ makeBridgeFromRemoteStatusRoute(config),
2954
+ makeBridgeFromRemoteStatusByTxRoute(config)
2186
2955
  ];
2187
- }, "getRouteDefinitions");
2956
+ };
2188
2957
 
2189
2958
  // src/server/routes/bridge/addBridgeRoutes.ts
2190
- var addBridgeRoutes = /* @__PURE__ */ __name((app, config, gateway) => {
2959
+ var addBridgeRoutes = (app, config, gateway) => {
2191
2960
  const routeDefinitions = getRouteDefinitions(config, gateway);
2192
2961
  for (const definition of routeDefinitions) {
2193
2962
  app[definition.method](definition.path, definition.handlers);
2194
2963
  }
2195
- }, "addBridgeRoutes");
2964
+ };
2196
2965
 
2197
2966
  // src/server/routes/addRoutes.ts
2198
- var addRoutes = /* @__PURE__ */ __name((app, config, gateway) => {
2967
+ var addRoutes = (app, config, gateway) => {
2199
2968
  addProbeRoutes(app);
2200
2969
  addBridgeRoutes(app, config, gateway);
2201
- }, "addRoutes");
2970
+ };
2202
2971
 
2203
2972
  // src/server/app.ts
2204
- var getApp = /* @__PURE__ */ __name((config, gateway) => {
2973
+ var getApp = (config, gateway) => {
2205
2974
  addInstrumentation();
2206
2975
  const app = express();
2207
2976
  sharedMiddleware(app);
@@ -2209,22 +2978,28 @@ var getApp = /* @__PURE__ */ __name((config, gateway) => {
2209
2978
  addRoutes(app, config, gateway);
2210
2979
  app.use(standardErrors);
2211
2980
  return app;
2212
- }, "getApp");
2981
+ };
2213
2982
 
2214
2983
  // src/services/getServices.ts
2215
- import { assertEx as assertEx24 } from "@xylabs/sdk-js";
2984
+ import { assertEx as assertEx29 } from "@xylabs/sdk-js";
2216
2985
  import { initEvmProvider, resolveWalletForActor as resolveWalletForActor2 } from "@xyo-network/chain-orchestration";
2217
2986
  import { BridgeableToken__factory, LiquidityPoolBridge__factory } from "@xyo-network/typechain";
2218
- import { getAddress as getAddress2, Wallet } from "ethers";
2987
+ import { getAddress as getAddress3, Wallet } from "ethers";
2219
2988
 
2220
2989
  // src/services/getIterableMap.ts
2221
2990
  import { BaseMongoSdk } from "@xylabs/mongo";
2222
2991
  import { MongoMap } from "@xyo-network/chain-protocol-driver-mongodb";
2223
2992
  import { hasMongoConfig, mapToMapType } from "@xyo-network/xl1-sdk";
2224
- var getIterableMap = /* @__PURE__ */ __name(async (config, collection) => {
2993
+ var getIterableMap = async (config, collection) => {
2225
2994
  const mongoConfig = config.storage?.mongo;
2226
2995
  if (hasMongoConfig(mongoConfig)) {
2227
- const { connectionString: dbConnectionString, database: dbName, domain: dbDomain, password: dbPassword, username: dbUserName } = mongoConfig;
2996
+ const {
2997
+ connectionString: dbConnectionString,
2998
+ database: dbName,
2999
+ domain: dbDomain,
3000
+ password: dbPassword,
3001
+ username: dbUserName
3002
+ } = mongoConfig;
2228
3003
  const payloadSdkConfig = {
2229
3004
  dbConnectionString,
2230
3005
  dbDomain,
@@ -2232,237 +3007,98 @@ var getIterableMap = /* @__PURE__ */ __name(async (config, collection) => {
2232
3007
  dbPassword,
2233
3008
  dbUserName
2234
3009
  };
2235
- const sdkBalanceSummaryMap = new BaseMongoSdk({
2236
- ...payloadSdkConfig,
2237
- collection
2238
- });
3010
+ const sdkBalanceSummaryMap = new BaseMongoSdk({ ...payloadSdkConfig, collection });
2239
3011
  const result = await MongoMap.create({
2240
3012
  sdk: sdkBalanceSummaryMap,
2241
- getCache: {
2242
- enabled: true,
2243
- maxEntries: 5e3
2244
- }
3013
+ getCache: { enabled: true, maxEntries: 5e3 }
2245
3014
  });
2246
3015
  return result;
2247
3016
  } else {
2248
3017
  return mapToMapType(/* @__PURE__ */ new Map());
2249
3018
  }
2250
- }, "getIterableMap");
3019
+ };
2251
3020
 
2252
3021
  // src/services/getServices.ts
2253
- var getServices = /* @__PURE__ */ __name(async (context, gateway) => {
3022
+ var getServices = async (context, gateway, logger, meter) => {
2254
3023
  const { config } = context;
2255
3024
  const ethTxStateMap = await getIterableMap(config, "liquidity_bridge_xl1_to_eth_eth_tx_state");
2256
3025
  const xl1TxStateMap = await getIterableMap(config, "liquidity_bridge_xl1_to_eth_xl1_tx_state");
2257
3026
  const evmBridgeCursorMap = await getIterableMap(config, "liquidity_bridge_eth_to_xl1_scanner_cursor");
2258
3027
  const bridgeFulfillmentMap = await getIterableMap(config, "liquidity_bridge_eth_to_xl1_fulfillment");
2259
3028
  const provider = await initEvmProvider(context);
2260
- const { remoteBridgeContractAddress, remoteChainWalletPrivateKey, remoteTokenAddress, accountPath } = config;
3029
+ const {
3030
+ remoteBridgeContractAddress,
3031
+ remoteChainWalletPrivateKey,
3032
+ remoteTokenAddress,
3033
+ accountPath
3034
+ } = config;
2261
3035
  const account = await resolveWalletForActor2(config.name, accountPath);
2262
3036
  const wallet = new Wallet(remoteChainWalletPrivateKey, provider);
2263
- const bridgeableToken = BridgeableToken__factory.connect(getAddress2(remoteTokenAddress), wallet);
2264
- const bridge = LiquidityPoolBridge__factory.connect(getAddress2(remoteBridgeContractAddress), wallet);
3037
+ const bridgeableToken = BridgeableToken__factory.connect(getAddress3(remoteTokenAddress), wallet);
3038
+ const bridge = LiquidityPoolBridge__factory.connect(getAddress3(remoteBridgeContractAddress), wallet);
2265
3039
  const bridgeOwner = await bridge.owner();
2266
- assertEx24(bridgeOwner.toLowerCase() === wallet.address.toLowerCase(), () => "Wallet is not the owner of the bridge contract");
3040
+ assertEx29(bridgeOwner.toLowerCase() === wallet.address.toLowerCase(), () => "Wallet is not the owner of the bridge contract");
2267
3041
  const remoteConfirmationDepth = getRemoteConfirmationDepth(config);
3042
+ const evmBridgeDeployBlock = await resolveDeployBlock({
3043
+ configuredDeployBlock: config.remoteBridgeContractDeployBlock,
3044
+ contractAddress: remoteBridgeContractAddress,
3045
+ provider
3046
+ });
3047
+ const bridgeFlowMetrics = createBridgeFlowMetrics({
3048
+ meter,
3049
+ remoteChainId: config.remoteChainId
3050
+ });
2268
3051
  return {
2269
3052
  account,
2270
3053
  bridge,
3054
+ bridgeFlowMetrics,
2271
3055
  bridgeableToken,
2272
3056
  bridgeFulfillmentMap,
3057
+ config,
2273
3058
  ethTxStateMap,
2274
3059
  evmBridgeCursorMap,
3060
+ evmBridgeDeployBlock,
2275
3061
  gateway,
3062
+ logger,
2276
3063
  provider,
2277
3064
  remoteConfirmationDepth,
2278
3065
  wallet,
2279
3066
  xl1TxStateMap
2280
3067
  };
2281
- }, "getServices");
3068
+ };
2282
3069
 
2283
3070
  // src/server/addWorkers.ts
2284
- var addWorkers = /* @__PURE__ */ __name((config, services) => {
3071
+ var addWorkers = (config, services) => {
2285
3072
  const connection2 = getConnection(config);
2286
3073
  const telemetry2 = getTelemetry();
2287
3074
  createWorkers(connection2, telemetry2, services);
2288
- }, "addWorkers");
3075
+ };
2289
3076
 
2290
3077
  // src/server/server.ts
2291
3078
  var hostname = "::";
2292
- var getServer = /* @__PURE__ */ __name(async (context, gateway) => {
2293
- const { logger, config } = context;
3079
+ var getServer = async (context, gateway, logger, meter) => {
3080
+ const { config } = context;
2294
3081
  const { port } = config;
2295
3082
  const app = getApp(config, gateway);
2296
- const services = await getServices(context, gateway);
3083
+ const services = await getServices(context, gateway, logger, meter);
2297
3084
  app.services = services;
2298
3085
  addWorkers(config, services);
2299
3086
  const server = await new Promise((resolve, reject) => {
2300
3087
  const srv = app.listen(port, hostname, () => {
2301
- logger?.log(`[Bridge] Server listening at http://${hostname}:${port}`);
3088
+ logger.log(`[Bridge] Server listening at http://${hostname}:${port}`);
2302
3089
  resolve(srv);
2303
3090
  });
2304
3091
  srv.once("error", reject);
2305
3092
  });
2306
3093
  server.setTimeout(2e4);
2307
- return {
2308
- server,
2309
- services
2310
- };
2311
- }, "getServer");
2312
-
2313
- // src/telemetry/createBalanceMonitor.ts
2314
- var DEFAULT_INTERVAL_MS = 6e4;
2315
- var WEI_PER_GWEI = 10n ** 9n;
2316
- var TOKEN_DECIMALS = 10n ** 18n;
2317
- function createBalanceMonitor(config) {
2318
- const { account, bridge, bridgeableToken, gateway, meter, provider, wallet, intervalMs = DEFAULT_INTERVAL_MS } = config;
2319
- let timer;
2320
- const ethWalletGasBalance = meter.createGauge("bridge_eth_wallet_gas_balance_gwei", {
2321
- description: "ETH balance of the bridge runner wallet (in gwei)",
2322
- unit: "gwei"
2323
- });
2324
- const liquidityTokenBalance = meter.createGauge("bridge_eth_liquidity_token_balance", {
2325
- description: "ERC-20 token balance of the liquidity source (in whole tokens)",
2326
- unit: "tokens"
2327
- });
2328
- const liquidityTokenAllowance = meter.createGauge("bridge_eth_liquidity_token_allowance", {
2329
- description: "ERC-20 token allowance from liquidity source to bridge contract (in whole tokens)",
2330
- unit: "tokens"
2331
- });
2332
- const xl1AccountBalance = meter.createGauge("bridge_xl1_account_balance", {
2333
- description: "XL1 native balance of the bridge reserve account (in whole XL1)",
2334
- unit: "xl1"
2335
- });
2336
- const walletAddress = wallet.address;
2337
- async function poll() {
2338
- try {
2339
- const balance = await provider.getBalance(walletAddress);
2340
- ethWalletGasBalance.record(Number(balance / WEI_PER_GWEI), {
2341
- address: walletAddress
2342
- });
2343
- } catch (err) {
2344
- console.error("[BalanceMonitor] Failed to read ETH wallet gas balance:", err);
2345
- }
2346
- try {
2347
- const liquiditySourceAddress = await bridge.liquiditySource();
2348
- const balance = await bridgeableToken.balanceOf(liquiditySourceAddress);
2349
- liquidityTokenBalance.record(Number(balance / TOKEN_DECIMALS), {
2350
- address: liquiditySourceAddress
2351
- });
2352
- } catch (err) {
2353
- console.error("[BalanceMonitor] Failed to read liquidity source token balance:", err);
2354
- }
2355
- try {
2356
- const liquiditySourceAddress = await bridge.liquiditySource();
2357
- const bridgeAddress = await bridge.getAddress();
2358
- const allowance = await bridgeableToken.allowance(liquiditySourceAddress, bridgeAddress);
2359
- liquidityTokenAllowance.record(Number(allowance / TOKEN_DECIMALS), {
2360
- address: liquiditySourceAddress
2361
- });
2362
- } catch (err) {
2363
- console.error("[BalanceMonitor] Failed to read liquidity source token allowance:", err);
2364
- }
2365
- try {
2366
- const viewer = gateway.connection.viewer;
2367
- if (viewer) {
2368
- const balance = await viewer.account.balance.accountBalance(account.address);
2369
- xl1AccountBalance.record(Number(balance / TOKEN_DECIMALS), {
2370
- address: account.address.toString()
2371
- });
2372
- }
2373
- } catch (err) {
2374
- console.error("[BalanceMonitor] Failed to read XL1 account balance:", err);
2375
- }
2376
- }
2377
- __name(poll, "poll");
2378
- return {
2379
- start() {
2380
- void poll();
2381
- timer = setInterval(() => void poll(), intervalMs);
2382
- },
2383
- stop() {
2384
- if (timer) {
2385
- clearInterval(timer);
2386
- timer = void 0;
2387
- }
2388
- }
2389
- };
2390
- }
2391
- __name(createBalanceMonitor, "createBalanceMonitor");
2392
-
2393
- // src/telemetry/createQueueMetrics.ts
2394
- var DEFAULT_INTERVAL_MS2 = 3e4;
2395
- function createQueueMetrics(config) {
2396
- const { meter, queues, intervalMs = DEFAULT_INTERVAL_MS2 } = config;
2397
- let timer;
2398
- const waitingGauge = meter.createGauge("bridge_queue_waiting", {
2399
- description: "Number of waiting jobs in the bridge queue"
2400
- });
2401
- const activeGauge = meter.createGauge("bridge_queue_active", {
2402
- description: "Number of active jobs in the bridge queue"
2403
- });
2404
- const completedGauge = meter.createGauge("bridge_queue_completed", {
2405
- description: "Number of completed jobs in the bridge queue"
2406
- });
2407
- const failedGauge = meter.createGauge("bridge_queue_failed", {
2408
- description: "Number of failed jobs in the bridge queue"
2409
- });
2410
- const delayedGauge = meter.createGauge("bridge_queue_delayed", {
2411
- description: "Number of delayed jobs in the bridge queue"
2412
- });
2413
- async function poll() {
2414
- for (const [name13, queue] of Object.entries(queues)) {
2415
- try {
2416
- const counts = await queue.getJobCounts("waiting", "active", "completed", "failed", "delayed");
2417
- const attrs = {
2418
- queue_name: name13
2419
- };
2420
- waitingGauge.record(counts.waiting ?? 0, attrs);
2421
- activeGauge.record(counts.active ?? 0, attrs);
2422
- completedGauge.record(counts.completed ?? 0, attrs);
2423
- failedGauge.record(counts.failed ?? 0, attrs);
2424
- delayedGauge.record(counts.delayed ?? 0, attrs);
2425
- } catch (err) {
2426
- console.error(`[QueueMetrics] Failed to read job counts for queue ${name13}:`, err);
2427
- }
2428
- }
2429
- }
2430
- __name(poll, "poll");
2431
- return {
2432
- start() {
2433
- void poll();
2434
- timer = setInterval(() => void poll(), intervalMs);
2435
- },
2436
- stop() {
2437
- if (timer) {
2438
- clearInterval(timer);
2439
- timer = void 0;
2440
- }
2441
- }
2442
- };
2443
- }
2444
- __name(createQueueMetrics, "createQueueMetrics");
3094
+ return { server, services };
3095
+ };
2445
3096
 
2446
3097
  // src/BridgeActor.ts
2447
- function _ts_decorate(decorators, target, key, desc) {
2448
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
2449
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
2450
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
2451
- return c > 3 && r && Object.defineProperty(target, key, r), r;
2452
- }
2453
- __name(_ts_decorate, "_ts_decorate");
2454
3098
  var BridgeActor = class extends ActorV3 {
2455
- static {
2456
- __name(this, "BridgeActor");
2457
- }
2458
- static needs = {
2459
- required: [
2460
- XyoGatewayRunnerMoniker,
2461
- XyoViewerMoniker
2462
- ]
2463
- };
2464
3099
  _gatewayRunner;
2465
3100
  _balanceMonitor;
3101
+ _inFlightPoller;
2466
3102
  _queueMetrics;
2467
3103
  _scannerRunner;
2468
3104
  server;
@@ -2483,15 +3119,17 @@ var BridgeActor = class extends ActorV3 {
2483
3119
  await this._scannerRunner?.stop();
2484
3120
  this._scannerRunner = void 0;
2485
3121
  this._balanceMonitor?.stop();
3122
+ this._inFlightPoller?.stop();
2486
3123
  this._queueMetrics?.stop();
2487
3124
  this._balanceMonitor = void 0;
3125
+ this._inFlightPoller = void 0;
2488
3126
  this._queueMetrics = void 0;
2489
3127
  this.stopServer();
2490
3128
  }
2491
3129
  async startServer() {
2492
3130
  const context = asBridgeConfigContext(this.context, true);
2493
3131
  const config = context.config;
2494
- const { server, services } = await getServer(context, this._gatewayRunner);
3132
+ const { server, services } = await getServer(context, this._gatewayRunner, this.logger, this.meter);
2495
3133
  this.server = server;
2496
3134
  const connection2 = getConnection(config);
2497
3135
  const telemetry2 = getTelemetry();
@@ -2500,7 +3138,6 @@ var BridgeActor = class extends ActorV3 {
2500
3138
  config,
2501
3139
  connection: connection2,
2502
3140
  flowProducer: flowProducer2,
2503
- logger: this.logger,
2504
3141
  services,
2505
3142
  telemetry: telemetry2
2506
3143
  });
@@ -2513,6 +3150,7 @@ var BridgeActor = class extends ActorV3 {
2513
3150
  gateway: services.gateway,
2514
3151
  meter: this.meter,
2515
3152
  provider: services.provider,
3153
+ remoteChainId: config.remoteChainId,
2516
3154
  wallet: services.wallet
2517
3155
  });
2518
3156
  this._balanceMonitor.start();
@@ -2522,9 +3160,16 @@ var BridgeActor = class extends ActorV3 {
2522
3160
  };
2523
3161
  this._queueMetrics = createQueueMetrics({
2524
3162
  meter: this.meter,
2525
- queues
3163
+ queues,
3164
+ remoteChainId: config.remoteChainId
2526
3165
  });
2527
3166
  this._queueMetrics.start();
3167
+ this._inFlightPoller = createInFlightPoller({
3168
+ bridgeFulfillmentMap: services.bridgeFulfillmentMap,
3169
+ meter: this.meter,
3170
+ remoteChainId: config.remoteChainId
3171
+ });
3172
+ this._inFlightPoller.start();
2528
3173
  }
2529
3174
  }
2530
3175
  stopServer() {
@@ -2532,7 +3177,13 @@ var BridgeActor = class extends ActorV3 {
2532
3177
  this.server = void 0;
2533
3178
  }
2534
3179
  };
2535
- BridgeActor = _ts_decorate([
3180
+ __publicField(BridgeActor, "needs", {
3181
+ required: [
3182
+ XyoGatewayRunnerMoniker,
3183
+ XyoViewerMoniker
3184
+ ]
3185
+ });
3186
+ BridgeActor = __decorateClass([
2536
3187
  creatable()
2537
3188
  ], BridgeActor);
2538
3189
 
@@ -2542,7 +3193,7 @@ import { BridgeConfigZod } from "@xyo-network/chain-orchestration";
2542
3193
  // src/run.ts
2543
3194
  import { exists } from "@xylabs/sdk-js";
2544
3195
  import { initActorWallet } from "@xyo-network/chain-orchestration";
2545
- var getBridgeActor = /* @__PURE__ */ __name(async (config, locator) => {
3196
+ var getBridgeActor = async (config, locator) => {
2546
3197
  const account = await initActorWallet({
2547
3198
  config,
2548
3199
  logger: locator.context.logger,
@@ -2554,17 +3205,15 @@ var getBridgeActor = /* @__PURE__ */ __name(async (config, locator) => {
2554
3205
  config,
2555
3206
  locator
2556
3207
  });
2557
- }, "getBridgeActor");
2558
- var runBridge = /* @__PURE__ */ __name(async (config, orchestrator, locator) => {
3208
+ };
3209
+ var runBridge = async (config, orchestrator, locator) => {
2559
3210
  const bridge = await getBridgeActor(config, locator);
2560
- const actors = [
2561
- bridge
2562
- ].filter(exists);
3211
+ const actors = [bridge].filter(exists);
2563
3212
  for (const actor of actors) {
2564
3213
  await orchestrator.registerActor(actor);
2565
3214
  }
2566
3215
  await orchestrator.start();
2567
- }, "runBridge");
3216
+ };
2568
3217
 
2569
3218
  // src/command.ts
2570
3219
  function bridgeCommand(getConfiguration, getLocatorsFromConfig) {
@@ -2572,22 +3221,22 @@ function bridgeCommand(getConfiguration, getLocatorsFromConfig) {
2572
3221
  command: "bridge",
2573
3222
  deprecated: 'Use "start bridge" instead',
2574
3223
  describe: "Run a XL1 Bridge Node",
2575
- handler: /* @__PURE__ */ __name(async () => {
3224
+ handler: async () => {
2576
3225
  const configuration = getConfiguration();
2577
- const { locators, orchestrator } = await getLocatorsFromConfig([
2578
- "bridge"
2579
- ], configuration);
3226
+ const { locators, orchestrator } = await getLocatorsFromConfig(["bridge"], configuration);
2580
3227
  await runBridge(BridgeConfigZod.parse(locators["bridge"].context.config), orchestrator, locators["bridge"]);
2581
- }, "handler")
3228
+ }
2582
3229
  };
2583
3230
  }
2584
- __name(bridgeCommand, "bridgeCommand");
2585
3231
  export {
2586
3232
  BridgeActor,
2587
3233
  bridgeCommand,
3234
+ bucketFailureReason,
2588
3235
  createBalanceMonitor,
3236
+ createBridgeFlowMetrics,
3237
+ createInFlightPoller,
2589
3238
  createQueueMetrics,
2590
3239
  getBridgeActor,
2591
3240
  runBridge
2592
3241
  };
2593
- //# sourceMappingURL=index.mjs.map
3242
+ //# sourceMappingURL=index.mjs.map