@xyo-network/chain-bridge 1.17.2 → 1.17.3

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 (160) hide show
  1. package/dist/node/config/asChainId.d.ts +3 -0
  2. package/dist/node/config/asChainId.d.ts.map +1 -0
  3. package/dist/node/config/asToken.d.ts +3 -0
  4. package/dist/node/config/asToken.d.ts.map +1 -0
  5. package/dist/node/config/getBridgeEscrowAddress.d.ts +5 -0
  6. package/dist/node/config/getBridgeEscrowAddress.d.ts.map +1 -0
  7. package/dist/node/config/getBridgeFeesAddress.d.ts +5 -0
  8. package/dist/node/config/getBridgeFeesAddress.d.ts.map +1 -0
  9. package/dist/node/config/getBridgeSettings.d.ts +3 -0
  10. package/dist/node/config/getBridgeSettings.d.ts.map +1 -0
  11. package/dist/node/config/getBridgeWalletAccount.d.ts +6 -0
  12. package/dist/node/config/getBridgeWalletAccount.d.ts.map +1 -0
  13. package/dist/node/config/getFeeStructure.d.ts +4 -0
  14. package/dist/node/config/getFeeStructure.d.ts.map +1 -0
  15. package/dist/node/config/getGateway.d.ts +3 -0
  16. package/dist/node/config/getGateway.d.ts.map +1 -0
  17. package/dist/node/config/getMaxBridgeAmount.d.ts +4 -0
  18. package/dist/node/config/getMaxBridgeAmount.d.ts.map +1 -0
  19. package/dist/node/config/getMinBridgeAmount.d.ts +4 -0
  20. package/dist/node/config/getMinBridgeAmount.d.ts.map +1 -0
  21. package/dist/node/config/getRemoteChainId.d.ts +4 -0
  22. package/dist/node/config/getRemoteChainId.d.ts.map +1 -0
  23. package/dist/node/config/getRemoteTokenAddress.d.ts +4 -0
  24. package/dist/node/config/getRemoteTokenAddress.d.ts.map +1 -0
  25. package/dist/node/config/getTransferAddresses.d.ts +8 -0
  26. package/dist/node/config/getTransferAddresses.d.ts.map +1 -0
  27. package/dist/node/config/getXl1ChainId.d.ts +4 -0
  28. package/dist/node/config/getXl1ChainId.d.ts.map +1 -0
  29. package/dist/node/config/getXl1TokenAddress.d.ts +4 -0
  30. package/dist/node/config/getXl1TokenAddress.d.ts.map +1 -0
  31. package/dist/node/config/index.d.ts +16 -0
  32. package/dist/node/config/index.d.ts.map +1 -0
  33. package/dist/node/index.mjs +1133 -206
  34. package/dist/node/index.mjs.map +1 -1
  35. package/dist/node/interface/service/Observer/LiquidityPoolBridgeObserver/LiquidityPoolBridgeObserver.d.ts.map +1 -1
  36. package/dist/node/manifest/getLocator.d.ts.map +1 -1
  37. package/dist/node/manifest/public/index.d.ts +0 -4
  38. package/dist/node/manifest/public/index.d.ts.map +1 -1
  39. package/dist/node/modules/EVMLiquidityBridgeTransactionCompletionMonitorSentinel/EVMLiquidityBridgeTransactionCompletionMonitorSentinel.d.ts +77 -0
  40. package/dist/node/modules/EVMLiquidityBridgeTransactionCompletionMonitorSentinel/EVMLiquidityBridgeTransactionCompletionMonitorSentinel.d.ts.map +1 -0
  41. package/dist/node/modules/EVMLiquidityBridgeTransactionCompletionMonitorSentinel/index.d.ts +2 -0
  42. package/dist/node/modules/EVMLiquidityBridgeTransactionCompletionMonitorSentinel/index.d.ts.map +1 -0
  43. package/dist/node/modules/XL1TransactionCompletionMonitorSentinel/XL1TransactionCompletionMonitorSentinel.d.ts +56 -0
  44. package/dist/node/modules/XL1TransactionCompletionMonitorSentinel/XL1TransactionCompletionMonitorSentinel.d.ts.map +1 -0
  45. package/dist/node/modules/XL1TransactionCompletionMonitorSentinel/index.d.ts +2 -0
  46. package/dist/node/modules/XL1TransactionCompletionMonitorSentinel/index.d.ts.map +1 -0
  47. package/dist/node/modules/index.d.ts +2 -1
  48. package/dist/node/modules/index.d.ts.map +1 -1
  49. package/dist/node/server/app.d.ts +3 -1
  50. package/dist/node/server/app.d.ts.map +1 -1
  51. package/dist/node/server/routes/addRoutes.d.ts +2 -1
  52. package/dist/node/server/routes/addRoutes.d.ts.map +1 -1
  53. package/dist/node/server/routes/bridge/addBridgeRoutes.d.ts +2 -1
  54. package/dist/node/server/routes/bridge/addBridgeRoutes.d.ts.map +1 -1
  55. package/dist/node/server/routes/bridge/routeDefinitions/getRouteDefinitions.d.ts +2 -1
  56. package/dist/node/server/routes/bridge/routeDefinitions/getRouteDefinitions.d.ts.map +1 -1
  57. package/dist/node/server/routes/bridge/routeDefinitions/pathParams/ChainIdPathParam.d.ts +2 -1
  58. package/dist/node/server/routes/bridge/routeDefinitions/pathParams/ChainIdPathParam.d.ts.map +1 -1
  59. package/dist/node/server/routes/bridge/routeDefinitions/routes/bridgeConfig.d.ts +4 -0
  60. package/dist/node/server/routes/bridge/routeDefinitions/routes/bridgeConfig.d.ts.map +1 -0
  61. package/dist/node/server/routes/bridge/routeDefinitions/routes/bridgeFromRemoteStatus.d.ts +2 -1
  62. package/dist/node/server/routes/bridge/routeDefinitions/routes/bridgeFromRemoteStatus.d.ts.map +1 -1
  63. package/dist/node/server/routes/bridge/routeDefinitions/routes/bridgeToRemote.d.ts +2 -1
  64. package/dist/node/server/routes/bridge/routeDefinitions/routes/bridgeToRemote.d.ts.map +1 -1
  65. package/dist/node/server/routes/bridge/routeDefinitions/routes/bridgeToRemoteEstimate.d.ts +2 -1
  66. package/dist/node/server/routes/bridge/routeDefinitions/routes/bridgeToRemoteEstimate.d.ts.map +1 -1
  67. package/dist/node/server/routes/bridge/routeDefinitions/routes/bridgeToRemoteStatus.d.ts +2 -1
  68. package/dist/node/server/routes/bridge/routeDefinitions/routes/bridgeToRemoteStatus.d.ts.map +1 -1
  69. package/dist/node/server/routes/bridge/routeDefinitions/routes/index.d.ts +1 -0
  70. package/dist/node/server/routes/bridge/routeDefinitions/routes/index.d.ts.map +1 -1
  71. package/dist/node/server/routes/index.d.ts +0 -2
  72. package/dist/node/server/routes/index.d.ts.map +1 -1
  73. package/dist/node/server/server.d.ts +1 -1
  74. package/dist/node/server/server.d.ts.map +1 -1
  75. package/dist/node/util/calculateBridgeFees.d.ts +10 -0
  76. package/dist/node/util/calculateBridgeFees.d.ts.map +1 -0
  77. package/dist/node/util/generateBridgeEstimate.d.ts +5 -0
  78. package/dist/node/util/generateBridgeEstimate.d.ts.map +1 -0
  79. package/dist/node/util/index.d.ts +5 -0
  80. package/dist/node/util/index.d.ts.map +1 -0
  81. package/dist/node/util/validateBridgeEstimate.d.ts +13 -0
  82. package/dist/node/util/validateBridgeEstimate.d.ts.map +1 -0
  83. package/dist/node/util/validateBridgeEstimateExact.d.ts +12 -0
  84. package/dist/node/util/validateBridgeEstimateExact.d.ts.map +1 -0
  85. package/package.json +29 -14
  86. package/src/config/asChainId.ts +7 -0
  87. package/src/config/asToken.ts +7 -0
  88. package/src/config/getBridgeEscrowAddress.ts +13 -0
  89. package/src/config/getBridgeFeesAddress.ts +13 -0
  90. package/src/config/getBridgeSettings.ts +24 -0
  91. package/src/config/getBridgeWalletAccount.ts +34 -0
  92. package/src/config/getFeeStructure.ts +8 -0
  93. package/src/config/getGateway.ts +19 -0
  94. package/src/config/getMaxBridgeAmount.ts +7 -0
  95. package/src/config/getMinBridgeAmount.ts +7 -0
  96. package/src/config/getRemoteChainId.ts +10 -0
  97. package/src/config/getRemoteTokenAddress.ts +10 -0
  98. package/src/config/getTransferAddresses.ts +17 -0
  99. package/src/config/getXl1ChainId.ts +13 -0
  100. package/src/config/getXl1TokenAddress.ts +12 -0
  101. package/src/config/index.ts +15 -0
  102. package/src/interface/service/Observer/LiquidityPoolBridgeObserver/LiquidityPoolBridgeObserver.ts +1 -2
  103. package/src/manifest/getLocator.ts +97 -34
  104. package/src/manifest/public/Ethereum.json +24 -64
  105. package/src/manifest/public/XL1.json +24 -64
  106. package/src/manifest/public/index.ts +0 -6
  107. package/src/modules/EVMLiquidityBridgeTransactionCompletionMonitorSentinel/EVMLiquidityBridgeTransactionCompletionMonitorSentinel.ts +234 -0
  108. package/src/modules/EVMLiquidityBridgeTransactionCompletionMonitorSentinel/index.ts +1 -0
  109. package/src/modules/XL1TransactionCompletionMonitorSentinel/XL1TransactionCompletionMonitorSentinel.ts +166 -0
  110. package/src/modules/XL1TransactionCompletionMonitorSentinel/index.ts +1 -0
  111. package/src/modules/index.ts +2 -1
  112. package/src/server/app.ts +5 -4
  113. package/src/server/routes/addRoutes.ts +3 -2
  114. package/src/server/routes/bridge/addBridgeRoutes.ts +3 -2
  115. package/src/server/routes/bridge/routeDefinitions/getRouteDefinitions.ts +8 -6
  116. package/src/server/routes/bridge/routeDefinitions/pathParams/ChainIdPathParam.ts +16 -13
  117. package/src/server/routes/bridge/routeDefinitions/routes/bridgeConfig.ts +43 -0
  118. package/src/server/routes/bridge/routeDefinitions/routes/bridgeFromRemoteStatus.ts +40 -37
  119. package/src/server/routes/bridge/routeDefinitions/routes/bridgeToRemote.ts +74 -45
  120. package/src/server/routes/bridge/routeDefinitions/routes/bridgeToRemoteEstimate.ts +48 -75
  121. package/src/server/routes/bridge/routeDefinitions/routes/bridgeToRemoteStatus.ts +95 -47
  122. package/src/server/routes/bridge/routeDefinitions/routes/index.ts +1 -0
  123. package/src/server/routes/index.ts +0 -2
  124. package/src/server/server.ts +37 -31
  125. package/src/util/calculateBridgeFees.ts +39 -0
  126. package/src/util/generateBridgeEstimate.ts +64 -0
  127. package/src/util/index.ts +4 -0
  128. package/src/util/validateBridgeEstimate.ts +60 -0
  129. package/src/util/validateBridgeEstimateExact.ts +34 -0
  130. package/dist/node/modules/XL1toEvmBridgeSentinel/XL1toEvmBridgeSentinel.d.ts +0 -47
  131. package/dist/node/modules/XL1toEvmBridgeSentinel/XL1toEvmBridgeSentinel.d.ts.map +0 -1
  132. package/dist/node/modules/XL1toEvmBridgeSentinel/index.d.ts +0 -2
  133. package/dist/node/modules/XL1toEvmBridgeSentinel/index.d.ts.map +0 -1
  134. package/dist/node/server/routes/address/AddressPathParams.d.ts +0 -4
  135. package/dist/node/server/routes/address/AddressPathParams.d.ts.map +0 -1
  136. package/dist/node/server/routes/address/addNodeRoutes.d.ts +0 -3
  137. package/dist/node/server/routes/address/addNodeRoutes.d.ts.map +0 -1
  138. package/dist/node/server/routes/address/get/get.d.ts +0 -4
  139. package/dist/node/server/routes/address/get/get.d.ts.map +0 -1
  140. package/dist/node/server/routes/address/get/index.d.ts +0 -2
  141. package/dist/node/server/routes/address/get/index.d.ts.map +0 -1
  142. package/dist/node/server/routes/address/index.d.ts +0 -2
  143. package/dist/node/server/routes/address/index.d.ts.map +0 -1
  144. package/dist/node/server/routes/address/post/getQueryConfig.d.ts +0 -6
  145. package/dist/node/server/routes/address/post/getQueryConfig.d.ts.map +0 -1
  146. package/dist/node/server/routes/address/post/index.d.ts +0 -2
  147. package/dist/node/server/routes/address/post/index.d.ts.map +0 -1
  148. package/dist/node/server/routes/address/post/post.d.ts +0 -8
  149. package/dist/node/server/routes/address/post/post.d.ts.map +0 -1
  150. package/src/manifest/public/Chain.json +0 -32
  151. package/src/modules/XL1toEvmBridgeSentinel/XL1toEvmBridgeSentinel.ts +0 -156
  152. package/src/modules/XL1toEvmBridgeSentinel/index.ts +0 -1
  153. package/src/server/routes/address/AddressPathParams.ts +0 -3
  154. package/src/server/routes/address/addNodeRoutes.ts +0 -21
  155. package/src/server/routes/address/get/get.ts +0 -30
  156. package/src/server/routes/address/get/index.ts +0 -1
  157. package/src/server/routes/address/index.ts +0 -1
  158. package/src/server/routes/address/post/getQueryConfig.ts +0 -23
  159. package/src/server/routes/address/post/index.ts +0 -1
  160. package/src/server/routes/address/post/post.ts +0 -77
@@ -1,26 +1,32 @@
1
1
  import { BaseMongoSdk, type BaseMongoSdkPrivateConfig } from '@xylabs/mongo'
2
2
  import type { Hash, Logger } from '@xylabs/sdk-js'
3
- import {
4
- asAddress, assertEx, isDefined,
5
- ZERO_ADDRESS,
6
- } from '@xylabs/sdk-js'
3
+ import { assertEx, isDefined } from '@xylabs/sdk-js'
7
4
  import { MemoryArchivist } from '@xyo-network/archivist-memory'
8
5
  import { MongoDBArchivistV2 } from '@xyo-network/archivist-mongodb'
9
6
  import { ViewArchivist } from '@xyo-network/archivist-view'
10
- import {
11
- AddressBalanceDivinerV2, ArchivistSyncDiviner, HeadValidationDiviner,
12
- } from '@xyo-network/chain-modules'
13
- import { MongoMap } from '@xyo-network/chain-protocol'
7
+ import { mapToMapType, MongoMap } from '@xyo-network/chain-protocol'
8
+ import { initEvmProvider } from '@xyo-network/chain-services'
14
9
  import { initTelemetry } from '@xyo-network/chain-telemetry'
15
10
  import { AbstractModule, LoggerModuleStatusReporter } from '@xyo-network/module-abstract'
16
11
  import { ModuleFactoryLocator } from '@xyo-network/module-factory-locator'
17
12
  import type { MongoDBModuleParamsV2 } from '@xyo-network/module-model-mongodb'
18
- import type { WithStorageMeta } from '@xyo-network/payload-model'
19
13
  import { MemorySentinel } from '@xyo-network/sentinel-memory'
14
+ import { HDWallet } from '@xyo-network/wallet'
15
+ import type { BridgeDestinationObservation, SignedHydratedTransaction } from '@xyo-network/xl1-protocol'
20
16
  import type {
21
- BalancesStepSummary, Config, MapType,
17
+ Config, IterableMap, XyoGatewayRunner,
18
+ } from '@xyo-network/xl1-protocol-sdk'
19
+ import {
20
+ hasMongoConfig, SimpleXyoGatewayRunner, SimpleXyoSigner,
22
21
  } from '@xyo-network/xl1-protocol-sdk'
23
- import { hasMongoConfig, MemoryMap } from '@xyo-network/xl1-protocol-sdk'
22
+ import { HttpRpcXyoConnection } from '@xyo-network/xl1-rpc'
23
+ import type { Document } from 'mongodb'
24
+
25
+ import type { EVMLiquidityBridgeTransactionCompletionMonitorSentinelParams, XL1TransactionCompletionMonitorSentinelParams } from '../modules/index.ts'
26
+ import {
27
+ EVMLiquidityBridgeTransactionCompletionMonitorSentinel, EVMLiquidityBridgeTransactionCompletionMonitorSentinelConfigSchema,
28
+ XL1TransactionCompletionMonitorSentinel, XL1TransactionCompletionMonitorSentinelConfigSchema,
29
+ } from '../modules/index.ts'
24
30
 
25
31
  export interface GetLocatorContext {
26
32
  config: Config
@@ -49,8 +55,6 @@ export const getLocator = async (context: GetLocatorContext) => {
49
55
  const statusReporter = logger ? new LoggerModuleStatusReporter(logger) : undefined
50
56
 
51
57
  const locator = new ModuleFactoryLocator()
52
- // Initialize with an in-memory map for backing the summary repository
53
- let summaryMap: MapType<Hash, WithStorageMeta<BalancesStepSummary>> = new MemoryMap<Hash, WithStorageMeta<BalancesStepSummary>>()
54
58
  // If there's a MongoDB configuration
55
59
  const mongoConfig = config.storage?.mongo
56
60
  if (hasMongoConfig(mongoConfig)) {
@@ -66,26 +70,8 @@ export const getLocator = async (context: GetLocatorContext) => {
66
70
  }
67
71
  // Register the MongoDB Archivist as the default
68
72
  locator.register(MongoDBArchivistV2.factory(params), undefined, true)
69
-
70
- // Use a persistent MongoMap for the summary repository if MongoDB is configured
71
- const sdk = new BaseMongoSdk<WithStorageMeta<BalancesStepSummary>>({ ...payloadSdkConfig, collection: 'balance_summary_map' })
72
- summaryMap = await MongoMap.create<MongoMap<Hash, WithStorageMeta<BalancesStepSummary>>>({ sdk })
73
73
  }
74
74
 
75
- locator.register(AddressBalanceDivinerV2.factory<AddressBalanceDivinerV2>({
76
- traceProvider, meterProvider, statusReporter, summaryMap,
77
- }))
78
-
79
- const chainId = isDefined(config.chain.id)
80
- ? assertEx(asAddress(config.chain.id), () => 'chain.id must be an Address')
81
- : ZERO_ADDRESS
82
- locator.register(HeadValidationDiviner.factory<HeadValidationDiviner>({
83
- traceProvider,
84
- meterProvider,
85
- statusReporter,
86
- chainId,
87
- allowedProducers: config.producer.allowlist,
88
- }))
89
75
  locator.register(MemoryArchivist.factory({
90
76
  traceProvider, meterProvider, statusReporter,
91
77
  }))
@@ -95,8 +81,85 @@ export const getLocator = async (context: GetLocatorContext) => {
95
81
  locator.register(ViewArchivist.factory({
96
82
  traceProvider, meterProvider, statusReporter,
97
83
  }))
98
- locator.register(ArchivistSyncDiviner.factory({
99
- traceProvider, meterProvider, statusReporter,
100
- }))
84
+
85
+ const gateway = await getGateway(config)
86
+ const viewer = assertEx(gateway.connectionInstance.viewer, () => 'Gateway viewer is not defined')
87
+ const pendingXl1ToEthXl1BridgeIntentTransactions = await getIterableMap<Hash, SignedHydratedTransaction>(
88
+ config,
89
+ 'liquidity_bridge_xl1_to_eth_xl1_pending',
90
+ )
91
+ const completedXl1ToEthXl1BridgeIntentTransactions = await getIterableMap<Hash, SignedHydratedTransaction>(
92
+ config,
93
+ 'liquidity_bridge_xl1_to_eth_xl1_completed',
94
+ )
95
+
96
+ const xl1TransactionCompletionMonitorSentinelParams: XL1TransactionCompletionMonitorSentinelParams = {
97
+ completedTransactions: completedXl1ToEthXl1BridgeIntentTransactions,
98
+ config: { schema: XL1TransactionCompletionMonitorSentinelConfigSchema },
99
+ meterProvider,
100
+ pendingTransactions: pendingXl1ToEthXl1BridgeIntentTransactions,
101
+ statusReporter,
102
+ traceProvider,
103
+ viewer,
104
+ }
105
+ locator.register(XL1TransactionCompletionMonitorSentinel.factory(xl1TransactionCompletionMonitorSentinelParams))
106
+
107
+ const completedEthXl1BridgeTransactions = await getIterableMap<Hash, BridgeDestinationObservation>(
108
+ config,
109
+ 'liquidity_bridge_eth_xl1_bridge_completed',
110
+ )
111
+ const provider = await initEvmProvider({ config })
112
+ const bridgeAddress = config.bridge.remoteBridgeContractAddress
113
+ const evmLiquidityBridgeTransactionCompletionMonitorSentinelParams: EVMLiquidityBridgeTransactionCompletionMonitorSentinelParams = {
114
+ bridgeAddress,
115
+ completedTransactions: completedEthXl1BridgeTransactions,
116
+ config: { schema: EVMLiquidityBridgeTransactionCompletionMonitorSentinelConfigSchema },
117
+ meterProvider,
118
+ pendingTransactions: completedXl1ToEthXl1BridgeIntentTransactions,
119
+ provider,
120
+ statusReporter,
121
+ traceProvider,
122
+ }
123
+ locator.register(EVMLiquidityBridgeTransactionCompletionMonitorSentinel.factory(evmLiquidityBridgeTransactionCompletionMonitorSentinelParams))
124
+
101
125
  return locator
102
126
  }
127
+
128
+ const getGateway = async (
129
+ config: Config,
130
+ ): Promise<XyoGatewayRunner> => {
131
+ const { mnemonic, chainRpcApiUrl: endpoint } = config.bridge
132
+ const walletPromise = isDefined(mnemonic) ? HDWallet.fromPhrase(mnemonic) : HDWallet.random()
133
+ const account = await walletPromise
134
+ const signer = new SimpleXyoSigner(account)
135
+ const connection = new HttpRpcXyoConnection({ endpoint })
136
+ const gateway = new SimpleXyoGatewayRunner(connection, signer)
137
+ return gateway
138
+ }
139
+
140
+ /**
141
+ * Gets an iterable map based on the storage instructions in the config
142
+ * @param config The config containing storage instructions
143
+ * @param collection The collection to use if using MongoDB for persistence
144
+ * @returns The iterable map
145
+ */
146
+ const getIterableMap = async <K extends {} = string, V extends Document = Document>
147
+ (config: Config, collection: string): Promise<IterableMap<K, V>> => {
148
+ const mongoConfig = config.storage?.mongo
149
+ if (hasMongoConfig(mongoConfig)) {
150
+ const {
151
+ connectionString: dbConnectionString, database: dbName, domain: dbDomain, password: dbPassword, username: dbUserName,
152
+ } = mongoConfig
153
+ const payloadSdkConfig: BaseMongoSdkPrivateConfig = {
154
+ dbConnectionString, dbDomain, dbName, dbPassword, dbUserName,
155
+ }
156
+ const sdkBalanceSummaryMap = new BaseMongoSdk<V>({ ...payloadSdkConfig, collection })
157
+ const result = await MongoMap.create<MongoMap<K, V>>({
158
+ sdk: sdkBalanceSummaryMap,
159
+ getCache: { enabled: true, maxEntries: 5000 },
160
+ })
161
+ return result
162
+ } else {
163
+ return mapToMapType(new Map<K, V>())
164
+ }
165
+ }
@@ -12,75 +12,35 @@
12
12
  {
13
13
  "config": {
14
14
  "accountPath": "1/1'/1'",
15
- "name": "BridgeIntent",
16
- "getCache": {
17
- "enabled": true,
18
- "maxEntries": 5000
19
- },
20
- "payloadSdkConfig": {
21
- "collection": "chain_bridge_intents"
22
- },
23
- "schema": "network.xyo.archivist.config"
15
+ "automations": [
16
+ {
17
+ "frequency": 60000,
18
+ "frequencyUnits": "millis",
19
+ "schema": "network.xyo.automation.interval",
20
+ "type": "interval"
21
+ }
22
+ ],
23
+ "name": "EVMLiquidityBridgeTransactionCompletionMonitorSentinelIntervalSentinel",
24
+ "schema": "network.xyo.sentinel.config",
25
+ "synchronous": true,
26
+ "tasks": [
27
+ {
28
+ "mod": "EVMLiquidityBridgeTransactionCompletionMonitorSentinel",
29
+ "endPoint": "report"
30
+ }
31
+ ]
24
32
  }
25
- },
26
- {
27
- "config": {
28
- "accountPath": "1/1'/2'",
29
- "name": "BridgeSourceObservation",
30
- "getCache": {
31
- "enabled": true,
32
- "maxEntries": 5000
33
- },
34
- "payloadSdkConfig": {
35
- "collection": "chain_bridge_intents"
36
- },
37
- "schema": "network.xyo.archivist.config"
38
- }
39
- },
40
- {
41
- "config": {
42
- "accountPath": "1/1'/3'",
43
- "name": "BridgeDestinationObservation",
44
- "getCache": {
45
- "enabled": true,
46
- "maxEntries": 5000
47
- },
48
- "payloadSdkConfig": {
49
- "collection": "chain_bridge_intents"
50
- },
51
- "schema": "network.xyo.archivist.config"
52
- }
53
- },
54
- {
55
- "config": {
56
- "accountPath": "1/1'/4'",
57
- "name": "BridgeIntentProcessing",
58
- "getCache": {
59
- "enabled": true,
60
- "maxEntries": 5000
61
- },
62
- "payloadSdkConfig": {
63
- "collection": "chain_bridge_intents"
64
- },
65
- "schema": "network.xyo.archivist.config"
66
- }
67
- },
33
+ }
34
+ ],
35
+ "public": [
68
36
  {
69
37
  "config": {
70
- "accountPath": "1/1'/5'",
71
- "name": "BridgeIntentProcessed",
72
- "getCache": {
73
- "enabled": true,
74
- "maxEntries": 5000
75
- },
76
- "payloadSdkConfig": {
77
- "collection": "chain_bridge_intents"
78
- },
79
- "schema": "network.xyo.archivist.config"
38
+ "accountPath": "1/1/1",
39
+ "name": "EVMLiquidityBridgeTransactionCompletionMonitorSentinel",
40
+ "schema": "network.xyo.sentinel.chain.evm.liquidity.bridge.transaction.completion.monitor.config"
80
41
  }
81
42
  }
82
- ],
83
- "public": []
43
+ ]
84
44
  }
85
45
  }
86
46
  ],
@@ -12,75 +12,35 @@
12
12
  {
13
13
  "config": {
14
14
  "accountPath": "1/1'/1'",
15
- "name": "BridgeIntent",
16
- "getCache": {
17
- "enabled": true,
18
- "maxEntries": 5000
19
- },
20
- "payloadSdkConfig": {
21
- "collection": "chain_bridge_intents"
22
- },
23
- "schema": "network.xyo.archivist.config"
15
+ "automations": [
16
+ {
17
+ "frequency": 60000,
18
+ "frequencyUnits": "millis",
19
+ "schema": "network.xyo.automation.interval",
20
+ "type": "interval"
21
+ }
22
+ ],
23
+ "name": "XL1BridgeIntentTransactionCompletionMonitorSentinelIntervalSentinel",
24
+ "schema": "network.xyo.sentinel.config",
25
+ "synchronous": true,
26
+ "tasks": [
27
+ {
28
+ "mod": "XL1BridgeIntentTransactionCompletionMonitorSentinel",
29
+ "endPoint": "report"
30
+ }
31
+ ]
24
32
  }
25
- },
26
- {
27
- "config": {
28
- "accountPath": "1/1'/2'",
29
- "name": "BridgeSourceObservation",
30
- "getCache": {
31
- "enabled": true,
32
- "maxEntries": 5000
33
- },
34
- "payloadSdkConfig": {
35
- "collection": "chain_bridge_intents"
36
- },
37
- "schema": "network.xyo.archivist.config"
38
- }
39
- },
40
- {
41
- "config": {
42
- "accountPath": "1/1'/3'",
43
- "name": "BridgeDestinationObservation",
44
- "getCache": {
45
- "enabled": true,
46
- "maxEntries": 5000
47
- },
48
- "payloadSdkConfig": {
49
- "collection": "chain_bridge_intents"
50
- },
51
- "schema": "network.xyo.archivist.config"
52
- }
53
- },
54
- {
55
- "config": {
56
- "accountPath": "1/1'/4'",
57
- "name": "BridgeIntentProcessing",
58
- "getCache": {
59
- "enabled": true,
60
- "maxEntries": 5000
61
- },
62
- "payloadSdkConfig": {
63
- "collection": "chain_bridge_intents"
64
- },
65
- "schema": "network.xyo.archivist.config"
66
- }
67
- },
33
+ }
34
+ ],
35
+ "public": [
68
36
  {
69
37
  "config": {
70
- "accountPath": "1/1'/5'",
71
- "name": "BridgeIntentProcessed",
72
- "getCache": {
73
- "enabled": true,
74
- "maxEntries": 5000
75
- },
76
- "payloadSdkConfig": {
77
- "collection": "chain_bridge_intents"
78
- },
79
- "schema": "network.xyo.archivist.config"
38
+ "accountPath": "1/1/1",
39
+ "name": "XL1BridgeIntentTransactionCompletionMonitorSentinel",
40
+ "schema": "network.xyo.sentinel.chain.transaction.completion.monitor.config"
80
41
  }
81
42
  }
82
- ],
83
- "public": []
43
+ ]
84
44
  }
85
45
  }
86
46
  ],
@@ -1,13 +1,8 @@
1
1
  import type { ModuleManifest, PackageManifestPayload } from '@xyo-network/manifest-model'
2
2
 
3
- import ChainNode from './Chain.json' with { type: 'json' }
4
3
  import XL1Node from './XL1.json' with { type: 'json' }
5
4
  import EthereumNode from './Ethereum.json' with { type: 'json' }
6
5
 
7
- /**
8
- * Chain Node Manifest
9
- */
10
- export const ChainNodeManifest = ChainNode as PackageManifestPayload
11
6
 
12
7
  /**
13
8
  * XL1 Node Manifest
@@ -23,7 +18,6 @@ export const EthereumNodeManifest = EthereumNode as PackageManifestPayload
23
18
  * Public Child Manifests
24
19
  */
25
20
  export const PublicChildManifests: ModuleManifest[] = [
26
- ...ChainNodeManifest.nodes,
27
21
  ...XL1NodeManifest.nodes,
28
22
  ...EthereumNodeManifest.nodes,
29
23
  ]
@@ -0,0 +1,234 @@
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 { AnyConfigSchema } from '@xyo-network/module-model'
9
+ import { PayloadBuilder } from '@xyo-network/payload-builder'
10
+ import type { Payload } from '@xyo-network/payload-model'
11
+ import { AbstractSentinel } from '@xyo-network/sentinel-abstract'
12
+ import type {
13
+ SentinelConfig, SentinelInstance, SentinelModuleEventData, SentinelParams,
14
+ } from '@xyo-network/sentinel-model'
15
+ import { type LiquidityPoolBridge, LiquidityPoolBridge__factory } from '@xyo-network/typechain'
16
+ import {
17
+ type BridgeDestinationObservation, BridgeDestinationObservationSchema, type BridgeIntent, isBridgeIntent, type SignedHydratedTransaction,
18
+ } from '@xyo-network/xl1-protocol'
19
+ import type { IterableMap, MapType } from '@xyo-network/xl1-protocol-sdk'
20
+ import {
21
+ flattenHydratedTransaction, flattenHydratedTransactions, tryUnflattenHydratedTransaction,
22
+ } from '@xyo-network/xl1-protocol-sdk'
23
+ import { Mutex } from 'async-mutex'
24
+ import { getAddress } from 'ethers/address'
25
+ import type { Provider } from 'ethers/providers'
26
+ import { Wallet } from 'ethers/wallet'
27
+
28
+ export const EVMLiquidityBridgeTransactionCompletionMonitorSentinelConfigSchema
29
+ = 'network.xyo.sentinel.chain.evm.liquidity.bridge.transaction.completion.monitor.config'
30
+ export type EVMLiquidityBridgeTransactionCompletionMonitorSentinelConfigSchema = typeof EVMLiquidityBridgeTransactionCompletionMonitorSentinelConfigSchema
31
+
32
+ /**
33
+ * The configuration for the sentinel
34
+ */
35
+ export type EVMLiquidityBridgeTransactionCompletionMonitorSentinelConfig = SentinelConfig<{
36
+ /**
37
+ * The interval in milliseconds between checking for jobs to fulfill
38
+ */
39
+ jobCheckInterval: number
40
+
41
+ /**
42
+ * The schema for the sentinel config
43
+ */
44
+ schema: EVMLiquidityBridgeTransactionCompletionMonitorSentinelConfigSchema
45
+ }>
46
+
47
+ interface EVMLiquidityBridgeTransactionCompletionMonitorSentinelParamFields {
48
+ /**
49
+ * The address to watch for incoming or outgoing ERC-20 token transfers.
50
+ */
51
+ bridgeAddress: string
52
+
53
+ /**
54
+ * The map of completed transactions to monitor for completion
55
+ */
56
+ completedTransactions: MapType<Hash, BridgeDestinationObservation>
57
+
58
+ /**
59
+ * The map of pending transactions to monitor for completion
60
+ */
61
+ pendingTransactions: IterableMap<Hash, SignedHydratedTransaction>
62
+
63
+ /**
64
+ * An ethers.js Provider connected to the Ethereum network to monitor for ERC-20 transfers.
65
+ */
66
+ provider: Provider
67
+ }
68
+
69
+ export type EVMLiquidityBridgeTransactionCompletionMonitorSentinelParams<TConfig extends
70
+ AnyConfigSchema<EVMLiquidityBridgeTransactionCompletionMonitorSentinelConfig> = AnyConfigSchema<EVMLiquidityBridgeTransactionCompletionMonitorSentinelConfig>,
71
+ > = SentinelParams<TConfig> & EVMLiquidityBridgeTransactionCompletionMonitorSentinelParamFields
72
+
73
+ const defaultJobCheckIntervalMs = 15_000
74
+
75
+ export class EVMLiquidityBridgeTransactionCompletionMonitorSentinel<
76
+ TParams extends EVMLiquidityBridgeTransactionCompletionMonitorSentinelParams = EVMLiquidityBridgeTransactionCompletionMonitorSentinelParams,
77
+ TEventData extends SentinelModuleEventData<SentinelInstance<TParams>> = SentinelModuleEventData<SentinelInstance<TParams>>,
78
+ > extends AbstractSentinel<TParams, TEventData> {
79
+ static override readonly configSchemas = [EVMLiquidityBridgeTransactionCompletionMonitorSentinelConfigSchema]
80
+ static override readonly defaultConfigSchema = EVMLiquidityBridgeTransactionCompletionMonitorSentinelConfigSchema
81
+ protected _attemptsCounter: Counter<Attributes> | undefined
82
+ protected _bridge: LiquidityPoolBridge | undefined
83
+ protected _bridgeChainId: Hex | undefined
84
+ protected _bridgeRemoteChainId: Hex | undefined
85
+ protected _bridgeTokenAddress: Address | undefined
86
+ protected _checkCounter: Counter<Attributes> | undefined
87
+ protected _errorCounter: Counter<Attributes> | undefined
88
+ protected _reportMutex = new Mutex()
89
+ protected _successCounter: Counter<Attributes> | undefined
90
+ protected _wallet: Wallet | undefined
91
+
92
+ protected get bridge(): LiquidityPoolBridge {
93
+ return assertEx(this._bridge, () => new Error('Bridge contract not initialized'))
94
+ }
95
+
96
+ protected get completedTransactions(): MapType<Hash, BridgeDestinationObservation> {
97
+ return assertEx(this.params.completedTransactions, () => 'Completed transactions map is not defined')
98
+ }
99
+
100
+ protected get jobCheckInterval(): number {
101
+ return isDefined(this.config.jobCheckInterval) ? this.config.jobCheckInterval : defaultJobCheckIntervalMs
102
+ }
103
+
104
+ protected get pendingTransactions(): IterableMap<Hash, SignedHydratedTransaction> {
105
+ return assertEx(this.params.pendingTransactions, () => 'Pending transactions map is not defined')
106
+ }
107
+
108
+ protected get wallet(): Wallet {
109
+ return assertEx(this._wallet, () => 'wallet is required')
110
+ }
111
+
112
+ override async createHandler(): Promise<void> {
113
+ await super.createHandler()
114
+ // Create meters for tracking bridge attempts, successes, and errors.
115
+ this._attemptsCounter = this.meter?.createCounter(
116
+ 'evm_liquidity_bridge_transaction_completion_monitor_sentinel_attempts_total',
117
+ { description: 'Number of attempts' },
118
+ )
119
+ this._checkCounter = this.meter?.createCounter(
120
+ 'evm_liquidity_bridge_transaction_completion_monitor_sentinel_check_total',
121
+ { description: 'Number of checks' },
122
+ )
123
+ this._successCounter = this.meter?.createCounter(
124
+ 'evm_liquidity_bridge_transaction_completion_monitor_sentinel_success_total',
125
+ { description: 'Number of successes' },
126
+ )
127
+ this._errorCounter = this.meter?.createCounter(
128
+ 'evm_liquidity_bridge_transaction_completion_monitor_sentinel_errors_total',
129
+ { description: 'Number of errors' },
130
+ )
131
+ const { provider, bridgeAddress } = this.params
132
+
133
+ // Connect to the bridge contract
134
+ // Create a wallet bound to the provider (signer + provider)
135
+ const key = assertEx(this.account?.private?.hex, () => new Error('Account private key is required'))
136
+ this._wallet = new Wallet(key, provider)
137
+ this._bridge = LiquidityPoolBridge__factory.connect(getAddress(bridgeAddress), this._wallet)
138
+
139
+ // Parse bridge network chain ID
140
+ const network = await provider.getNetwork()
141
+ this._bridgeChainId = assertEx(hexFromBigInt(network.chainId), () => new Error('Failed to parse bridgeChainId'))
142
+
143
+ // Parse bridge token address
144
+ const tokenAddress = await this.bridge.token()
145
+ this._bridgeTokenAddress = asAddress(tokenAddress, true)
146
+
147
+ // Parse bridge remote chain ID
148
+ const bridgeRemoteChain = await this.bridge.remoteChain()
149
+ this._bridgeRemoteChainId = asHex(bridgeRemoteChain)
150
+ }
151
+
152
+ override async reportHandler(payloads?: Payload[]): Promise<Payload[]> {
153
+ if (isDefined(payloads) && payloads.length > 0) {
154
+ const signedHydratedTransaction = tryUnflattenHydratedTransaction(payloads)
155
+ if (isDefined(signedHydratedTransaction)) {
156
+ // Insert into pending transactions for monitoring
157
+ const txHash = await PayloadBuilder.hash(signedHydratedTransaction[0])
158
+ this.logger?.info(`Adding transaction ${signedHydratedTransaction[0]} with hash ${txHash} to pending transactions for monitoring`)
159
+ await this.pendingTransactions.set(txHash, signedHydratedTransaction)
160
+ return flattenHydratedTransaction(signedHydratedTransaction)
161
+ }
162
+ return []
163
+ } else {
164
+ if (this._reportMutex.isLocked()) {
165
+ this.logger?.debug(`EVMLiquidityBridgeTransactionCompletionMonitorSentinel [${this.id}] is already running, skipping report [${Date.now()}]`)
166
+ return []
167
+ }
168
+ return await this._reportMutex.runExclusive(async () => {
169
+ const response: Payload[] = []
170
+ if (isUndefined(payloads) || payloads.length === 0) {
171
+ await this.processAllTransactions()
172
+ }
173
+ return response
174
+ })
175
+ }
176
+ }
177
+
178
+ private async processAllTransactions(): Promise<Payload[]> {
179
+ const results: SignedHydratedTransaction[] = []
180
+ for await (const [hash, signedHydratedTransaction] of this.pendingTransactions) {
181
+ const result = await this.processTransaction([hash, signedHydratedTransaction])
182
+ if (isDefined(result)) results.push(result[1])
183
+ await delay(this.jobCheckInterval)
184
+ }
185
+ return flattenHydratedTransactions(results)
186
+ }
187
+
188
+ private async processTransaction(
189
+ [hash, signedHydratedTransaction]: [Hash, SignedHydratedTransaction],
190
+ ): Promise<[Hash, SignedHydratedTransaction] | undefined> {
191
+ this.logger?.info(`Checking for transaction ${signedHydratedTransaction[0]} with hash ${hash}`)
192
+ try {
193
+ let ret: [Hash, SignedHydratedTransaction] | undefined = undefined
194
+ this._checkCounter?.add(1)
195
+ const bridgeIntents = signedHydratedTransaction[1].filter(isBridgeIntent)
196
+ // Only support a single intent per transaction for now
197
+ if (bridgeIntents.length !== 1) {
198
+ await this.pendingTransactions.delete(hash)
199
+ return ret
200
+ }
201
+ const bridgeIntent = bridgeIntents[0]
202
+ this._attemptsCounter?.add(1)
203
+ const bridgeDestinationObservation = await this.relayBridgeIntentSync(bridgeIntent)
204
+ await this.completedTransactions.set(hash, bridgeDestinationObservation)
205
+ await this.pendingTransactions.delete(hash)
206
+ this._successCounter?.add(1)
207
+ return ret
208
+ } catch (error) {
209
+ this._errorCounter?.add(1)
210
+ this.logger?.error(`Error checking for transaction ${signedHydratedTransaction[0]} with hash ${hash}:`, error)
211
+ }
212
+ }
213
+
214
+ /**
215
+ * Relays a given BridgeIntent.
216
+ * @param bridgeIntent The BridgeIntent to relay
217
+ * @returns Relays the intent in a blocking manner, returning the resulting BridgeDestinationObservation if successful
218
+ */
219
+ private async relayBridgeIntentSync(bridgeIntent: BridgeIntent): Promise<BridgeDestinationObservation> {
220
+ // Ensure source observation exists
221
+ const amount = hexToBigInt(bridgeIntent.destAmount)
222
+ const nonce = await this.wallet.getNonce()
223
+ const srcAddress = getAddress(bridgeIntent.srcAddress)
224
+ const destAddress = getAddress(bridgeIntent.destAddress)
225
+ const tx = await this.bridge.bridgeFromRemote(srcAddress, destAddress, amount, { nonce })
226
+ const confirmation = await tx.wait()
227
+ const transactionResponse = await confirmation?.getTransaction()
228
+ const destConfirmation = asHex(transactionResponse?.hash ?? '', true)
229
+ const { schema, ...rest } = bridgeIntent
230
+ const result: BridgeDestinationObservation = new PayloadBuilder<BridgeDestinationObservation>({ schema: BridgeDestinationObservationSchema })
231
+ .fields({ ...rest, destConfirmation }).build()
232
+ return result
233
+ }
234
+ }
@@ -0,0 +1 @@
1
+ export * from './EVMLiquidityBridgeTransactionCompletionMonitorSentinel.ts'