@xyo-network/chain-bridge 1.20.4 → 1.20.8

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 (60) hide show
  1. package/dist/node/index.mjs +57 -49
  2. package/dist/node/index.mjs.map +1 -1
  3. package/dist/node/modules/EVMLiquidityBridgeTransactionCompletionMonitorSentinel/EVMLiquidityBridgeTransactionCompletionMonitorSentinel.d.ts +2 -3
  4. package/dist/node/modules/EVMLiquidityBridgeTransactionCompletionMonitorSentinel/EVMLiquidityBridgeTransactionCompletionMonitorSentinel.d.ts.map +1 -1
  5. package/dist/node/queue/flows/createXl1ToEthBridgeJob/createXl1ToEthBridgeJob.d.ts +3 -1
  6. package/dist/node/queue/flows/createXl1ToEthBridgeJob/createXl1ToEthBridgeJob.d.ts.map +1 -1
  7. package/dist/node/queue/workers/EthTransactionMonitor.d.ts +2 -4
  8. package/dist/node/queue/workers/EthTransactionMonitor.d.ts.map +1 -1
  9. package/dist/node/queue/workers/EthTransactionPreparation.d.ts +2 -4
  10. package/dist/node/queue/workers/EthTransactionPreparation.d.ts.map +1 -1
  11. package/dist/node/queue/workers/EthTransactionSubmission.d.ts +2 -4
  12. package/dist/node/queue/workers/EthTransactionSubmission.d.ts.map +1 -1
  13. package/dist/node/queue/workers/EthTransactionSubmissionStorage.d.ts +2 -4
  14. package/dist/node/queue/workers/EthTransactionSubmissionStorage.d.ts.map +1 -1
  15. package/dist/node/queue/workers/Xl1ToEthBridgeParent.d.ts +2 -4
  16. package/dist/node/queue/workers/Xl1ToEthBridgeParent.d.ts.map +1 -1
  17. package/dist/node/queue/workers/Xl1TransactionJobData.d.ts +15 -0
  18. package/dist/node/queue/workers/Xl1TransactionJobData.d.ts.map +1 -0
  19. package/dist/node/queue/workers/Xl1TransactionMonitor.d.ts +2 -4
  20. package/dist/node/queue/workers/Xl1TransactionMonitor.d.ts.map +1 -1
  21. package/dist/node/queue/workers/Xl1TransactionPreparation.d.ts +2 -3
  22. package/dist/node/queue/workers/Xl1TransactionPreparation.d.ts.map +1 -1
  23. package/dist/node/queue/workers/Xl1TransactionSubmission.d.ts +2 -4
  24. package/dist/node/queue/workers/Xl1TransactionSubmission.d.ts.map +1 -1
  25. package/dist/node/queue/workers/Xl1TransactionSubmissionStorage.d.ts +2 -4
  26. package/dist/node/queue/workers/Xl1TransactionSubmissionStorage.d.ts.map +1 -1
  27. package/dist/node/queue/workers/util/submitEthTransaction.d.ts +3 -2
  28. package/dist/node/queue/workers/util/submitEthTransaction.d.ts.map +1 -1
  29. package/dist/node/queue/workers/util/submitXl1Transaction.d.ts +2 -1
  30. package/dist/node/queue/workers/util/submitXl1Transaction.d.ts.map +1 -1
  31. package/dist/node/server/app.d.ts.map +1 -1
  32. package/dist/node/server/routes/bridge/routeDefinitions/routes/bridgeToRemoteStatus.d.ts.map +1 -1
  33. package/dist/node/services/Xl1TxState.d.ts +2 -0
  34. package/dist/node/services/Xl1TxState.d.ts.map +1 -1
  35. package/dist/node/validation/validateSufficientLiquiditySourceAllowance.d.ts +3 -1
  36. package/dist/node/validation/validateSufficientLiquiditySourceAllowance.d.ts.map +1 -1
  37. package/dist/node/validation/validateSufficientLiquiditySourceBalance.d.ts +3 -1
  38. package/dist/node/validation/validateSufficientLiquiditySourceBalance.d.ts.map +1 -1
  39. package/package.json +27 -45
  40. package/src/modules/EVMLiquidityBridgeTransactionCompletionMonitorSentinel/EVMLiquidityBridgeTransactionCompletionMonitorSentinel.ts +5 -4
  41. package/src/queue/flows/createXl1ToEthBridgeJob/createXl1ToEthBridgeJob.ts +23 -9
  42. package/src/queue/workers/EthTransactionMonitor.ts +2 -2
  43. package/src/queue/workers/EthTransactionPreparation.ts +8 -6
  44. package/src/queue/workers/EthTransactionSubmission.ts +4 -5
  45. package/src/queue/workers/EthTransactionSubmissionStorage.ts +2 -2
  46. package/src/queue/workers/Xl1ToEthBridgeParent.ts +2 -2
  47. package/src/queue/workers/Xl1TransactionJobData.ts +12 -0
  48. package/src/queue/workers/Xl1TransactionMonitor.ts +2 -2
  49. package/src/queue/workers/Xl1TransactionPreparation.ts +4 -3
  50. package/src/queue/workers/Xl1TransactionSubmission.ts +7 -8
  51. package/src/queue/workers/Xl1TransactionSubmissionStorage.ts +2 -2
  52. package/src/queue/workers/util/submitEthTransaction.ts +10 -3
  53. package/src/queue/workers/util/submitXl1Transaction.ts +4 -5
  54. package/src/server/app.ts +3 -15
  55. package/src/server/routes/bridge/routeDefinitions/routes/bridgeToRemote.ts +2 -2
  56. package/src/server/routes/bridge/routeDefinitions/routes/bridgeToRemoteStatus.ts +3 -2
  57. package/src/services/Xl1TxState.ts +4 -1
  58. package/src/util/calculateBridgeFees.ts +4 -4
  59. package/src/validation/validateSufficientLiquiditySourceAllowance.ts +5 -1
  60. package/src/validation/validateSufficientLiquiditySourceBalance.ts +5 -1
@@ -1,6 +1,18 @@
1
+ import type { Payload } from '@xyo-network/sdk-js'
1
2
  import type { SignedHydratedTransaction } from '@xyo-network/xl1-sdk'
2
3
  import type { FlowProducer } from 'bullmq'
3
4
 
5
+ import type {
6
+ EthTransactionMonitorJobData,
7
+ EthTransactionPreparationJobData,
8
+ EthTransactionSubmissionJobData,
9
+ EthTransactionSubmissionStorageJobData,
10
+ Xl1ToEthBridgeParentJobData,
11
+ Xl1TransactionMonitorJobData,
12
+ Xl1TransactionPreparationJobData,
13
+ Xl1TransactionSubmissionJobData,
14
+ Xl1TransactionSubmissionStorageJobData,
15
+ } from '../../workers/index.ts'
4
16
  import {
5
17
  EthTransactionMonitor, EthTransactionPreparation, EthTransactionSubmission, EthTransactionSubmissionStorage, Xl1ToEthBridgeParent, Xl1TransactionMonitor,
6
18
  Xl1TransactionPreparation, Xl1TransactionSubmission, Xl1TransactionSubmissionStorage,
@@ -11,25 +23,27 @@ import { getJobIdForXl1ToEthBridgeJob } from './getJobIdForXl1ToEthBridgeJob.ts'
11
23
  * Creates a job flow for bridging a transaction from XL1 to Ethereum.
12
24
  * @param flowProducer The flow producer to run the job
13
25
  * @param tx The bridge transaction
26
+ * @param offChainPayloads The payloads to put off chain
14
27
  * @returns The JobNode representing the XL1 to ETH bridge job
15
28
  */
16
29
  export const createXl1ToEthBridgeJob = async (
17
30
  flowProducer: FlowProducer,
18
31
  tx: SignedHydratedTransaction,
32
+ offChainPayloads: Payload[] = [],
19
33
  ) => {
20
34
  const jobId = await getJobIdForXl1ToEthBridgeJob(tx)
21
35
  const flow = await flowProducer.add({
22
36
  // Step 0 (runs first as parent job)
23
37
  name: Xl1ToEthBridgeParent.name,
24
38
  queueName: Xl1ToEthBridgeParent.queueName,
25
- data: { tx },
39
+ data: { tx, offChainPayloads } as Xl1ToEthBridgeParentJobData,
26
40
  opts: { jobId },
27
41
  children: [
28
42
  {
29
43
  // Step 8
30
44
  name: EthTransactionMonitor.name,
31
45
  queueName: EthTransactionMonitor.queueName,
32
- data: { tx },
46
+ data: { tx } as EthTransactionMonitorJobData,
33
47
  opts: {
34
48
  jobId, attempts: 60, backoff: { type: 'fixed', delay: 5000 },
35
49
  },
@@ -38,7 +52,7 @@ export const createXl1ToEthBridgeJob = async (
38
52
  // Step 7
39
53
  name: EthTransactionSubmissionStorage.name,
40
54
  queueName: EthTransactionSubmissionStorage.queueName,
41
- data: { tx },
55
+ data: { tx } as EthTransactionSubmissionStorageJobData,
42
56
  opts: {
43
57
  jobId, attempts: 60, backoff: { type: 'fixed', delay: 5000 },
44
58
  },
@@ -47,14 +61,14 @@ export const createXl1ToEthBridgeJob = async (
47
61
  // Step 6
48
62
  name: EthTransactionSubmission.name,
49
63
  queueName: EthTransactionSubmission.queueName,
50
- data: { tx },
64
+ data: { tx, offChainPayloads } as EthTransactionSubmissionJobData,
51
65
  opts: { jobId },
52
66
  children: [
53
67
  {
54
68
  // Step 5
55
69
  name: EthTransactionPreparation.name,
56
70
  queueName: EthTransactionPreparation.queueName,
57
- data: { tx },
71
+ data: { tx, offChainPayloads } as EthTransactionPreparationJobData,
58
72
  opts: {
59
73
  jobId, attempts: 60, backoff: { type: 'fixed', delay: 5000 },
60
74
  },
@@ -63,7 +77,7 @@ export const createXl1ToEthBridgeJob = async (
63
77
  // Step 4
64
78
  name: Xl1TransactionMonitor.name,
65
79
  queueName: Xl1TransactionMonitor.queueName,
66
- data: { tx },
80
+ data: { tx } as Xl1TransactionMonitorJobData,
67
81
  opts: {
68
82
  jobId, attempts: 60, backoff: { type: 'fixed', delay: 5000 },
69
83
  },
@@ -72,7 +86,7 @@ export const createXl1ToEthBridgeJob = async (
72
86
  // Step 3
73
87
  name: Xl1TransactionSubmissionStorage.name,
74
88
  queueName: Xl1TransactionSubmissionStorage.queueName,
75
- data: { tx },
89
+ data: { tx } as Xl1TransactionSubmissionStorageJobData,
76
90
  opts: {
77
91
  jobId, attempts: 60, backoff: { type: 'fixed', delay: 5000 },
78
92
  },
@@ -81,14 +95,14 @@ export const createXl1ToEthBridgeJob = async (
81
95
  // Step 2
82
96
  name: Xl1TransactionSubmission.name,
83
97
  queueName: Xl1TransactionSubmission.queueName,
84
- data: { tx },
98
+ data: { tx } as Xl1TransactionSubmissionJobData,
85
99
  opts: { jobId },
86
100
  children: [
87
101
  {
88
102
  // Step 1 (runs first as deepest child)
89
103
  name: Xl1TransactionPreparation.name,
90
104
  queueName: Xl1TransactionPreparation.queueName,
91
- data: { tx },
105
+ data: { tx, offChainPayloads } as Xl1TransactionPreparationJobData,
92
106
  opts: {
93
107
  jobId, attempts: 60, backoff: { type: 'fixed', delay: 5000 },
94
108
  },
@@ -1,6 +1,5 @@
1
1
  import { assertEx } from '@xylabs/sdk-js'
2
2
  import { PayloadBuilder } from '@xyo-network/sdk-js'
3
- import type { SignedHydratedTransaction } from '@xyo-network/xl1-sdk'
4
3
  import type { Job } from 'bullmq'
5
4
  import { Worker } from 'bullmq'
6
5
  import type { BullMQOtel } from 'bullmq-otel'
@@ -9,8 +8,9 @@ import type { Redis } from 'ioredis'
9
8
  import type { IBridgeServiceCollection } from '../../services/index.ts'
10
9
  import { prefix } from '../prefix.ts'
11
10
  import type { WorkerDescription } from './WorkerDescription.ts'
11
+ import type { Xl1TransactionJobData } from './Xl1TransactionJobData.ts'
12
12
 
13
- export type EthTransactionMonitorJobData = { tx: SignedHydratedTransaction }
13
+ export type EthTransactionMonitorJobData = Xl1TransactionJobData
14
14
  export interface EthTransactionMonitorJobReturn {
15
15
  blockHash: string
16
16
  blockNumber: number
@@ -1,6 +1,6 @@
1
1
  import { assertEx, hexToBigInt } from '@xylabs/sdk-js'
2
2
  import { PayloadBuilder } from '@xyo-network/sdk-js'
3
- import { isBridgeIntent, type SignedHydratedTransaction } from '@xyo-network/xl1-sdk'
3
+ import { isBridgeIntent } from '@xyo-network/xl1-sdk'
4
4
  import type { Job } from 'bullmq'
5
5
  import { Worker } from 'bullmq'
6
6
  import type { BullMQOtel } from 'bullmq-otel'
@@ -13,8 +13,9 @@ import {
13
13
  } from '../../validation/index.ts'
14
14
  import { prefix } from '../prefix.ts'
15
15
  import type { WorkerDescription } from './WorkerDescription.ts'
16
+ import type { Xl1DataLakeTransactionJobData } from './Xl1TransactionJobData.ts'
16
17
 
17
- export type EthTransactionPreparationJobData = { tx: SignedHydratedTransaction }
18
+ export type EthTransactionPreparationJobData = Xl1DataLakeTransactionJobData
18
19
  export type EthTransactionPreparationJobReturn = Record<string, never>
19
20
  export type EthTransactionPreparationJob = Job<EthTransactionPreparationJobData, EthTransactionPreparationJobReturn>
20
21
 
@@ -30,21 +31,22 @@ export const createWorker = (connection: Redis, telemetry?: BullMQOtel, services
30
31
  const worker = new Worker(
31
32
  queueName,
32
33
  async (job: EthTransactionPreparationJob) => {
33
- const { tx } = job.data
34
+ const { tx, offChainPayloads } = job.data
34
35
  const hash = await PayloadBuilder.hash(tx[0])
35
36
  await job.log(`[${hash}] preparing ETH transaction`)
36
37
  await job.log(`[${hash}] validating liquiditySource has sufficient allowance`)
37
- if (!await validateSufficientLiquiditySourceAllowance(tx, bridgeableToken, bridge, job)) {
38
+ if (!await validateSufficientLiquiditySourceAllowance(tx, offChainPayloads, bridgeableToken, bridge, job)) {
38
39
  throw new Error('Liquidity source does not have sufficient allowance for the bridge to execute the transaction')
39
40
  }
40
41
  await job.log(`[${hash}] validated liquiditySource has sufficient allowance`)
41
42
  await job.log(`[${hash}] validating liquiditySource has sufficient balance`)
42
- if (!await validateSufficientLiquiditySourceBalance(tx, bridgeableToken, bridge, job)) {
43
+ if (!await validateSufficientLiquiditySourceBalance(tx, offChainPayloads, bridgeableToken, bridge, job)) {
43
44
  throw new Error('Liquidity source does not have sufficient balance for the bridge to execute the transaction')
44
45
  }
45
46
  await job.log(`[${hash}] validated liquiditySource has sufficient balance`)
46
47
  await job.log(`[${hash}] building ETH transaction`)
47
- const bridgeIntent = assertEx(tx[1].find(isBridgeIntent), () => 'No bridge intent found')
48
+ const allPayloads = [...tx[1], ...offChainPayloads]
49
+ const bridgeIntent = assertEx(allPayloads.find(isBridgeIntent), () => 'No bridge intent found')
48
50
  const amount = hexToBigInt(bridgeIntent.destAmount)
49
51
  const srcAddress = getAddress(bridgeIntent.srcAddress)
50
52
  const destAddress = getAddress(bridgeIntent.destAddress)
@@ -1,6 +1,5 @@
1
1
  import { assertEx, isDefined } from '@xylabs/sdk-js'
2
2
  import { PayloadBuilder } from '@xyo-network/sdk-js'
3
- import { type SignedHydratedTransaction } from '@xyo-network/xl1-sdk'
4
3
  import type { Job } from 'bullmq'
5
4
  import { Worker } from 'bullmq'
6
5
  import type { BullMQOtel } from 'bullmq-otel'
@@ -10,8 +9,9 @@ import type { EthTxState, IBridgeServiceCollection } from '../../services/index.
10
9
  import { prefix } from '../prefix.ts'
11
10
  import { submitEthTransaction } from './util/index.ts'
12
11
  import type { WorkerDescription } from './WorkerDescription.ts'
12
+ import type { Xl1DataLakeTransactionJobData } from './Xl1TransactionJobData.ts'
13
13
 
14
- export type EthTransactionSubmissionJobData = { tx: SignedHydratedTransaction }
14
+ export type EthTransactionSubmissionJobData = Xl1DataLakeTransactionJobData
15
15
  export interface EthTransactionSubmissionJobReturn {
16
16
  submissionHash: Required<EthTxState>['submissionHash']
17
17
  }
@@ -21,14 +21,13 @@ const name = 'Submit ETH Transaction'
21
21
  const queueName = 'eth-tx-submit'
22
22
  const createWorker = (connection: Redis, telemetry?: BullMQOtel, services?: IBridgeServiceCollection) => {
23
23
  const bridge = assertEx(services?.bridge, () => 'bridge service not provided')
24
- const bridgeableToken = assertEx(services?.bridgeableToken, () => 'bridgeableToken service not provided')
25
24
  const wallet = assertEx(services?.wallet, () => 'wallet service not provided')
26
25
  const stateMap = assertEx(services?.ethTxStateMap, () => 'ethTxStateMap service not provided')
27
26
 
28
27
  const worker = new Worker(
29
28
  queueName,
30
29
  async (job: EthTransactionSubmissionJob) => {
31
- const { tx } = job.data
30
+ const { tx, offChainPayloads } = job.data
32
31
  const hash = await PayloadBuilder.hash(tx[0])
33
32
  const state = assertEx(await stateMap.get(hash), () => `[${hash}] state not found`)
34
33
 
@@ -41,7 +40,7 @@ const createWorker = (connection: Redis, telemetry?: BullMQOtel, services?: IBri
41
40
 
42
41
  // Submit the transaction to the Ethereum network
43
42
  await job.log(`[${hash}] Submitting ETH tx`)
44
- const submissionHash = assertEx(await submitEthTransaction(tx, bridgeableToken, bridge, wallet), () => `[${hash}] submissionHash not found in receipt`)
43
+ const submissionHash = assertEx(await submitEthTransaction(tx, offChainPayloads, bridge, wallet), () => `[${hash}] submissionHash not found in receipt`)
45
44
  await job.log(`[${hash}] Submitted ETH tx and received submission response hash ${submissionHash}`)
46
45
  return { submissionHash }
47
46
  },
@@ -1,6 +1,5 @@
1
1
  import { assertEx, isDefined } from '@xylabs/sdk-js'
2
2
  import { PayloadBuilder } from '@xyo-network/sdk-js'
3
- import type { SignedHydratedTransaction } from '@xyo-network/xl1-sdk'
4
3
  import type { Job } from 'bullmq'
5
4
  import { Worker } from 'bullmq'
6
5
  import type { BullMQOtel } from 'bullmq-otel'
@@ -11,8 +10,9 @@ import { prefix } from '../prefix.ts'
11
10
  import type { EthTransactionSubmissionJobReturn } from './EthTransactionSubmission.ts'
12
11
  import { EthTransactionSubmission } from './EthTransactionSubmission.ts'
13
12
  import type { WorkerDescription } from './WorkerDescription.ts'
13
+ import type { Xl1TransactionJobData } from './Xl1TransactionJobData.ts'
14
14
 
15
- export type EthTransactionSubmissionStorageJobData = { tx: SignedHydratedTransaction }
15
+ export type EthTransactionSubmissionStorageJobData = Xl1TransactionJobData
16
16
  export interface EthTransactionSubmissionStorageJobReturn {
17
17
  submissionHash: Required<EthTxState>['submissionHash']
18
18
  }
@@ -1,4 +1,3 @@
1
- import type { SignedHydratedTransaction } from '@xyo-network/xl1-sdk'
2
1
  import type { Job } from 'bullmq'
3
2
  import { Worker } from 'bullmq'
4
3
  import type { BullMQOtel } from 'bullmq-otel'
@@ -6,8 +5,9 @@ import type { Redis } from 'ioredis'
6
5
 
7
6
  import { prefix } from '../prefix.ts'
8
7
  import type { WorkerDescription } from './WorkerDescription.ts'
8
+ import type { Xl1DataLakeTransactionJobData } from './Xl1TransactionJobData.ts'
9
9
 
10
- export type Xl1ToEthBridgeParentJobData = { tx: SignedHydratedTransaction }
10
+ export type Xl1ToEthBridgeParentJobData = Xl1DataLakeTransactionJobData
11
11
  export interface Xl1ToEthBridgeParentJobReturn { }
12
12
  export type Xl1ToEthBridgeParentJob = Job<Xl1ToEthBridgeParentJobData, Xl1ToEthBridgeParentJobReturn>
13
13
 
@@ -0,0 +1,12 @@
1
+ import type { Payload } from '@xyo-network/sdk-js'
2
+ import type { SignedHydratedTransaction } from '@xyo-network/xl1-sdk'
3
+
4
+ /**
5
+ * Represents the data required for a job that requires an XL1 transaction.
6
+ */
7
+ export type Xl1TransactionJobData = { tx: SignedHydratedTransaction }
8
+
9
+ /**
10
+ * Represents the data required for a job that requires an XL1 transaction and its associated off-chain payloads.
11
+ */
12
+ export type Xl1DataLakeTransactionJobData = Xl1TransactionJobData & { offChainPayloads: Payload[] }
@@ -3,7 +3,6 @@ import {
3
3
  assertEx, isDefined, isNull,
4
4
  } from '@xylabs/sdk-js'
5
5
  import { PayloadBuilder } from '@xyo-network/sdk-js'
6
- import type { SignedHydratedTransaction } from '@xyo-network/xl1-sdk'
7
6
  import type { Job } from 'bullmq'
8
7
  import { UnrecoverableError, Worker } from 'bullmq'
9
8
  import type { BullMQOtel } from 'bullmq-otel'
@@ -12,8 +11,9 @@ import type { Redis } from 'ioredis'
12
11
  import type { IBridgeServiceCollection } from '../../services/index.ts'
13
12
  import { prefix } from '../prefix.ts'
14
13
  import type { WorkerDescription } from './WorkerDescription.ts'
14
+ import type { Xl1TransactionJobData } from './Xl1TransactionJobData.ts'
15
15
 
16
- export type Xl1TransactionMonitorJobData = { tx: SignedHydratedTransaction }
16
+ export type Xl1TransactionMonitorJobData = Xl1TransactionJobData
17
17
  export interface Xl1TransactionMonitorJobReturn {
18
18
  submissionHash: BrandedHash
19
19
  }
@@ -9,8 +9,9 @@ import type { Redis } from 'ioredis'
9
9
  import type { IBridgeServiceCollection } from '../../services/index.ts'
10
10
  import { prefix } from '../prefix.ts'
11
11
  import type { WorkerDescription } from './WorkerDescription.ts'
12
+ import type { Xl1DataLakeTransactionJobData } from './Xl1TransactionJobData.ts'
12
13
 
13
- export type Xl1TransactionPreparationJobData = { tx: SignedHydratedTransaction }
14
+ export type Xl1TransactionPreparationJobData = Xl1DataLakeTransactionJobData
14
15
  export interface Xl1TransactionPreparationJobReturn { preparedTx: SignedHydratedTransaction }
15
16
  export type Xl1TransactionPreparationJob = Job<Xl1TransactionPreparationJobData, Xl1TransactionPreparationJobReturn>
16
17
 
@@ -22,12 +23,12 @@ const createWorker = (connection: Redis, telemetry?: BullMQOtel, services?: IBri
22
23
  const worker = new Worker(
23
24
  queueName,
24
25
  async (job: Xl1TransactionPreparationJob) => {
25
- const { tx } = job.data
26
+ const { tx, offChainPayloads = [] } = job.data
26
27
  const hash = await PayloadBuilder.hash(tx[0])
27
28
  await job.log(`[${hash}] preparing XL1 transaction`)
28
29
  const preparedTx = tx
29
30
  await job.log(`[${hash}] storing XL1 preparedTx`)
30
- await stateMap.set(hash, { preparedTx })
31
+ await stateMap.set(hash, { offChainPayloads, preparedTx })
31
32
  await job.log(`[${hash}] stored XL1 preparedTx`)
32
33
  await job.log(`[${hash}] prepared XL1 transaction`)
33
34
  return { preparedTx }
@@ -1,6 +1,5 @@
1
1
  import { assertEx, isDefined } from '@xylabs/sdk-js'
2
2
  import { PayloadBuilder } from '@xyo-network/sdk-js'
3
- import { type SignedHydratedTransaction } from '@xyo-network/xl1-sdk'
4
3
  import type { Job } from 'bullmq'
5
4
  import { Worker } from 'bullmq'
6
5
  import type { BullMQOtel } from 'bullmq-otel'
@@ -10,8 +9,9 @@ import type { IBridgeServiceCollection, Xl1TxState } from '../../services/index.
10
9
  import { prefix } from '../prefix.ts'
11
10
  import { submitXl1Transaction } from './util/index.ts'
12
11
  import type { WorkerDescription } from './WorkerDescription.ts'
12
+ import type { Xl1TransactionJobData } from './Xl1TransactionJobData.ts'
13
13
 
14
- export type Xl1TransactionSubmissionJobData = { tx: SignedHydratedTransaction }
14
+ export type Xl1TransactionSubmissionJobData = Xl1TransactionJobData
15
15
  export interface Xl1TransactionSubmissionJobReturn {
16
16
  submissionHash: Required<Xl1TxState>['submissionHash']
17
17
  }
@@ -32,21 +32,20 @@ const createWorker = (connection: Redis, telemetry?: BullMQOtel, services?: IBri
32
32
  const hash = await PayloadBuilder.hash(tx[0])
33
33
  // Get the state of the transaction
34
34
  const state = assertEx(await stateMap.get(hash), () => `[${hash}] state not found`)
35
- const preparedTx = assertEx(state?.preparedTx, () => `[${hash}] preparedTx not found`)
35
+ const {
36
+ preparedTx, offChainPayloads = [], submissionHash: existingSubmissionHash,
37
+ } = state
36
38
 
37
39
  // Idempotency check against resubmission
38
- const { submissionHash: existingSubmissionHash } = state
39
40
  if (isDefined(existingSubmissionHash)) {
40
41
  await job.log(`[${hash}] Tx already submitted with submission response hash ${existingSubmissionHash}`)
41
42
  return { submissionHash: existingSubmissionHash }
42
43
  }
44
+ const txToSubmit = assertEx(preparedTx, () => `[${hash}] preparedTx not found`)
43
45
 
44
46
  // Submit the transaction to the XL1 network
45
47
  await job.log(`[${hash}] Submitting XL1 tx`)
46
- const [submissionHash] = await submitXl1Transaction(preparedTx, gateway)
47
-
48
- // Ensure the submission hash matches the expected hash
49
- // assertEx(submissionHash === hash, () => `[${hash}] Submitted transaction hash ${submissionHash} does not match expected hash`)
48
+ const [submissionHash] = await submitXl1Transaction(txToSubmit, offChainPayloads, gateway)
50
49
  await job.log(`[${hash}] Submitted XL1 tx`)
51
50
 
52
51
  // This worker intentionally does NOT store state as subsequent steps will do that.
@@ -1,6 +1,5 @@
1
1
  import { assertEx, isDefined } from '@xylabs/sdk-js'
2
2
  import { PayloadBuilder } from '@xyo-network/sdk-js'
3
- import { type SignedHydratedTransaction } from '@xyo-network/xl1-sdk'
4
3
  import type { Job } from 'bullmq'
5
4
  import { Worker } from 'bullmq'
6
5
  import type { BullMQOtel } from 'bullmq-otel'
@@ -9,10 +8,11 @@ import type { Redis } from 'ioredis'
9
8
  import type { IBridgeServiceCollection, Xl1TxState } from '../../services/index.ts'
10
9
  import { prefix } from '../prefix.ts'
11
10
  import type { WorkerDescription } from './WorkerDescription.ts'
11
+ import type { Xl1TransactionJobData } from './Xl1TransactionJobData.ts'
12
12
  import type { Xl1TransactionSubmissionJobReturn } from './Xl1TransactionSubmission.ts'
13
13
  import { Xl1TransactionSubmission } from './Xl1TransactionSubmission.ts'
14
14
 
15
- export type Xl1TransactionSubmissionStorageJobData = { tx: SignedHydratedTransaction }
15
+ export type Xl1TransactionSubmissionStorageJobData = Xl1TransactionJobData
16
16
  export interface Xl1TransactionSubmissionStorageJobReturn {
17
17
  submissionHash: Required<Xl1TxState>['submissionHash']
18
18
  }
@@ -1,15 +1,22 @@
1
1
  import {
2
2
  assertEx, hexToBigInt, toEthAddress,
3
3
  } from '@xylabs/sdk-js'
4
+ import type { Payload } from '@xyo-network/sdk-js'
4
5
  import { PayloadBuilder } from '@xyo-network/sdk-js'
5
- import type { BridgeableToken, LiquidityPoolBridge } from '@xyo-network/typechain'
6
+ import type { LiquidityPoolBridge } from '@xyo-network/typechain'
6
7
  import { isBridgeIntent, type SignedHydratedTransaction } from '@xyo-network/xl1-sdk'
7
8
  import type { Wallet } from 'ethers'
8
9
 
9
- export const submitEthTransaction = async (tx: SignedHydratedTransaction, bridgeableToken: BridgeableToken, bridge: LiquidityPoolBridge, wallet: Wallet) => {
10
+ export const submitEthTransaction = async (
11
+ tx: SignedHydratedTransaction,
12
+ offChainPayloads: Payload[],
13
+ bridge: LiquidityPoolBridge,
14
+ wallet: Wallet,
15
+ ) => {
10
16
  // Approve the bridge to spend tokens
11
17
  const xl1Transaction = assertEx(tx[0], () => 'No corresponding XL1 transaction found')
12
- const bridgeIntent = assertEx(tx[1].find(isBridgeIntent), () => 'No bridge intent found')
18
+ const allPayloads = [...tx[1], ...offChainPayloads]
19
+ const bridgeIntent = assertEx(allPayloads.find(isBridgeIntent), () => 'No bridge intent found')
13
20
  const srcAddress = toEthAddress(bridgeIntent.srcAddress)
14
21
  const destAddress = toEthAddress(bridgeIntent.destAddress)
15
22
  const amount = hexToBigInt(bridgeIntent.destAmount)
@@ -1,10 +1,10 @@
1
1
  import { type BrandedHash } from '@xylabs/sdk-js'
2
- import {
3
- isAllowedBlockPayload, type SignedHydratedTransaction, type XyoGatewayRunner,
4
- } from '@xyo-network/xl1-sdk'
2
+ import type { Payload } from '@xyo-network/sdk-js'
3
+ import { type SignedHydratedTransaction, type XyoGatewayRunner } from '@xyo-network/xl1-sdk'
5
4
 
6
5
  export const submitXl1Transaction = async (
7
6
  preparedTx: SignedHydratedTransaction,
7
+ offChain: Payload[] = [],
8
8
  gateway: XyoGatewayRunner,
9
9
  ): Promise<[BrandedHash, SignedHydratedTransaction]> => {
10
10
  // Option 1: Add payloads to chain with addPayloadsToChain
@@ -16,8 +16,7 @@ export const submitXl1Transaction = async (
16
16
 
17
17
  // Option 2: Add transaction to chain with addTransactionToChain
18
18
  // Fails due to resigning of transaction in addTransactionToChain, which causes `from` to be invalid
19
- const offChainPayloads = preparedTx[1].filter(p => !isAllowedBlockPayload(p))
20
- const result = await gateway.addTransactionToChain(preparedTx, offChainPayloads)
19
+ const result = await gateway.addTransactionToChain(preparedTx, offChain)
21
20
  return result
22
21
 
23
22
  // Option 3: Add transaction to chain with addTransactionToChain, but bypass resigning by passing the preparedTx as an unsigned transaction
package/src/server/app.ts CHANGED
@@ -1,11 +1,7 @@
1
- import {
2
- customPoweredByHeader, disableCaseSensitiveRouting, disableExpressDefaultPoweredByHeader, getJsonBodyParser, getJsonBodyParserOptions, responseProfiler,
3
- standardErrors, standardResponses,
4
- } from '@xylabs/express'
1
+ import { standardErrors } from '@xylabs/express'
5
2
  import type { BridgeConfig } from '@xyo-network/chain-orchestration'
3
+ import { sharedMiddleware } from '@xyo-network/chain-orchestration'
6
4
  import type { XyoGatewayRunner } from '@xyo-network/xl1-sdk'
7
- import compression from 'compression'
8
- import cors from 'cors'
9
5
  import type { Express } from 'express'
10
6
  import express from 'express'
11
7
 
@@ -16,15 +12,7 @@ import { addRoutes } from './routes/index.ts'
16
12
  export const getApp = (config: BridgeConfig, gateway: XyoGatewayRunner): Express => {
17
13
  addInstrumentation()
18
14
  const app = express()
19
- app.set('etag', false)
20
- app.use(cors())
21
- app.use(compression())
22
- app.use(responseProfiler)
23
- app.use(getJsonBodyParser(getJsonBodyParserOptions({ limit: '1mb' })))
24
- app.use(standardResponses)
25
- disableExpressDefaultPoweredByHeader(app)
26
- app.use(customPoweredByHeader)
27
- disableCaseSensitiveRouting(app)
15
+ sharedMiddleware(app)
28
16
  addFlowProducer(app, config)
29
17
  addRoutes(app, config, gateway)
30
18
  app.use(standardErrors)
@@ -65,7 +65,7 @@ export const makeBridgeToRemoteRoute = (config: BridgeConfig): RouteDefinition =
65
65
  }
66
66
 
67
67
  // Create the signed hydrated transaction for the job
68
- const singedHydratedTransaction: SignedHydratedTransaction = [signedTxBw, [transfer, bridgeIntent]]
68
+ const singedHydratedTransaction: SignedHydratedTransaction = [signedTxBw, [transfer]]
69
69
 
70
70
  // Check if a job already exists for this transaction
71
71
  const existingFlow = await getXl1ToEthBridgeJob(flowProducer, singedHydratedTransaction)
@@ -75,7 +75,7 @@ export const makeBridgeToRemoteRoute = (config: BridgeConfig): RouteDefinition =
75
75
  }
76
76
 
77
77
  // Submit to job queue
78
- await createXl1ToEthBridgeJob(flowProducer, singedHydratedTransaction)
78
+ await createXl1ToEthBridgeJob(flowProducer, singedHydratedTransaction, [bridgeIntent])
79
79
 
80
80
  // Create BridgeObservation
81
81
  const srcConfirmation = await PayloadBuilder.hash(signedTxBw)
@@ -49,13 +49,14 @@ export const makeBridgeToRemoteStatusRoute = (config: BridgeConfig): RouteDefini
49
49
  const statusQueueJobs = await getStatusQueueJobs(queues, jobId)
50
50
 
51
51
  // Check for the transaction hash in the parent job
52
- const tx = statusQueueJobs.xl1ToEthBridgeParentJob?.data?.tx
52
+ const { tx, offChainPayloads = [] } = statusQueueJobs.xl1ToEthBridgeParentJob?.data ?? {}
53
53
 
54
54
  // If the job does not exist return Not Found
55
55
  if (!tx) return res.sendStatus(404)
56
56
 
57
57
  // If the tx is not the right shape for bridging return Not Found
58
- const bridgeIntent = tx[1].find(isBridgeIntent)
58
+ const allPayloads = [...tx[1], ...offChainPayloads]
59
+ const bridgeIntent = allPayloads.find(isBridgeIntent)
59
60
  if (!bridgeIntent) return res.sendStatus(404)
60
61
 
61
62
  // At this point we know we have a valid bridge intent, so we can start building the response
@@ -1,6 +1,9 @@
1
1
  import type { Hash } from '@xylabs/sdk-js'
2
+ import type { Payload } from '@xyo-network/sdk-js'
2
3
  import type { SignedHydratedTransaction } from '@xyo-network/xl1-sdk'
3
4
 
4
5
  import type { TxState } from './TxState.ts'
5
6
 
6
- export interface Xl1TxState extends TxState<SignedHydratedTransaction, Hash, Hash> {}
7
+ export interface Xl1TxState extends TxState<SignedHydratedTransaction, Hash, Hash> {
8
+ offChainPayloads?: Payload[]
9
+ }
@@ -13,7 +13,7 @@ export const calculateBridgeFees = (srcAmount: Hex, feeStructure: FeeStructure):
13
13
  const srcAmountBigInt = hexToBigInt(srcAmount)
14
14
 
15
15
  // Calculate fixed fee
16
- const feeFixedBigInt = hexToBigInt(feeFixed)
16
+ // const feeFixedBigInt = hexToBigInt(feeFixed)
17
17
 
18
18
  // Integer-safe basis point calculation (floor division)
19
19
  const feeVariableBigInt
@@ -21,11 +21,11 @@ export const calculateBridgeFees = (srcAmount: Hex, feeStructure: FeeStructure):
21
21
  const feeVariable = toHex(feeVariableBigInt)
22
22
 
23
23
  // Calculate total fee
24
- const feeTotalBigInt = feeFixedBigInt + feeVariableBigInt
24
+ // const feeTotalBigInt = feeFixedBigInt + feeVariableBigInt
25
25
 
26
26
  // Calculate destination amount
27
- const destAmountBigInt = srcAmountBigInt > feeTotalBigInt ? srcAmountBigInt - feeTotalBigInt : 0n
28
- const destAmount = toHex(destAmountBigInt)
27
+ // const destAmountBigInt = srcAmountBigInt > feeTotalBigInt ? srcAmountBigInt - feeTotalBigInt : 0n
28
+ // const destAmount = toHex(destAmountBigInt)
29
29
 
30
30
  return {
31
31
  feeFixed, feeVariable, srcAmount,
@@ -1,4 +1,5 @@
1
1
  import { assertEx, hexToBigInt } from '@xylabs/sdk-js'
2
+ import type { Payload } from '@xyo-network/sdk-js'
2
3
  import type { BridgeableToken, LiquidityPoolBridge } from '@xyo-network/typechain'
3
4
  import { isBridgeIntent, type SignedHydratedTransaction } from '@xyo-network/xl1-sdk'
4
5
 
@@ -9,6 +10,7 @@ import type { AsyncLogger } from './AsyncLogger.ts'
9
10
  * ensure that (due to race conditions) the transaction will succeed, but is a quick check to avoid
10
11
  * submitting transactions that are likely to fail.
11
12
  * @param tx The transaction containing a bridge intent
13
+ * @param offChainPayloads The payloads to put off chain
12
14
  * @param bridgeableToken The contract for the token being bridged
13
15
  * @param bridge The contract for the liquidity bridge
14
16
  * @param logger Optional logger for asynchronous logging
@@ -16,12 +18,14 @@ import type { AsyncLogger } from './AsyncLogger.ts'
16
18
  */
17
19
  export const validateSufficientLiquiditySourceAllowance = async (
18
20
  tx: SignedHydratedTransaction,
21
+ offChainPayloads: Payload[],
19
22
  bridgeableToken: BridgeableToken,
20
23
  bridge: LiquidityPoolBridge,
21
24
  logger?: AsyncLogger,
22
25
  ) => {
23
26
  // Get the amount being bridged from the bridge intent
24
- const bridgeIntent = assertEx(tx[1].find(isBridgeIntent), () => 'No bridge intent found')
27
+ const allPayloads = [...tx[1], ...offChainPayloads]
28
+ const bridgeIntent = assertEx(allPayloads.find(isBridgeIntent), () => 'No bridge intent found')
25
29
  const amount = hexToBigInt(bridgeIntent.destAmount)
26
30
 
27
31
  // Get the addresses
@@ -1,4 +1,5 @@
1
1
  import { assertEx, hexToBigInt } from '@xylabs/sdk-js'
2
+ import type { Payload } from '@xyo-network/sdk-js'
2
3
  import type { BridgeableToken, LiquidityPoolBridge } from '@xyo-network/typechain'
3
4
  import { isBridgeIntent, type SignedHydratedTransaction } from '@xyo-network/xl1-sdk'
4
5
 
@@ -9,6 +10,7 @@ import type { AsyncLogger } from './AsyncLogger.ts'
9
10
  * ensure that (due to race conditions) the transaction will succeed, but is a quick check to avoid
10
11
  * submitting transactions that are likely to fail.
11
12
  * @param tx The transaction containing a bridge intent
13
+ * @param offChainPayloads The payloads to put off chain
12
14
  * @param bridgeableToken The contract for the token being bridged
13
15
  * @param bridge The contract for the liquidity bridge
14
16
  * @param logger Optional logger for asynchronous logging
@@ -16,12 +18,14 @@ import type { AsyncLogger } from './AsyncLogger.ts'
16
18
  */
17
19
  export const validateSufficientLiquiditySourceBalance = async (
18
20
  tx: SignedHydratedTransaction,
21
+ offChainPayloads: Payload[],
19
22
  bridgeableToken: BridgeableToken,
20
23
  bridge: LiquidityPoolBridge,
21
24
  logger?: AsyncLogger,
22
25
  ) => {
23
26
  // Get the amount being bridged from the bridge intent
24
- const bridgeIntent = assertEx(tx[1].find(isBridgeIntent), () => 'No bridge intent found')
27
+ const allPayloads = [...tx[1], ...offChainPayloads]
28
+ const bridgeIntent = assertEx(allPayloads.find(isBridgeIntent), () => 'No bridge intent found')
25
29
  const amount = hexToBigInt(bridgeIntent.destAmount)
26
30
 
27
31
  // Get the addresses