@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
@@ -0,0 +1,166 @@
1
+ import type { Attributes, Counter } from '@opentelemetry/api'
2
+ import type { Hash } from '@xylabs/sdk-js'
3
+ import {
4
+ assertEx, delay, isDefined, isNull, isUndefined,
5
+ } from '@xylabs/sdk-js'
6
+ import type { AnyConfigSchema } from '@xyo-network/module-model'
7
+ import { PayloadBuilder } from '@xyo-network/payload-builder'
8
+ import type { Payload } from '@xyo-network/payload-model'
9
+ import { AbstractSentinel } from '@xyo-network/sentinel-abstract'
10
+ import type {
11
+ SentinelConfig, SentinelInstance, SentinelModuleEventData, SentinelParams,
12
+ } from '@xyo-network/sentinel-model'
13
+ import type { SignedHydratedTransaction } from '@xyo-network/xl1-protocol'
14
+ import type {
15
+ IterableMap, MapType, XyoViewer,
16
+ } from '@xyo-network/xl1-protocol-sdk'
17
+ import {
18
+ flattenHydratedTransaction, flattenHydratedTransactions, tryUnflattenHydratedTransaction,
19
+ } from '@xyo-network/xl1-protocol-sdk'
20
+ import { Mutex } from 'async-mutex'
21
+
22
+ export const XL1TransactionCompletionMonitorSentinelConfigSchema = 'network.xyo.sentinel.chain.transaction.completion.monitor.config'
23
+ export type XL1TransactionCompletionMonitorSentinelConfigSchema = typeof XL1TransactionCompletionMonitorSentinelConfigSchema
24
+
25
+ /**
26
+ * The configuration for the sentinel
27
+ */
28
+ export type XL1TransactionCompletionMonitorSentinelConfig = SentinelConfig<{
29
+ /**
30
+ * The interval in milliseconds between checking for jobs to fulfill
31
+ */
32
+ jobCheckInterval: number
33
+
34
+ /**
35
+ * The schema for the sentinel config
36
+ */
37
+ schema: XL1TransactionCompletionMonitorSentinelConfigSchema
38
+ }>
39
+
40
+ interface XL1TransactionCompletionMonitorSentinelParamFields {
41
+ /**
42
+ * The map of completed transactions to monitor for completion
43
+ */
44
+ completedTransactions: MapType<Hash, SignedHydratedTransaction>
45
+
46
+ /**
47
+ * The map of pending transactions to monitor for completion
48
+ */
49
+ pendingTransactions: IterableMap<Hash, SignedHydratedTransaction>
50
+
51
+ /**
52
+ * The viewer instance to use for viewing transactions
53
+ */
54
+ viewer: XyoViewer
55
+ }
56
+
57
+ export type XL1TransactionCompletionMonitorSentinelParams<
58
+ TConfig extends AnyConfigSchema<XL1TransactionCompletionMonitorSentinelConfig> = AnyConfigSchema<XL1TransactionCompletionMonitorSentinelConfig>,
59
+ > = SentinelParams<TConfig> & XL1TransactionCompletionMonitorSentinelParamFields
60
+
61
+ const defaultJobCheckIntervalMs = 15_000
62
+
63
+ export class XL1TransactionCompletionMonitorSentinel<
64
+ TParams extends XL1TransactionCompletionMonitorSentinelParams = XL1TransactionCompletionMonitorSentinelParams,
65
+ TEventData extends SentinelModuleEventData<SentinelInstance<TParams>> = SentinelModuleEventData<SentinelInstance<TParams>>,
66
+ > extends AbstractSentinel<TParams, TEventData> {
67
+ static override readonly configSchemas = [XL1TransactionCompletionMonitorSentinelConfigSchema]
68
+ static override readonly defaultConfigSchema = XL1TransactionCompletionMonitorSentinelConfigSchema
69
+ private _attemptsCounter: Counter<Attributes> | undefined
70
+ private _checkCounter: Counter<Attributes> | undefined
71
+ private _errorCounter: Counter<Attributes> | undefined
72
+ private _reportMutex = new Mutex()
73
+ private _successCounter: Counter<Attributes> | undefined
74
+
75
+ protected get completedTransactions(): MapType<Hash, SignedHydratedTransaction> {
76
+ return assertEx(this.params.completedTransactions, () => 'Completed transactions map is not defined')
77
+ }
78
+
79
+ protected get jobCheckInterval(): number {
80
+ return isDefined(this.config.jobCheckInterval) ? this.config.jobCheckInterval : defaultJobCheckIntervalMs
81
+ }
82
+
83
+ protected get pendingTransactions(): IterableMap<Hash, SignedHydratedTransaction> {
84
+ return assertEx(this.params.pendingTransactions, () => 'Pending transactions map is not defined')
85
+ }
86
+
87
+ protected get viewer(): XyoViewer {
88
+ return assertEx(this.params.viewer, () => 'Viewer is not defined in params')
89
+ }
90
+
91
+ override async createHandler(): Promise<void> {
92
+ await super.createHandler()
93
+ // Create meters for tracking bridge attempts, successes, and errors.
94
+ this._attemptsCounter = this.meter?.createCounter('xl1_transaction_completion_monitor_sentinel_attempts_total', { description: 'Number of attempts' })
95
+ this._checkCounter = this.meter?.createCounter('xl1_transaction_completion_monitor_sentinel_check_total', { description: 'Number of checks' })
96
+ this._successCounter = this.meter?.createCounter('xl1_transaction_completion_monitor_sentinel_success_total', { description: 'Number of successes' })
97
+ this._errorCounter = this.meter?.createCounter('xl1_transaction_completion_monitor_sentinel_errors_total', { description: 'Number of errors' })
98
+ }
99
+
100
+ override async reportHandler(payloads?: Payload[]): Promise<Payload[]> {
101
+ if (isDefined(payloads) && payloads.length > 0) {
102
+ const signedHydratedTransaction = tryUnflattenHydratedTransaction(payloads)
103
+ if (isDefined(signedHydratedTransaction)) {
104
+ // Insert into pending transactions for monitoring
105
+ const txHash = await PayloadBuilder.hash(signedHydratedTransaction[0])
106
+ this.logger?.info(`Adding transaction ${signedHydratedTransaction[0]} with hash ${txHash} to pending transactions for monitoring`)
107
+ await this.pendingTransactions.set(txHash, signedHydratedTransaction)
108
+ return flattenHydratedTransaction(signedHydratedTransaction)
109
+ }
110
+ return []
111
+ } else {
112
+ if (this._reportMutex.isLocked()) {
113
+ this.logger?.debug(`XL1TransactionCompletionMonitorSentinel [${this.id}] is already running, skipping report [${Date.now()}]`)
114
+ return []
115
+ }
116
+ return await this._reportMutex.runExclusive(async () => {
117
+ const response: Payload[] = []
118
+ if (isUndefined(payloads) || payloads.length === 0) {
119
+ await this.processAllTransactions()
120
+ }
121
+ return response
122
+ })
123
+ }
124
+ }
125
+
126
+ private async processAllTransactions(): Promise<Payload[]> {
127
+ const results: SignedHydratedTransaction[] = []
128
+ for await (const [hash, signedHydratedTransaction] of this.pendingTransactions) {
129
+ const result = await this.processTransaction([hash, signedHydratedTransaction])
130
+ if (isDefined(result)) results.push(result[1])
131
+ await delay(this.jobCheckInterval)
132
+ }
133
+ return flattenHydratedTransactions(results)
134
+ }
135
+
136
+ private async processTransaction(
137
+ [hash, signedHydratedTransaction]: [Hash, SignedHydratedTransaction],
138
+ ): Promise<[Hash, SignedHydratedTransaction] | undefined> {
139
+ this.logger?.info(`Checking for transaction ${signedHydratedTransaction[0]} with hash ${hash}`)
140
+ try {
141
+ let ret: [Hash, SignedHydratedTransaction] | undefined = undefined
142
+ this._checkCounter?.add(1)
143
+ this._attemptsCounter?.add(1)
144
+ // Check if the transaction is already included in the chain
145
+ const tx = await this.viewer.transactionByHash(hash)
146
+ if (isDefined(tx) && !isNull(tx)) {
147
+ await this.completedTransactions.set(hash, signedHydratedTransaction)
148
+ this.logger?.info(`Found transaction ${signedHydratedTransaction[0]} with hash ${hash}`)
149
+ this.logger?.info(`Removing completed transaction ${signedHydratedTransaction[0]} with hash ${hash}`)
150
+ await this.pendingTransactions.delete(hash)
151
+ ret = [hash, signedHydratedTransaction]
152
+ } else {
153
+ const currentBlockNumber = await this.viewer.currentBlockNumber()
154
+ if (signedHydratedTransaction[0].exp < currentBlockNumber) {
155
+ this.logger?.info(`Removing expired transaction ${signedHydratedTransaction[0]} with hash ${hash}`)
156
+ await this.pendingTransactions.delete(hash)
157
+ }
158
+ }
159
+ this._successCounter?.add(1)
160
+ return ret
161
+ } catch (error) {
162
+ this._errorCounter?.add(1)
163
+ this.logger?.error(`Error checking for transaction ${signedHydratedTransaction[0]} with hash ${hash}:`, error)
164
+ }
165
+ }
166
+ }
@@ -0,0 +1 @@
1
+ export * from './XL1TransactionCompletionMonitorSentinel.ts'
@@ -1 +1,2 @@
1
- export * from './XL1toEvmBridgeSentinel/index.ts'
1
+ export * from './EVMLiquidityBridgeTransactionCompletionMonitorSentinel/index.ts'
2
+ export * from './XL1TransactionCompletionMonitorSentinel/index.ts'
package/src/server/app.ts CHANGED
@@ -2,6 +2,8 @@ import {
2
2
  customPoweredByHeader, disableCaseSensitiveRouting, disableExpressDefaultPoweredByHeader, getJsonBodyParser, getJsonBodyParserOptions, responseProfiler,
3
3
  standardErrors, standardResponses,
4
4
  } from '@xylabs/express'
5
+ import type { NodeInstance } from '@xyo-network/node-model'
6
+ import type { Config } from '@xyo-network/xl1-protocol-sdk'
5
7
  import compression from 'compression'
6
8
  import cors from 'cors'
7
9
  import type { Express } from 'express'
@@ -10,8 +12,7 @@ import express from 'express'
10
12
  import { addInstrumentation } from './instrumentation.ts'
11
13
  import { addRoutes } from './routes/index.ts'
12
14
 
13
- // export const getApp = (node: NodeInstance): Express => {
14
- export const getApp = (): Express => {
15
+ export const getApp = (node: NodeInstance, config: Config): Express => {
15
16
  addInstrumentation()
16
17
  const app = express()
17
18
  app.set('etag', false)
@@ -23,8 +24,8 @@ export const getApp = (): Express => {
23
24
  disableExpressDefaultPoweredByHeader(app)
24
25
  app.use(customPoweredByHeader)
25
26
  disableCaseSensitiveRouting(app)
26
- // app.node = node
27
- addRoutes(app)
27
+ app.node = node
28
+ addRoutes(app, config)
28
29
  app.use(standardErrors)
29
30
  return app
30
31
  }
@@ -1,7 +1,8 @@
1
+ import type { Config } from '@xyo-network/xl1-protocol-sdk'
1
2
  import type { Express } from 'express'
2
3
 
3
4
  import { addBridgeRoutes } from './bridge/index.ts'
4
5
 
5
- export const addRoutes = (app: Express) => {
6
- addBridgeRoutes(app)
6
+ export const addRoutes = (app: Express, config: Config) => {
7
+ addBridgeRoutes(app, config)
7
8
  }
@@ -1,9 +1,10 @@
1
+ import type { Config } from '@xyo-network/xl1-protocol-sdk'
1
2
  import type { Express } from 'express'
2
3
 
3
4
  import { getRouteDefinitions } from './routeDefinitions/index.ts'
4
5
 
5
- export const addBridgeRoutes = (app: Express) => {
6
- const routeDefinitions = getRouteDefinitions()
6
+ export const addBridgeRoutes = (app: Express, config: Config) => {
7
+ const routeDefinitions = getRouteDefinitions(config)
7
8
  for (const definition of routeDefinitions) {
8
9
  app[definition.method](definition.path, definition.handlers)
9
10
  }
@@ -1,14 +1,16 @@
1
1
  import type { RouteDefinition } from '@xylabs/express'
2
+ import type { Config } from '@xyo-network/xl1-protocol-sdk'
2
3
 
3
4
  import {
4
- bridgeFromRemoteStatus, bridgeToRemote, bridgeToRemoteEstimate, bridgeToRemoteStatus,
5
+ makeBridgeConfigRoute, makeBridgeFromRemoteStatusRoute, makeBridgeToRemoteEstimateRoute, makeBridgeToRemoteRoute, makeBridgeToRemoteStatusRoute,
5
6
  } from './routes/index.ts'
6
7
 
7
- export const getRouteDefinitions = (): RouteDefinition[] => {
8
+ export const getRouteDefinitions = (config: Config): RouteDefinition[] => {
8
9
  return [
9
- bridgeFromRemoteStatus,
10
- bridgeToRemote,
11
- bridgeToRemoteEstimate,
12
- bridgeToRemoteStatus,
10
+ makeBridgeConfigRoute(config),
11
+ makeBridgeToRemoteEstimateRoute(config),
12
+ makeBridgeToRemoteRoute(config),
13
+ makeBridgeToRemoteStatusRoute(config),
14
+ makeBridgeFromRemoteStatusRoute(config),
13
15
  ]
14
16
  }
@@ -1,18 +1,21 @@
1
1
  import {
2
- hexFromHexString, HexZod, isAddress, isUndefined,
3
- toAddress,
2
+ asHex, HexZod, isUndefined,
4
3
  } from '@xylabs/sdk-js'
5
4
  import type { ChainId } from '@xyo-network/xl1-protocol'
5
+ import type { Config } from '@xyo-network/xl1-protocol-sdk'
6
6
 
7
- const remoteChainId: ChainId = toAddress('0x01')
7
+ import { getRemoteChainId } from '../../../../../config/index.ts'
8
8
 
9
- export const ChainIdPathParam = HexZod.refine(
10
- (val) => {
11
- const chainIdHex = hexFromHexString(val, { prefix: true })
12
- if (isAddress(chainIdHex)) return false
13
- const suppliedChainId = toAddress(chainIdHex)
14
- if (isUndefined(suppliedChainId)) return false
15
- return suppliedChainId === remoteChainId
16
- },
17
- { message: `Only ${remoteChainId} is supported` },
18
- )
9
+ export const getRemoteChainIdZod = (config: Config) => {
10
+ const remoteChainId: ChainId = getRemoteChainId(config)
11
+ return HexZod.superRefine((val, ctx) => {
12
+ const chainId = asHex(val)
13
+ if (isUndefined(chainId)) {
14
+ ctx.addIssue('Not a valid chain id')
15
+ return
16
+ }
17
+ if (chainId !== remoteChainId) {
18
+ ctx.addIssue(`Only ${remoteChainId} is supported`)
19
+ }
20
+ })
21
+ }
@@ -0,0 +1,43 @@
1
+ import type { RouteDefinition } from '@xylabs/express'
2
+ import { requestHandlerValidator } from '@xylabs/express'
3
+ import { BridgeSettingsZod, type Config } from '@xyo-network/xl1-protocol-sdk'
4
+
5
+ import { getBridgeSettings } from '../../../../../config/index.ts'
6
+
7
+ const response = BridgeSettingsZod
8
+
9
+ const validateRequest = requestHandlerValidator({ response })
10
+
11
+ export const makeBridgeConfigRoute = (config: Config): RouteDefinition => {
12
+ return {
13
+ method: 'get',
14
+ path: '/bridge/chains/:chainId/config',
15
+ handlers: validateRequest(async (_, res) => {
16
+ const {
17
+ escrowAddress,
18
+ feeFixed,
19
+ feeRateBasisPoints,
20
+ feesAddress,
21
+ maxBridgeAmount,
22
+ minBridgeAmount,
23
+ remoteChainId,
24
+ remoteTokenAddress,
25
+ xl1ChainId,
26
+ xl1TokenAddress,
27
+ } = await getBridgeSettings(config)
28
+ const sanitizedConfig = {
29
+ escrowAddress,
30
+ feeFixed,
31
+ feeRateBasisPoints,
32
+ feesAddress,
33
+ maxBridgeAmount,
34
+ minBridgeAmount,
35
+ remoteChainId,
36
+ remoteTokenAddress,
37
+ xl1ChainId,
38
+ xl1TokenAddress,
39
+ }
40
+ res.json(sanitizedConfig)
41
+ }),
42
+ }
43
+ }
@@ -7,49 +7,52 @@ import {
7
7
  BridgeDestinationObservationFieldsZod,
8
8
  BridgeDestinationObservationSchema,
9
9
  } from '@xyo-network/xl1-protocol'
10
+ import type { Config } from '@xyo-network/xl1-protocol-sdk'
10
11
  import { z } from 'zod'
11
12
 
12
- import { ChainIdPathParam } from '../pathParams/index.ts'
13
+ import { getBridgeSettings } from '../../../../../config/index.ts'
14
+ import { getRemoteChainIdZod } from '../pathParams/index.ts'
13
15
 
14
- const params = z.object({
15
- chainId: ChainIdPathParam,
16
- nonce: z.string(),
17
- })
18
- const response = PayloadZodStrictOfSchema(BridgeDestinationObservationSchema).extend(
19
- BridgeDestinationObservationFieldsZod.shape,
20
- )
16
+ export const makeBridgeFromRemoteStatusRoute = (config: Config): RouteDefinition => {
17
+ const params = z.object({
18
+ chainId: getRemoteChainIdZod(config),
19
+ nonce: z.string().nonempty(),
20
+ })
21
+ const response = PayloadZodStrictOfSchema(BridgeDestinationObservationSchema).extend(
22
+ BridgeDestinationObservationFieldsZod.shape,
23
+ )
24
+ const validateRequest = requestHandlerValidator({ params, response })
21
25
 
22
- const validateRequest = requestHandlerValidator({
23
- params,
24
- response,
25
- })
26
+ return {
27
+ method: 'get',
28
+ path: '/bridge/chains/:chainId/bridgeFromRemote/status/:nonce',
29
+ handlers: validateRequest(async (req, res) => {
30
+ const {
31
+ remoteChainId, remoteTokenAddress, xl1ChainId, xl1TokenAddress,
32
+ } = await getBridgeSettings(config)
26
33
 
27
- export const bridgeFromRemoteStatus: RouteDefinition = {
28
- method: 'get',
29
- path: '/bridge/chains/:chainId/bridgeFromRemote/status/:nonce',
30
- handlers: validateRequest(async (req, res) => {
31
- const { chainId } = req.params
32
- const rand = await Promise.resolve(Math.random())
34
+ const rand = await Promise.resolve(Math.random())
33
35
 
34
- // TODO: Replace with actual lookup logic (e.g. database or chain query)
35
- const found = rand > 0.5 // simulate lookup
36
- if (!found) return res.sendStatus(404)
36
+ // TODO: Replace with actual lookup logic (e.g. database or chain query)
37
+ const found = rand > 0.5 // simulate lookup
38
+ if (!found) return res.sendStatus(404)
37
39
 
38
- const confirmed = rand > 0.8 // simulate pending/confirmed
39
- if (!confirmed) return res.sendStatus(204)
40
+ const confirmed = rand > 0.8 // simulate pending/confirmed
41
+ if (!confirmed) return res.sendStatus(204)
40
42
 
41
- const observation: BridgeDestinationObservation = {
42
- schema: BridgeDestinationObservationSchema,
43
- dest: chainId,
44
- destAddress: toAddress('0xabc'),
45
- destAmount: toHex('0x100'),
46
- destToken: toAddress('0xdef'),
47
- src: toAddress('0x02'),
48
- srcAddress: toAddress('0x123'),
49
- srcAmount: toHex('0x200'),
50
- srcToken: toHex('0x456'),
51
- destConfirmation: toHex('0x9999'),
52
- }
53
- res.json(observation)
54
- }),
43
+ const observation: BridgeDestinationObservation = {
44
+ schema: BridgeDestinationObservationSchema,
45
+ dest: xl1ChainId,
46
+ destAddress: toAddress('0xabc'),
47
+ destAmount: toHex('0x100'),
48
+ destToken: xl1TokenAddress,
49
+ src: remoteChainId,
50
+ srcAddress: toAddress('0x123'),
51
+ srcAmount: toHex('0x200'),
52
+ srcToken: remoteTokenAddress,
53
+ destConfirmation: toHex('0x9999'),
54
+ }
55
+ res.json(observation)
56
+ }),
57
+ }
55
58
  }
@@ -1,53 +1,82 @@
1
1
  import type { RouteDefinition } from '@xylabs/express'
2
2
  import { requestHandlerValidator } from '@xylabs/express'
3
- import { asHash } from '@xylabs/sdk-js'
3
+ import { asAddress, assertEx } from '@xylabs/sdk-js'
4
4
  import { PayloadBuilder } from '@xyo-network/payload-builder'
5
- import { PayloadZodLooseOfSchema, PayloadZodStrictOfSchema } from '@xyo-network/payload-model'
6
- import type { BridgeSourceObservation, BridgeSourceObservationFields } from '@xyo-network/xl1-protocol'
5
+ import { PayloadZodStrictOfSchema } from '@xyo-network/payload-model'
6
+ import { asSentinelInstance } from '@xyo-network/sentinel-model'
7
+ import type {
8
+ BridgeSourceObservation, BridgeSourceObservationFields, SignedHydratedTransaction,
9
+ } from '@xyo-network/xl1-protocol'
7
10
  import {
8
- BridgeIntentFieldsZod,
9
- BridgeIntentSchema,
10
- BridgeSourceObservationFieldsZod,
11
- BridgeSourceObservationSchema,
12
- TransferSchema,
11
+ BridgeIntentFieldsZod, BridgeIntentSchema, BridgeSourceObservationFieldsZod, BridgeSourceObservationSchema, SignedTransactionBoundWitnessZod,
12
+ TransferZod,
13
13
  } from '@xyo-network/xl1-protocol'
14
+ import { type Config, flattenHydratedTransaction } from '@xyo-network/xl1-protocol-sdk'
14
15
  import { z } from 'zod'
15
16
 
16
- import { ChainIdPathParam } from '../pathParams/index.ts'
17
-
18
- const params = z.object({ chainId: ChainIdPathParam })
19
- const body = z.tuple([
20
- // TODO: TransactionBoundWitness
21
- PayloadZodStrictOfSchema(BridgeIntentSchema).extend(BridgeIntentFieldsZod.shape),
22
- PayloadZodLooseOfSchema(TransferSchema),
23
- ])
24
- const response = PayloadZodStrictOfSchema(BridgeSourceObservationSchema).extend(BridgeSourceObservationFieldsZod.shape)
25
-
26
- const validateRequest = requestHandlerValidator({
27
- params,
28
- body,
29
- response,
30
- })
31
-
32
- export const bridgeToRemote: RouteDefinition = {
33
- method: 'post',
34
- path: '/bridge/chains/:chainId/bridgeToRemote',
35
- handlers: validateRequest(async (req, res) => {
36
- const { body } = req
37
- const [bridgeIntent] = body
38
- // TODO: Execute bridge transaction on-chain
39
- const srcConfirmation = await Promise.resolve(asHash('0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef'))
40
-
41
- // Extract common fields for BridgeSourceObservation from BridgeIntent
42
- const bridgeCommonFieldsZod = z.object({}).extend(BridgeSourceObservationFieldsZod.shape)
43
- const bridgeCommonFields = bridgeCommonFieldsZod.parse(bridgeIntent)
44
- const bridgeObservationFields: BridgeSourceObservationFields = {
45
- ...bridgeCommonFields,
46
- srcConfirmation,
47
- }
48
- const bridgeObservation: BridgeSourceObservation = new PayloadBuilder<BridgeSourceObservation>(
49
- { schema: BridgeSourceObservationSchema },
50
- ).fields(bridgeObservationFields).build()
51
- res.json(bridgeObservation)
52
- }),
17
+ import { validateBridgeEstimateExact } from '../../../../../util/index.ts'
18
+ import { getRemoteChainIdZod } from '../pathParams/index.ts'
19
+
20
+ export const makeBridgeToRemoteRoute = (config: Config): RouteDefinition => {
21
+ const params = z.object({ chainId: getRemoteChainIdZod(config) })
22
+ const body = z.tuple([
23
+ SignedTransactionBoundWitnessZod,
24
+ PayloadZodStrictOfSchema(BridgeIntentSchema).extend(BridgeIntentFieldsZod.shape),
25
+ TransferZod,
26
+ ])
27
+ const response = PayloadZodStrictOfSchema(BridgeSourceObservationSchema).extend(BridgeSourceObservationFieldsZod.shape)
28
+
29
+ const validateRequest = requestHandlerValidator({
30
+ params, body, response,
31
+ })
32
+ return {
33
+ method: 'post',
34
+ path: '/bridge/chains/:chainId/bridgeToRemote',
35
+ handlers: validateRequest(async (req, res) => {
36
+ const [signedTxBw, bridgeIntent, transfer] = req.body
37
+ const { srcAddress } = bridgeIntent
38
+ const { node } = req.app
39
+
40
+ // TODO: Validate TX is valid BW
41
+ // BoundWitnessBuilder.validate(signedTxBw)
42
+
43
+ // Validate TX has address from srcAddress
44
+ // const sender = asAddress(srcAddress, true)
45
+ // const srcAddressValid = signedTxBw.addresses.includes(sender)
46
+ // if (!srcAddressValid) {
47
+ // res.status(400).send()
48
+ // return
49
+ // }
50
+
51
+ // Validate estimate
52
+ const estimateValid = await validateBridgeEstimateExact(bridgeIntent, transfer, config)
53
+ if (!estimateValid) {
54
+ res.status(400).send()
55
+ return
56
+ }
57
+
58
+ // Submit to sentinel
59
+ const mod = await node.resolve('XL1BridgeIntentTransactionCompletionMonitorSentinel')
60
+ const sentinel = assertEx(asSentinelInstance(mod), () => 'Error resolving XL1BridgeIntentTransactionCompletionMonitorSentinel')
61
+ const singedHydratedTransaction: SignedHydratedTransaction = [signedTxBw, [transfer, bridgeIntent]]
62
+ const observation = await sentinel.report(flattenHydratedTransaction(singedHydratedTransaction))
63
+ if (observation.length === 0) {
64
+ console.error('Error submitting bridge intent transaction to sentinel')
65
+ res.status(500).send()
66
+ return
67
+ }
68
+ const srcConfirmation = await PayloadBuilder.hash(signedTxBw)
69
+
70
+ // Create BridgeObservation
71
+ const bridgeCommonFieldsZod = z.object({}).extend(BridgeSourceObservationFieldsZod.shape)
72
+ const bridgeCommonFields = bridgeCommonFieldsZod.parse(bridgeIntent)
73
+ const bridgeObservationFields: BridgeSourceObservationFields = { ...bridgeCommonFields, srcConfirmation }
74
+ const bridgeObservation: BridgeSourceObservation = new PayloadBuilder<BridgeSourceObservation>(
75
+ { schema: BridgeSourceObservationSchema },
76
+ ).fields(bridgeObservationFields).build()
77
+
78
+ // Return bridge observation to caller
79
+ res.json(bridgeObservation)
80
+ }),
81
+ }
53
82
  }