@xyo-network/chain-bridge 1.20.15 → 1.20.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (147) hide show
  1. package/README.md +9 -75
  2. package/dist/node/index.mjs +44 -0
  3. package/dist/node/index.mjs.map +1 -1
  4. package/dist/node/queue/flows/createXl1ToEthBridgeJob/getJobIdForXl1ToEthBridgeJob.d.ts +1 -1
  5. package/dist/node/queue/flows/createXl1ToEthBridgeJob/getJobIdForXl1ToEthBridgeJob.d.ts.map +1 -1
  6. package/dist/node/server/routes/addProbeRoutes.d.ts +3 -0
  7. package/dist/node/server/routes/addProbeRoutes.d.ts.map +1 -0
  8. package/dist/node/server/routes/addRoutes.d.ts.map +1 -1
  9. package/dist/node/server/routes/bridge/routeDefinitions/routes/bridgeConfig.d.ts +7 -7
  10. package/dist/node/server/routes/{healthz → livez}/get.d.ts +1 -1
  11. package/dist/node/server/routes/livez/get.d.ts.map +1 -0
  12. package/dist/node/server/routes/livez/index.d.ts.map +1 -0
  13. package/dist/node/server/routes/readyz/get.d.ts +4 -0
  14. package/dist/node/server/routes/readyz/get.d.ts.map +1 -0
  15. package/dist/node/server/routes/readyz/index.d.ts +2 -0
  16. package/dist/node/server/routes/readyz/index.d.ts.map +1 -0
  17. package/dist/node/server/routes/startupz/get.d.ts +4 -0
  18. package/dist/node/server/routes/startupz/get.d.ts.map +1 -0
  19. package/dist/node/server/routes/startupz/index.d.ts +2 -0
  20. package/dist/node/server/routes/startupz/index.d.ts.map +1 -0
  21. package/package.json +141 -52
  22. package/dist/node/server/routes/healthz/get.d.ts.map +0 -1
  23. package/dist/node/server/routes/healthz/index.d.ts.map +0 -1
  24. package/src/BridgeActor.ts +0 -51
  25. package/src/config/asChainId.ts +0 -7
  26. package/src/config/asToken.ts +0 -7
  27. package/src/config/getBridgeEscrowAddress.ts +0 -13
  28. package/src/config/getBridgeFeesAddress.ts +0 -13
  29. package/src/config/getBridgeSettings.ts +0 -24
  30. package/src/config/getBridgeWalletAccount.ts +0 -37
  31. package/src/config/getFeeStructure.ts +0 -8
  32. package/src/config/getMaxBridgeAmount.ts +0 -7
  33. package/src/config/getMinBridgeAmount.ts +0 -7
  34. package/src/config/getRemoteChainId.ts +0 -10
  35. package/src/config/getRemoteTokenAddress.ts +0 -10
  36. package/src/config/getTestGateway.ts +0 -24
  37. package/src/config/getTransferAddresses.ts +0 -17
  38. package/src/config/getXl1ChainId.ts +0 -13
  39. package/src/config/getXl1TokenAddress.ts +0 -12
  40. package/src/config/index.ts +0 -15
  41. package/src/index.ts +0 -1
  42. package/src/interface/index.ts +0 -4
  43. package/src/interface/interface/ChainBridgeRelayInterface.ts +0 -9
  44. package/src/interface/interface/IntentIndexerInterface.ts +0 -8
  45. package/src/interface/interface/LockingProcessorInterface.ts +0 -10
  46. package/src/interface/interface/ObservationIndexerInterface.ts +0 -12
  47. package/src/interface/interface/Params.ts +0 -26
  48. package/src/interface/interface/RelayInterface.ts +0 -8
  49. package/src/interface/interface/index.ts +0 -6
  50. package/src/interface/repository/RepositoryInterface.ts +0 -28
  51. package/src/interface/repository/index.ts +0 -1
  52. package/src/interface/service/Observer/ERC20TransferObserver/ERC20TransferObserver.ts +0 -180
  53. package/src/interface/service/Observer/ERC20TransferObserver/index.ts +0 -1
  54. package/src/interface/service/Observer/LiquidityPoolBridgeObserver/LiquidityPoolBridgeObserver.ts +0 -210
  55. package/src/interface/service/Observer/LiquidityPoolBridgeObserver/index.ts +0 -1
  56. package/src/interface/service/Observer/Observer.ts +0 -48
  57. package/src/interface/service/Observer/index.ts +0 -1
  58. package/src/interface/service/Relay/ChainBridgeRelay/ChainBridgeRelayInterface.ts +0 -11
  59. package/src/interface/service/Relay/ChainBridgeRelay/ChainBridgeRelayService.ts +0 -116
  60. package/src/interface/service/Relay/ChainBridgeRelay/index.ts +0 -1
  61. package/src/interface/service/Relay/LiquidityPoolBridgeRelay/LiquidityPoolBridgeRelay.ts +0 -227
  62. package/src/interface/service/Relay/LiquidityPoolBridgeRelay/index.ts +0 -1
  63. package/src/interface/service/Relay/index.ts +0 -1
  64. package/src/interface/service/index.ts +0 -2
  65. package/src/interface/util/getBridgeIntentIdentifier.ts +0 -18
  66. package/src/interface/util/index.ts +0 -1
  67. package/src/modules/EVMLiquidityBridgeTransactionCompletionMonitorSentinel/EVMLiquidityBridgeTransactionCompletionMonitorSentinel.ts +0 -235
  68. package/src/modules/EVMLiquidityBridgeTransactionCompletionMonitorSentinel/index.ts +0 -1
  69. package/src/modules/index.ts +0 -1
  70. package/src/queue/connection.ts +0 -16
  71. package/src/queue/flowProducer.ts +0 -16
  72. package/src/queue/flows/createEthToXl1BridgeJob.ts +0 -71
  73. package/src/queue/flows/createXl1ToEthBridgeJob/createXl1ToEthBridgeJob.ts +0 -127
  74. package/src/queue/flows/createXl1ToEthBridgeJob/getJobIdForXl1ToEthBridgeJob.ts +0 -18
  75. package/src/queue/flows/createXl1ToEthBridgeJob/getXl1ToEthBridgeJob.ts +0 -11
  76. package/src/queue/flows/createXl1ToEthBridgeJob/index.ts +0 -3
  77. package/src/queue/flows/index.ts +0 -2
  78. package/src/queue/getXl1ToEthQueueJobs.ts +0 -57
  79. package/src/queue/getXl1ToEthQueues.ts +0 -39
  80. package/src/queue/index.ts +0 -8
  81. package/src/queue/prefix.ts +0 -1
  82. package/src/queue/telemetry.ts +0 -12
  83. package/src/queue/workers/EthToXl1BridgeParent.ts +0 -40
  84. package/src/queue/workers/EthTransactionMonitor.ts +0 -59
  85. package/src/queue/workers/EthTransactionPreparation.ts +0 -83
  86. package/src/queue/workers/EthTransactionSubmission.ts +0 -63
  87. package/src/queue/workers/EthTransactionSubmissionStorage.ts +0 -76
  88. package/src/queue/workers/WorkerDescription.ts +0 -10
  89. package/src/queue/workers/Xl1ToEthBridgeParent.ts +0 -41
  90. package/src/queue/workers/Xl1TransactionJobData.ts +0 -12
  91. package/src/queue/workers/Xl1TransactionMonitor.ts +0 -82
  92. package/src/queue/workers/Xl1TransactionPreparation.ts +0 -52
  93. package/src/queue/workers/Xl1TransactionSubmission.ts +0 -70
  94. package/src/queue/workers/Xl1TransactionSubmissionStorage.ts +0 -77
  95. package/src/queue/workers/createWorkers.ts +0 -29
  96. package/src/queue/workers/index.ts +0 -11
  97. package/src/queue/workers/util/index.ts +0 -2
  98. package/src/queue/workers/util/submitEthTransaction.ts +0 -32
  99. package/src/queue/workers/util/submitXl1Transaction.ts +0 -26
  100. package/src/server/addFlowProducer.ts +0 -14
  101. package/src/server/addWorkers.ts +0 -13
  102. package/src/server/app.ts +0 -20
  103. package/src/server/index.ts +0 -19
  104. package/src/server/instrumentation.ts +0 -15
  105. package/src/server/routes/addRoutes.ts +0 -9
  106. package/src/server/routes/bridge/addBridgeRoutes.ts +0 -12
  107. package/src/server/routes/bridge/index.ts +0 -1
  108. package/src/server/routes/bridge/routeDefinitions/getRouteDefinitions.ts +0 -18
  109. package/src/server/routes/bridge/routeDefinitions/index.ts +0 -1
  110. package/src/server/routes/bridge/routeDefinitions/pathParams/ChainIdPathParam.ts +0 -21
  111. package/src/server/routes/bridge/routeDefinitions/pathParams/index.ts +0 -1
  112. package/src/server/routes/bridge/routeDefinitions/routes/bridgeConfig.ts +0 -46
  113. package/src/server/routes/bridge/routeDefinitions/routes/bridgeFromRemoteStatus.ts +0 -58
  114. package/src/server/routes/bridge/routeDefinitions/routes/bridgeToRemote.ts +0 -93
  115. package/src/server/routes/bridge/routeDefinitions/routes/bridgeToRemoteEstimate.ts +0 -69
  116. package/src/server/routes/bridge/routeDefinitions/routes/bridgeToRemoteMaxEstimate.ts +0 -64
  117. package/src/server/routes/bridge/routeDefinitions/routes/bridgeToRemoteStatus.ts +0 -98
  118. package/src/server/routes/bridge/routeDefinitions/routes/index.ts +0 -6
  119. package/src/server/routes/healthz/get.ts +0 -20
  120. package/src/server/routes/healthz/index.ts +0 -1
  121. package/src/server/routes/index.ts +0 -1
  122. package/src/server/server.ts +0 -21
  123. package/src/services/EthTxState.ts +0 -5
  124. package/src/services/IBridgeServiceCollection.ts +0 -19
  125. package/src/services/TxState.ts +0 -14
  126. package/src/services/Xl1TxState.ts +0 -9
  127. package/src/services/getIterableMap.ts +0 -34
  128. package/src/services/getServices.ts +0 -41
  129. package/src/services/index.ts +0 -5
  130. package/src/util/BridgeFees.ts +0 -16
  131. package/src/util/bridgeFeesAsBigInt.ts +0 -15
  132. package/src/util/calculateBridgeFees.ts +0 -33
  133. package/src/util/calculateMaxBridgeAmount.ts +0 -22
  134. package/src/util/createBridgeTransfer.ts +0 -31
  135. package/src/util/generateBridgeEstimate.ts +0 -55
  136. package/src/util/getConfigFromEnv.ts +0 -15
  137. package/src/util/index.ts +0 -7
  138. package/src/validation/AsyncLogger.ts +0 -5
  139. package/src/validation/index.ts +0 -6
  140. package/src/validation/validateBridgeEstimate.ts +0 -60
  141. package/src/validation/validateBridgeEstimateExact.ts +0 -39
  142. package/src/validation/validateBridgeTransaction.ts +0 -53
  143. package/src/validation/validateSufficientLiquiditySourceAllowance.ts +0 -39
  144. package/src/validation/validateSufficientLiquiditySourceBalance.ts +0 -38
  145. package/src/validation/validateSufficientRunnerEthBalanceForGas.ts +0 -57
  146. package/src/validation/validateSufficientXL1SourceAddressBalance.ts +0 -39
  147. /package/dist/node/server/routes/{healthz → livez}/index.d.ts +0 -0
@@ -1,116 +0,0 @@
1
- import { assertEx, isNull } from '@xylabs/sdk-js'
2
- import type { BridgeDestinationObservation, BridgeIntent } from '@xyo-network/xl1-sdk'
3
- import { AbstractCreatableProvider } from '@xyo-network/xl1-sdk'
4
-
5
- import type {
6
- BridgeDestinationObservationIndexerInterface, BridgeIntentIndexerInterface,
7
- BridgeServiceParams,
8
- BridgeSourceObservationIndexerInterface, ChainBridgeRelayInterface, LockingBridgeIntentProcessorInterface,
9
- UnlockingBridgeIntentProcessorInterface,
10
- } from '../../../interface/index.ts'
11
-
12
- export class ChainBridgeRelayService<TParams extends BridgeServiceParams = BridgeServiceParams>
13
- extends AbstractCreatableProvider<TParams> implements ChainBridgeRelayInterface {
14
- moniker = 'ChainBridgeRelayService'
15
- protected get account() {
16
- return assertEx(this.params.account, () => 'account is required')
17
- }
18
-
19
- protected get destinationObservations(): BridgeDestinationObservationIndexerInterface {
20
- return assertEx(this.params.destinationObservations, () => 'destinationObservations is required')
21
- }
22
-
23
- protected get destinationRelay(): ChainBridgeRelayInterface {
24
- return assertEx(this.params.destinationRelay, () => 'destinationRelay is required')
25
- }
26
-
27
- protected get intentProcessed(): LockingBridgeIntentProcessorInterface {
28
- return assertEx(this.params.intentProcessed, () => 'intentProcessed is required')
29
- }
30
-
31
- protected get intentProcessing(): UnlockingBridgeIntentProcessorInterface {
32
- return assertEx(this.params.intentProcessing, () => 'intentProcessing is required')
33
- }
34
-
35
- protected get intentResourceAccess(): BridgeIntentIndexerInterface {
36
- return assertEx(this.params.intents, () => 'intents is required')
37
- }
38
-
39
- protected get sourceObservations(): BridgeSourceObservationIndexerInterface {
40
- return assertEx(this.params.sourceObservations, () => 'sourceObservations is required')
41
- }
42
-
43
- /**
44
- * Begins the relay process for a given BridgeIntent.
45
- * @param bridgeIntent The bridgeIntent to begin relaying
46
- * @returns True if the relay was started, false otherwise
47
- */
48
- async beginRelay(bridgeIntent: BridgeIntent): Promise<boolean> {
49
- try {
50
- // Ensure source observation exists
51
- const bridgeSourceObservation = await this.sourceObservations.getObservationForIntent(bridgeIntent)
52
- if (!isNull(bridgeSourceObservation)) {
53
- const canProcess = await this.intentProcessing.lock(this.account.address, bridgeIntent)
54
- if (canProcess) {
55
- await this.destinationRelay.beginRelay(bridgeIntent)
56
- return true
57
- }
58
- }
59
- } catch {
60
- await this.intentProcessing.unlock(this.account.address, bridgeIntent)
61
- }
62
- return false
63
- }
64
-
65
- /**
66
- * Handles a BridgeDestinationObservation.
67
- * @param bridgeDestinationObservation The BridgeDestinationObservation to process
68
- * @returns True if the observation was processed as a completion for an outstanding relay, false otherwise
69
- */
70
- async onDestinationObservation(bridgeDestinationObservation: BridgeDestinationObservation): Promise<boolean> {
71
- // Ensure intent exists
72
- const bridgeIntent = await this.destinationObservations.getIntentForObservation(bridgeDestinationObservation)
73
- if (!isNull(bridgeIntent)) {
74
- // Ensure not already processed
75
- const processed = await this.intentProcessed.isLocked(bridgeIntent)
76
- if (isNull(processed)) {
77
- // Ensure we are the processor
78
- const processor = await this.intentProcessing.isLocked(bridgeIntent)
79
- if (!isNull(processor) && processor === this.account.address) {
80
- // Mark as completed
81
- await this.intentProcessed.lock(this.account.address, bridgeIntent)
82
- await this.intentProcessing.unlock(this.account.address, bridgeIntent)
83
- return true
84
- }
85
- }
86
- }
87
- return false
88
- }
89
-
90
- /**
91
- * Relays a given BridgeIntent.
92
- * @param bridgeIntent The BridgeIntent to relay
93
- * @returns Relays the intent in a blocking manner, returning the resulting BridgeDestinationObservation if successful
94
- */
95
- async relaySync(bridgeIntent: BridgeIntent): Promise<BridgeDestinationObservation | null> {
96
- let canProcess = isNull(await this.intentProcessing.isLocked(bridgeIntent))
97
- try {
98
- canProcess = await this.intentProcessing.lock(this.account.address, bridgeIntent)
99
- if (canProcess) {
100
- const result = await this.destinationRelay.relaySync(bridgeIntent)
101
- if (!isNull(result)) {
102
- // TODO: How to handle partial success here where relay succeeded but we didn't record result successfully?
103
- // Prefer async observer pattern instead?
104
- await this.destinationObservations.addObservation(result, bridgeIntent)
105
- await this.intentProcessed.lock(this.account.address, bridgeIntent)
106
- return result
107
- }
108
- }
109
- } finally {
110
- if (!isNull(bridgeIntent)) {
111
- await this.intentProcessing.unlock(this.account.address, bridgeIntent)
112
- }
113
- }
114
- return null
115
- }
116
- }
@@ -1 +0,0 @@
1
- export * from './ChainBridgeRelayService.ts'
@@ -1,227 +0,0 @@
1
- import type { Address, Hex } from '@xylabs/sdk-js'
2
- import {
3
- asHex, assertEx, hexFromBigInt, hexToBigInt, isNull,
4
- toAddress,
5
- } from '@xylabs/sdk-js'
6
- import { PayloadBuilder } from '@xyo-network/sdk-js'
7
- import type { LiquidityPoolBridge } from '@xyo-network/typechain'
8
- import { LiquidityPoolBridge__factory } from '@xyo-network/typechain'
9
- import { AbstractCreatableProvider } from '@xyo-network/xl1-sdk'
10
- import {
11
- type BridgeDestinationObservation, BridgeDestinationObservationSchema, type BridgeIntent,
12
- } from '@xyo-network/xl1-sdk'
13
- import type { WebSocketProvider } from 'ethers'
14
- import { getAddress, Wallet } from 'ethers'
15
-
16
- import type {
17
- BridgeDestinationObservationIndexerInterface, BridgeIntentIndexerInterface, BridgeServiceParams, BridgeSourceObservationIndexerInterface,
18
- ChainBridgeRelayInterface, LockingBridgeIntentProcessorInterface, UnlockingBridgeIntentProcessorInterface,
19
- } from '../../../interface/index.ts'
20
-
21
- export type LiquidityPoolBridgeRelayParams = BridgeServiceParams & {
22
- /**
23
- * The address to watch for incoming or outgoing ERC-20 token transfers.
24
- */
25
- bridgeAddress: string
26
- /**
27
- * An ethers.js WebSocketProvider connected to the Ethereum network to monitor for ERC-20 transfers.
28
- */
29
- provider: WebSocketProvider
30
- }
31
-
32
- export class LiquidityPoolBridgeRelay<TParams extends LiquidityPoolBridgeRelayParams = LiquidityPoolBridgeRelayParams>
33
- extends AbstractCreatableProvider<TParams> implements ChainBridgeRelayInterface {
34
- moniker = 'LiquidityPoolBridgeRelay'
35
- protected _bridge: LiquidityPoolBridge | undefined
36
- protected _bridgeChainId: Hex | undefined
37
- protected _bridgeRemoteChainId: Hex | undefined
38
- protected _bridgeTokenAddress: Address | undefined
39
- protected _wallet: Wallet | undefined
40
-
41
- protected get account() {
42
- return assertEx(this.params.account, () => 'account is required')
43
- }
44
-
45
- protected get bridge(): LiquidityPoolBridge {
46
- return assertEx(this._bridge, () => new Error('Bridge contract not initialized'))
47
- }
48
-
49
- protected get bridgeChainId(): Hex {
50
- return assertEx(this._bridgeChainId, () => new Error('Bridge chain ID not initialized'))
51
- }
52
-
53
- protected get bridgeRemoteChainId(): Hex {
54
- return assertEx(this._bridgeRemoteChainId, () => new Error('Bridge remote chain ID not initialized'))
55
- }
56
-
57
- protected get bridgeTokenAddress(): Address {
58
- return assertEx(this._bridgeTokenAddress, () => new Error('Bridge token address not initialized'))
59
- }
60
-
61
- protected get destinationObservations(): BridgeDestinationObservationIndexerInterface {
62
- return assertEx(this.params.destinationObservations, () => 'destinationObservations is required')
63
- }
64
-
65
- protected get destinationRelay(): ChainBridgeRelayInterface {
66
- return assertEx(this.params.destinationRelay, () => 'destinationRelay is required')
67
- }
68
-
69
- protected get intentProcessed(): LockingBridgeIntentProcessorInterface {
70
- return assertEx(this.params.intentProcessed, () => 'intentProcessed is required')
71
- }
72
-
73
- protected get intentProcessing(): UnlockingBridgeIntentProcessorInterface {
74
- return assertEx(this.params.intentProcessing, () => 'intentProcessing is required')
75
- }
76
-
77
- protected get intentResourceAccess(): BridgeIntentIndexerInterface {
78
- return assertEx(this.params.intents, () => 'intents is required')
79
- }
80
-
81
- protected get provider(): WebSocketProvider {
82
- return assertEx(this.params.provider, () => new Error('Provider not initialized'))
83
- }
84
-
85
- protected get sourceObservations(): BridgeSourceObservationIndexerInterface {
86
- return assertEx(this.params.sourceObservations, () => 'sourceObservations is required')
87
- }
88
-
89
- protected get wallet(): Wallet {
90
- return assertEx(this._wallet, () => 'wallet is required')
91
- }
92
-
93
- /**
94
- * Begins the relay process for a given BridgeIntent.
95
- * @param bridgeIntent The bridgeIntent to begin relaying
96
- * @returns True if the relay was started, false otherwise
97
- */
98
- async beginRelay(bridgeIntent: BridgeIntent): Promise<boolean> {
99
- try {
100
- // Ensure source observation exists
101
- const bridgeSourceObservation = await this.sourceObservations.getObservationForIntent(bridgeIntent)
102
- if (!isNull(bridgeSourceObservation)) {
103
- const canProcess = await this.intentProcessing.lock(this.account.address, bridgeIntent)
104
- if (canProcess) {
105
- const amount = hexToBigInt(bridgeIntent.destAmount)
106
- const nonce = await this.wallet.getNonce()
107
- await this.bridge.bridgeFromRemote(
108
- getAddress(bridgeIntent.srcAddress),
109
- getAddress(bridgeIntent.destAddress),
110
- amount,
111
- nonce,
112
- )
113
- return true
114
- }
115
- }
116
- } catch (error) {
117
- console.error('Error occurred while beginning relay:', error)
118
- await this.intentProcessing.unlock(this.account.address, bridgeIntent)
119
- }
120
- return false
121
- }
122
-
123
- override async createHandler() {
124
- const { provider, bridgeAddress } = this.params
125
-
126
- // Connect to the bridge contract
127
- // Create a wallet bound to the provider (signer + provider)
128
- const key = assertEx(this.account?.private?.hex, () => new Error('Account private key is required'))
129
- this._wallet = new Wallet(key, provider)
130
- this._bridge = LiquidityPoolBridge__factory.connect(getAddress(bridgeAddress), this._wallet)
131
-
132
- // Parse bridge network chain ID
133
- const network = await provider.getNetwork()
134
- this._bridgeChainId = assertEx(hexFromBigInt(network.chainId), () => new Error('Failed to parse bridgeChainId'))
135
-
136
- // Parse bridge token address
137
- const tokenAddress = await this.bridge.token()
138
- this._bridgeTokenAddress = toAddress(tokenAddress)
139
-
140
- // Parse bridge remote chain ID
141
- const bridgeRemoteChain = await this.bridge.remoteChain()
142
- this._bridgeRemoteChainId = asHex(bridgeRemoteChain)
143
-
144
- await this.bridge.on(this.bridge.getEvent('BridgedFromRemote'), (id, from, to, amount, remoteChain, args) => {
145
- const txHash = args.transactionHash
146
- const destConfirmation = asHex(txHash)
147
- const observation: BridgeDestinationObservation = new PayloadBuilder<BridgeDestinationObservation>({ schema: BridgeDestinationObservationSchema })
148
- .fields({
149
- src: this.bridgeRemoteChainId,
150
- dest: this.bridgeChainId,
151
- srcAddress: toAddress(from),
152
- destAddress: toAddress(to),
153
- srcToken: this.bridgeTokenAddress,
154
- destToken: this.bridgeTokenAddress,
155
- srcAmount: amount.toString(),
156
- destAmount: amount.toString(),
157
- destConfirmation,
158
- }).build()
159
- this.onDestinationObservation(observation).catch(console.error)
160
- })
161
- }
162
-
163
- /**
164
- * Handles a BridgeDestinationObservation.
165
- * @param bridgeDestinationObservation The BridgeDestinationObservation to process
166
- * @returns True if the observation was processed as a completion for an outstanding relay, false otherwise
167
- */
168
- async onDestinationObservation(bridgeDestinationObservation: BridgeDestinationObservation): Promise<boolean> {
169
- // Ensure intent exists
170
- const bridgeIntent = await this.destinationObservations.getIntentForObservation(bridgeDestinationObservation)
171
- if (!isNull(bridgeIntent)) {
172
- // Ensure not already processed
173
- const processed = await this.intentProcessed.isLocked(bridgeIntent)
174
- if (isNull(processed)) {
175
- // Ensure we are the processor
176
- const processor = await this.intentProcessing.isLocked(bridgeIntent)
177
- if (!isNull(processor) && processor === this.account.address) {
178
- // Mark as completed
179
- await this.intentProcessed.lock(this.account.address, bridgeIntent)
180
- await this.intentProcessing.unlock(this.account.address, bridgeIntent)
181
- return true
182
- }
183
- }
184
- }
185
- return false
186
- }
187
-
188
- /**
189
- * Relays a given BridgeIntent.
190
- * @param bridgeIntent The BridgeIntent to relay
191
- * @returns Relays the intent in a blocking manner, returning the resulting BridgeDestinationObservation if successful
192
- */
193
- async relaySync(bridgeIntent: BridgeIntent): Promise<BridgeDestinationObservation | null> {
194
- // Ensure source observation exists
195
- const bridgeSourceObservation = await this.sourceObservations.getObservationForIntent(bridgeIntent)
196
- if (!isNull(bridgeSourceObservation)) {
197
- let canProcess = isNull(await this.intentProcessing.isLocked(bridgeIntent))
198
- try {
199
- canProcess = await this.intentProcessing.lock(this.account.address, bridgeIntent)
200
- if (canProcess) {
201
- const amount = hexToBigInt(bridgeIntent.destAmount)
202
- const nonce = await this.wallet.getNonce()
203
- const tx = await this.bridge.bridgeFromRemote(
204
- getAddress(bridgeIntent.srcAddress),
205
- getAddress(bridgeIntent.destAddress),
206
- amount,
207
- nonce,
208
- )
209
- const confirmation = await tx.wait()
210
- const transactionResponse = await confirmation?.getTransaction()
211
- const destConfirmation = asHex(transactionResponse?.hash ?? '')
212
- const { schema, ...rest } = bridgeIntent
213
- const result: BridgeDestinationObservation = new PayloadBuilder<BridgeDestinationObservation>({ schema: BridgeDestinationObservationSchema })
214
- .fields({ ...rest, destConfirmation }).build()
215
- await this.destinationObservations.addObservation(result, bridgeIntent)
216
- await this.intentProcessed.lock(this.account.address, bridgeIntent)
217
- return result
218
- }
219
- } finally {
220
- if (!isNull(bridgeIntent)) {
221
- await this.intentProcessing.unlock(this.account.address, bridgeIntent)
222
- }
223
- }
224
- }
225
- return null
226
- }
227
- }
@@ -1 +0,0 @@
1
- export * from './LiquidityPoolBridgeRelay.ts'
@@ -1 +0,0 @@
1
- export * from './ChainBridgeRelay/index.ts'
@@ -1,2 +0,0 @@
1
- export * from './Observer/index.ts'
2
- export * from './Relay/index.ts'
@@ -1,18 +0,0 @@
1
- import type { Hash } from '@xylabs/sdk-js'
2
- import { PayloadBuilder } from '@xyo-network/sdk-js'
3
- import {
4
- type BridgeDestinationObservation, type BridgeIntent, BridgeIntentSchema, type BridgeSourceObservation,
5
- } from '@xyo-network/xl1-sdk'
6
-
7
- export const getBridgeIntentFromObservation = (observation: BridgeSourceObservation | BridgeDestinationObservation, nonce: string): BridgeIntent => {
8
- const {
9
- src, srcAddress, srcAmount, srcToken, dest, destAddress, destAmount, destToken,
10
- } = observation
11
- return new PayloadBuilder<BridgeIntent>({ schema: BridgeIntentSchema }).fields({
12
- src, srcAddress, srcAmount, srcToken, dest, destAddress, destAmount, destToken, nonce,
13
- }).build()
14
- }
15
-
16
- export const getBridgeIntentIdentifier = async (bridgeIntent: BridgeIntent): Promise<Hash> => {
17
- return await PayloadBuilder.hash(bridgeIntent)
18
- }
@@ -1 +0,0 @@
1
- export * from './getBridgeIntentIdentifier.ts'
@@ -1,235 +0,0 @@
1
- import type { Attributes, Counter } from '@opentelemetry/api'
2
- import type {
3
- Address, Hash, Hex,
4
- } from '@xylabs/sdk-js'
5
- import {
6
- asAddress, asHex, assertEx, delay, hexFromBigInt, hexToBigInt, isDefined, isUndefined,
7
- } from '@xylabs/sdk-js'
8
- import type {
9
- AnyConfigSchema, Payload,
10
- SentinelConfig, SentinelInstance, SentinelModuleEventData, SentinelParams,
11
- } from '@xyo-network/sdk-js'
12
- import {
13
- AbstractSentinel, asSchema, PayloadBuilder,
14
- } from '@xyo-network/sdk-js'
15
- import { type LiquidityPoolBridge, LiquidityPoolBridge__factory } from '@xyo-network/typechain'
16
- import type {
17
- BridgeDestinationObservation, BridgeIntent, IterableMap, MapType,
18
- SignedHydratedTransaction,
19
- } from '@xyo-network/xl1-sdk'
20
- import {
21
- BridgeDestinationObservationSchema, flattenHydratedTransaction, flattenHydratedTransactions, isBridgeIntent,
22
- tryUnflattenHydratedTransaction,
23
- } from '@xyo-network/xl1-sdk'
24
- import { Mutex } from 'async-mutex'
25
- import { getAddress } from 'ethers/address'
26
- import type { Provider } from 'ethers/providers'
27
- import { Wallet } from 'ethers/wallet'
28
-
29
- export const EVMLiquidityBridgeTransactionCompletionMonitorSentinelConfigSchema
30
- = asSchema('network.xyo.sentinel.chain.evm.liquidity.bridge.transaction.completion.monitor.config', true)
31
- export type EVMLiquidityBridgeTransactionCompletionMonitorSentinelConfigSchema = typeof EVMLiquidityBridgeTransactionCompletionMonitorSentinelConfigSchema
32
-
33
- /**
34
- * The configuration for the sentinel
35
- */
36
- export type EVMLiquidityBridgeTransactionCompletionMonitorSentinelConfig = SentinelConfig<{
37
- /**
38
- * The interval in milliseconds between checking for jobs to fulfill
39
- */
40
- jobCheckInterval: number
41
-
42
- /**
43
- * The schema for the sentinel config
44
- */
45
- schema: EVMLiquidityBridgeTransactionCompletionMonitorSentinelConfigSchema
46
- }>
47
-
48
- interface EVMLiquidityBridgeTransactionCompletionMonitorSentinelParamFields {
49
- /**
50
- * The address to watch for incoming or outgoing ERC-20 token transfers.
51
- */
52
- bridgeAddress: string
53
-
54
- /**
55
- * The map of completed transactions to monitor for completion
56
- */
57
- completedTransactions: MapType<Hash, BridgeDestinationObservation>
58
-
59
- /**
60
- * The map of pending transactions to monitor for completion
61
- */
62
- pendingTransactions: IterableMap<Hash, SignedHydratedTransaction>
63
-
64
- /**
65
- * An ethers.js Provider connected to the Ethereum network to monitor for ERC-20 transfers.
66
- */
67
- provider: Provider
68
- }
69
-
70
- export type EVMLiquidityBridgeTransactionCompletionMonitorSentinelParams<TConfig extends
71
- AnyConfigSchema<EVMLiquidityBridgeTransactionCompletionMonitorSentinelConfig> = AnyConfigSchema<EVMLiquidityBridgeTransactionCompletionMonitorSentinelConfig>,
72
- > = SentinelParams<TConfig> & EVMLiquidityBridgeTransactionCompletionMonitorSentinelParamFields
73
-
74
- const defaultJobCheckIntervalMs = 15_000
75
-
76
- export class EVMLiquidityBridgeTransactionCompletionMonitorSentinel<
77
- TParams extends EVMLiquidityBridgeTransactionCompletionMonitorSentinelParams = EVMLiquidityBridgeTransactionCompletionMonitorSentinelParams,
78
- TEventData extends SentinelModuleEventData<SentinelInstance<TParams>> = SentinelModuleEventData<SentinelInstance<TParams>>,
79
- > extends AbstractSentinel<TParams, TEventData> {
80
- static override readonly configSchemas = [EVMLiquidityBridgeTransactionCompletionMonitorSentinelConfigSchema]
81
- static override readonly defaultConfigSchema = EVMLiquidityBridgeTransactionCompletionMonitorSentinelConfigSchema
82
- protected _attemptsCounter: Counter<Attributes> | undefined
83
- protected _bridge: LiquidityPoolBridge | undefined
84
- protected _bridgeChainId: Hex | undefined
85
- protected _bridgeRemoteChainId: Hex | undefined
86
- protected _bridgeTokenAddress: Address | undefined
87
- protected _checkCounter: Counter<Attributes> | undefined
88
- protected _errorCounter: Counter<Attributes> | undefined
89
- protected _reportMutex = new Mutex()
90
- protected _successCounter: Counter<Attributes> | undefined
91
- protected _wallet: Wallet | undefined
92
-
93
- protected get bridge(): LiquidityPoolBridge {
94
- return assertEx(this._bridge, () => new Error('Bridge contract not initialized'))
95
- }
96
-
97
- protected get completedTransactions(): MapType<Hash, BridgeDestinationObservation> {
98
- return assertEx(this.params.completedTransactions, () => 'Completed transactions map is not defined')
99
- }
100
-
101
- protected get jobCheckInterval(): number {
102
- return isDefined(this.config.jobCheckInterval) ? this.config.jobCheckInterval : defaultJobCheckIntervalMs
103
- }
104
-
105
- protected get pendingTransactions(): IterableMap<Hash, SignedHydratedTransaction> {
106
- return assertEx(this.params.pendingTransactions, () => 'Pending transactions map is not defined')
107
- }
108
-
109
- protected get wallet(): Wallet {
110
- return assertEx(this._wallet, () => 'wallet is required')
111
- }
112
-
113
- override async createHandler() {
114
- await super.createHandler()
115
- // Create meters for tracking bridge attempts, successes, and errors.
116
- this._attemptsCounter = this.meter?.createCounter(
117
- 'evm_liquidity_bridge_transaction_completion_monitor_sentinel_attempts_total',
118
- { description: 'Number of attempts' },
119
- )
120
- this._checkCounter = this.meter?.createCounter(
121
- 'evm_liquidity_bridge_transaction_completion_monitor_sentinel_check_total',
122
- { description: 'Number of checks' },
123
- )
124
- this._successCounter = this.meter?.createCounter(
125
- 'evm_liquidity_bridge_transaction_completion_monitor_sentinel_success_total',
126
- { description: 'Number of successes' },
127
- )
128
- this._errorCounter = this.meter?.createCounter(
129
- 'evm_liquidity_bridge_transaction_completion_monitor_sentinel_errors_total',
130
- { description: 'Number of errors' },
131
- )
132
- const { provider, bridgeAddress } = this.params
133
-
134
- // Connect to the bridge contract
135
- // Create a wallet bound to the provider (signer + provider)
136
- const key = assertEx(this.account?.private?.hex, () => new Error('Account private key is required'))
137
- this._wallet = new Wallet(key, provider)
138
- this._bridge = LiquidityPoolBridge__factory.connect(getAddress(bridgeAddress), this._wallet)
139
-
140
- // Parse bridge network chain ID
141
- const network = await provider.getNetwork()
142
- this._bridgeChainId = assertEx(hexFromBigInt(network.chainId), () => new Error('Failed to parse bridgeChainId'))
143
-
144
- // Parse bridge token address
145
- const tokenAddress = await this.bridge.token()
146
- this._bridgeTokenAddress = asAddress(tokenAddress, true)
147
-
148
- // Parse bridge remote chain ID
149
- const bridgeRemoteChain = await this.bridge.remoteChain()
150
- this._bridgeRemoteChainId = asHex(bridgeRemoteChain)
151
- }
152
-
153
- override async reportHandler(payloads?: Payload[]): Promise<Payload[]> {
154
- if (isDefined(payloads) && payloads.length > 0) {
155
- const signedHydratedTransaction = tryUnflattenHydratedTransaction(payloads)
156
- if (isDefined(signedHydratedTransaction)) {
157
- // Insert into pending transactions for monitoring
158
- const txHash = await PayloadBuilder.hash(signedHydratedTransaction[0])
159
- this.logger?.info(`Adding transaction ${signedHydratedTransaction[0]} with hash ${txHash} to pending transactions for monitoring`)
160
- await this.pendingTransactions.set(txHash, signedHydratedTransaction)
161
- return flattenHydratedTransaction(signedHydratedTransaction)
162
- }
163
- return []
164
- } else {
165
- if (this._reportMutex.isLocked()) {
166
- this.logger?.debug(`EVMLiquidityBridgeTransactionCompletionMonitorSentinel [${this.id}] is already running, skipping report [${Date.now()}]`)
167
- return []
168
- }
169
- return await this._reportMutex.runExclusive(async () => {
170
- const response: Payload[] = []
171
- if (isUndefined(payloads) || payloads.length === 0) {
172
- await this.processAllTransactions()
173
- }
174
- return response
175
- })
176
- }
177
- }
178
-
179
- private async processAllTransactions(): Promise<Payload[]> {
180
- const results: SignedHydratedTransaction[] = []
181
- for await (const [hash, signedHydratedTransaction] of this.pendingTransactions) {
182
- const result = await this.processTransaction([hash, signedHydratedTransaction])
183
- if (isDefined(result)) results.push(result[1])
184
- await delay(this.jobCheckInterval)
185
- }
186
- return flattenHydratedTransactions(results)
187
- }
188
-
189
- private async processTransaction(
190
- [hash, signedHydratedTransaction]: [Hash, SignedHydratedTransaction],
191
- ): Promise<[Hash, SignedHydratedTransaction] | undefined> {
192
- this.logger?.info(`Checking for transaction ${signedHydratedTransaction[0]} with hash ${hash}`)
193
- try {
194
- let ret: [Hash, SignedHydratedTransaction] | undefined = undefined
195
- this._checkCounter?.add(1)
196
- const bridgeIntents = signedHydratedTransaction[1].filter(isBridgeIntent)
197
- // Only support a single intent per transaction for now
198
- if (bridgeIntents.length !== 1) {
199
- await this.pendingTransactions.delete(hash)
200
- return ret
201
- }
202
- const bridgeIntent = bridgeIntents[0]
203
- this._attemptsCounter?.add(1)
204
- const bridgeDestinationObservation = await this.relayBridgeIntentSync(bridgeIntent)
205
- await this.completedTransactions.set(hash, bridgeDestinationObservation)
206
- await this.pendingTransactions.delete(hash)
207
- this._successCounter?.add(1)
208
- return ret
209
- } catch (error) {
210
- this._errorCounter?.add(1)
211
- this.logger?.error(`Error checking for transaction ${signedHydratedTransaction[0]} with hash ${hash}:`, error)
212
- }
213
- }
214
-
215
- /**
216
- * Relays a given BridgeIntent.
217
- * @param bridgeIntent The BridgeIntent to relay
218
- * @returns Relays the intent in a blocking manner, returning the resulting BridgeDestinationObservation if successful
219
- */
220
- private async relayBridgeIntentSync(bridgeIntent: BridgeIntent): Promise<BridgeDestinationObservation> {
221
- // Ensure source observation exists
222
- const amount = hexToBigInt(bridgeIntent.destAmount)
223
- const nonce = await this.wallet.getNonce()
224
- const srcAddress = getAddress(bridgeIntent.srcAddress)
225
- const destAddress = getAddress(bridgeIntent.destAddress)
226
- const tx = await this.bridge.bridgeFromRemote(srcAddress, destAddress, amount, nonce)
227
- const confirmation = await tx.wait()
228
- const transactionResponse = await confirmation?.getTransaction()
229
- const destConfirmation = asHex(transactionResponse?.hash ?? '', true)
230
- const { schema, ...rest } = bridgeIntent
231
- const result: BridgeDestinationObservation = new PayloadBuilder<BridgeDestinationObservation>({ schema: BridgeDestinationObservationSchema })
232
- .fields({ ...rest, destConfirmation }).build()
233
- return result
234
- }
235
- }
@@ -1 +0,0 @@
1
- export * from './EVMLiquidityBridgeTransactionCompletionMonitorSentinel.ts'
@@ -1 +0,0 @@
1
- export * from './EVMLiquidityBridgeTransactionCompletionMonitorSentinel/index.ts'
@@ -1,16 +0,0 @@
1
- import { isDefined } from '@xylabs/sdk-js'
2
- import type { BridgeConfig } from '@xyo-network/chain-orchestration'
3
- import { Redis } from 'ioredis'
4
-
5
- let connection: Redis | undefined
6
-
7
- const maxRetriesPerRequest = null
8
-
9
- export const getConnection = (config: BridgeConfig) => {
10
- if (isDefined(connection)) return connection
11
- const { redisHost: host, redisPort: port } = config
12
- connection = new Redis({
13
- host, port, maxRetriesPerRequest,
14
- })
15
- return connection
16
- }
@@ -1,16 +0,0 @@
1
- import { isDefined } from '@xylabs/sdk-js'
2
- import { FlowProducer } from 'bullmq'
3
- import type { BullMQOtel } from 'bullmq-otel'
4
- import type { Redis } from 'ioredis'
5
-
6
- import { prefix } from './prefix.ts'
7
-
8
- let flowProducer: FlowProducer | undefined
9
-
10
- export const getFlowProducer = (connection: Redis, telemetry?: BullMQOtel) => {
11
- if (isDefined(flowProducer)) return flowProducer
12
- flowProducer = new FlowProducer({
13
- connection, telemetry, prefix,
14
- })
15
- return flowProducer
16
- }