@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.
- package/dist/node/config/asChainId.d.ts +3 -0
- package/dist/node/config/asChainId.d.ts.map +1 -0
- package/dist/node/config/asToken.d.ts +3 -0
- package/dist/node/config/asToken.d.ts.map +1 -0
- package/dist/node/config/getBridgeEscrowAddress.d.ts +5 -0
- package/dist/node/config/getBridgeEscrowAddress.d.ts.map +1 -0
- package/dist/node/config/getBridgeFeesAddress.d.ts +5 -0
- package/dist/node/config/getBridgeFeesAddress.d.ts.map +1 -0
- package/dist/node/config/getBridgeSettings.d.ts +3 -0
- package/dist/node/config/getBridgeSettings.d.ts.map +1 -0
- package/dist/node/config/getBridgeWalletAccount.d.ts +6 -0
- package/dist/node/config/getBridgeWalletAccount.d.ts.map +1 -0
- package/dist/node/config/getFeeStructure.d.ts +4 -0
- package/dist/node/config/getFeeStructure.d.ts.map +1 -0
- package/dist/node/config/getGateway.d.ts +3 -0
- package/dist/node/config/getGateway.d.ts.map +1 -0
- package/dist/node/config/getMaxBridgeAmount.d.ts +4 -0
- package/dist/node/config/getMaxBridgeAmount.d.ts.map +1 -0
- package/dist/node/config/getMinBridgeAmount.d.ts +4 -0
- package/dist/node/config/getMinBridgeAmount.d.ts.map +1 -0
- package/dist/node/config/getRemoteChainId.d.ts +4 -0
- package/dist/node/config/getRemoteChainId.d.ts.map +1 -0
- package/dist/node/config/getRemoteTokenAddress.d.ts +4 -0
- package/dist/node/config/getRemoteTokenAddress.d.ts.map +1 -0
- package/dist/node/config/getTransferAddresses.d.ts +8 -0
- package/dist/node/config/getTransferAddresses.d.ts.map +1 -0
- package/dist/node/config/getXl1ChainId.d.ts +4 -0
- package/dist/node/config/getXl1ChainId.d.ts.map +1 -0
- package/dist/node/config/getXl1TokenAddress.d.ts +4 -0
- package/dist/node/config/getXl1TokenAddress.d.ts.map +1 -0
- package/dist/node/config/index.d.ts +16 -0
- package/dist/node/config/index.d.ts.map +1 -0
- package/dist/node/index.mjs +1133 -206
- package/dist/node/index.mjs.map +1 -1
- package/dist/node/interface/service/Observer/LiquidityPoolBridgeObserver/LiquidityPoolBridgeObserver.d.ts.map +1 -1
- package/dist/node/manifest/getLocator.d.ts.map +1 -1
- package/dist/node/manifest/public/index.d.ts +0 -4
- package/dist/node/manifest/public/index.d.ts.map +1 -1
- package/dist/node/modules/EVMLiquidityBridgeTransactionCompletionMonitorSentinel/EVMLiquidityBridgeTransactionCompletionMonitorSentinel.d.ts +77 -0
- package/dist/node/modules/EVMLiquidityBridgeTransactionCompletionMonitorSentinel/EVMLiquidityBridgeTransactionCompletionMonitorSentinel.d.ts.map +1 -0
- package/dist/node/modules/EVMLiquidityBridgeTransactionCompletionMonitorSentinel/index.d.ts +2 -0
- package/dist/node/modules/EVMLiquidityBridgeTransactionCompletionMonitorSentinel/index.d.ts.map +1 -0
- package/dist/node/modules/XL1TransactionCompletionMonitorSentinel/XL1TransactionCompletionMonitorSentinel.d.ts +56 -0
- package/dist/node/modules/XL1TransactionCompletionMonitorSentinel/XL1TransactionCompletionMonitorSentinel.d.ts.map +1 -0
- package/dist/node/modules/XL1TransactionCompletionMonitorSentinel/index.d.ts +2 -0
- package/dist/node/modules/XL1TransactionCompletionMonitorSentinel/index.d.ts.map +1 -0
- package/dist/node/modules/index.d.ts +2 -1
- package/dist/node/modules/index.d.ts.map +1 -1
- package/dist/node/server/app.d.ts +3 -1
- package/dist/node/server/app.d.ts.map +1 -1
- package/dist/node/server/routes/addRoutes.d.ts +2 -1
- package/dist/node/server/routes/addRoutes.d.ts.map +1 -1
- package/dist/node/server/routes/bridge/addBridgeRoutes.d.ts +2 -1
- package/dist/node/server/routes/bridge/addBridgeRoutes.d.ts.map +1 -1
- package/dist/node/server/routes/bridge/routeDefinitions/getRouteDefinitions.d.ts +2 -1
- package/dist/node/server/routes/bridge/routeDefinitions/getRouteDefinitions.d.ts.map +1 -1
- package/dist/node/server/routes/bridge/routeDefinitions/pathParams/ChainIdPathParam.d.ts +2 -1
- package/dist/node/server/routes/bridge/routeDefinitions/pathParams/ChainIdPathParam.d.ts.map +1 -1
- package/dist/node/server/routes/bridge/routeDefinitions/routes/bridgeConfig.d.ts +4 -0
- package/dist/node/server/routes/bridge/routeDefinitions/routes/bridgeConfig.d.ts.map +1 -0
- package/dist/node/server/routes/bridge/routeDefinitions/routes/bridgeFromRemoteStatus.d.ts +2 -1
- package/dist/node/server/routes/bridge/routeDefinitions/routes/bridgeFromRemoteStatus.d.ts.map +1 -1
- package/dist/node/server/routes/bridge/routeDefinitions/routes/bridgeToRemote.d.ts +2 -1
- package/dist/node/server/routes/bridge/routeDefinitions/routes/bridgeToRemote.d.ts.map +1 -1
- package/dist/node/server/routes/bridge/routeDefinitions/routes/bridgeToRemoteEstimate.d.ts +2 -1
- package/dist/node/server/routes/bridge/routeDefinitions/routes/bridgeToRemoteEstimate.d.ts.map +1 -1
- package/dist/node/server/routes/bridge/routeDefinitions/routes/bridgeToRemoteStatus.d.ts +2 -1
- package/dist/node/server/routes/bridge/routeDefinitions/routes/bridgeToRemoteStatus.d.ts.map +1 -1
- package/dist/node/server/routes/bridge/routeDefinitions/routes/index.d.ts +1 -0
- package/dist/node/server/routes/bridge/routeDefinitions/routes/index.d.ts.map +1 -1
- package/dist/node/server/routes/index.d.ts +0 -2
- package/dist/node/server/routes/index.d.ts.map +1 -1
- package/dist/node/server/server.d.ts +1 -1
- package/dist/node/server/server.d.ts.map +1 -1
- package/dist/node/util/calculateBridgeFees.d.ts +10 -0
- package/dist/node/util/calculateBridgeFees.d.ts.map +1 -0
- package/dist/node/util/generateBridgeEstimate.d.ts +5 -0
- package/dist/node/util/generateBridgeEstimate.d.ts.map +1 -0
- package/dist/node/util/index.d.ts +5 -0
- package/dist/node/util/index.d.ts.map +1 -0
- package/dist/node/util/validateBridgeEstimate.d.ts +13 -0
- package/dist/node/util/validateBridgeEstimate.d.ts.map +1 -0
- package/dist/node/util/validateBridgeEstimateExact.d.ts +12 -0
- package/dist/node/util/validateBridgeEstimateExact.d.ts.map +1 -0
- package/package.json +29 -14
- package/src/config/asChainId.ts +7 -0
- package/src/config/asToken.ts +7 -0
- package/src/config/getBridgeEscrowAddress.ts +13 -0
- package/src/config/getBridgeFeesAddress.ts +13 -0
- package/src/config/getBridgeSettings.ts +24 -0
- package/src/config/getBridgeWalletAccount.ts +34 -0
- package/src/config/getFeeStructure.ts +8 -0
- package/src/config/getGateway.ts +19 -0
- package/src/config/getMaxBridgeAmount.ts +7 -0
- package/src/config/getMinBridgeAmount.ts +7 -0
- package/src/config/getRemoteChainId.ts +10 -0
- package/src/config/getRemoteTokenAddress.ts +10 -0
- package/src/config/getTransferAddresses.ts +17 -0
- package/src/config/getXl1ChainId.ts +13 -0
- package/src/config/getXl1TokenAddress.ts +12 -0
- package/src/config/index.ts +15 -0
- package/src/interface/service/Observer/LiquidityPoolBridgeObserver/LiquidityPoolBridgeObserver.ts +1 -2
- package/src/manifest/getLocator.ts +97 -34
- package/src/manifest/public/Ethereum.json +24 -64
- package/src/manifest/public/XL1.json +24 -64
- package/src/manifest/public/index.ts +0 -6
- package/src/modules/EVMLiquidityBridgeTransactionCompletionMonitorSentinel/EVMLiquidityBridgeTransactionCompletionMonitorSentinel.ts +234 -0
- package/src/modules/EVMLiquidityBridgeTransactionCompletionMonitorSentinel/index.ts +1 -0
- package/src/modules/XL1TransactionCompletionMonitorSentinel/XL1TransactionCompletionMonitorSentinel.ts +166 -0
- package/src/modules/XL1TransactionCompletionMonitorSentinel/index.ts +1 -0
- package/src/modules/index.ts +2 -1
- package/src/server/app.ts +5 -4
- package/src/server/routes/addRoutes.ts +3 -2
- package/src/server/routes/bridge/addBridgeRoutes.ts +3 -2
- package/src/server/routes/bridge/routeDefinitions/getRouteDefinitions.ts +8 -6
- package/src/server/routes/bridge/routeDefinitions/pathParams/ChainIdPathParam.ts +16 -13
- package/src/server/routes/bridge/routeDefinitions/routes/bridgeConfig.ts +43 -0
- package/src/server/routes/bridge/routeDefinitions/routes/bridgeFromRemoteStatus.ts +40 -37
- package/src/server/routes/bridge/routeDefinitions/routes/bridgeToRemote.ts +74 -45
- package/src/server/routes/bridge/routeDefinitions/routes/bridgeToRemoteEstimate.ts +48 -75
- package/src/server/routes/bridge/routeDefinitions/routes/bridgeToRemoteStatus.ts +95 -47
- package/src/server/routes/bridge/routeDefinitions/routes/index.ts +1 -0
- package/src/server/routes/index.ts +0 -2
- package/src/server/server.ts +37 -31
- package/src/util/calculateBridgeFees.ts +39 -0
- package/src/util/generateBridgeEstimate.ts +64 -0
- package/src/util/index.ts +4 -0
- package/src/util/validateBridgeEstimate.ts +60 -0
- package/src/util/validateBridgeEstimateExact.ts +34 -0
- package/dist/node/modules/XL1toEvmBridgeSentinel/XL1toEvmBridgeSentinel.d.ts +0 -47
- package/dist/node/modules/XL1toEvmBridgeSentinel/XL1toEvmBridgeSentinel.d.ts.map +0 -1
- package/dist/node/modules/XL1toEvmBridgeSentinel/index.d.ts +0 -2
- package/dist/node/modules/XL1toEvmBridgeSentinel/index.d.ts.map +0 -1
- package/dist/node/server/routes/address/AddressPathParams.d.ts +0 -4
- package/dist/node/server/routes/address/AddressPathParams.d.ts.map +0 -1
- package/dist/node/server/routes/address/addNodeRoutes.d.ts +0 -3
- package/dist/node/server/routes/address/addNodeRoutes.d.ts.map +0 -1
- package/dist/node/server/routes/address/get/get.d.ts +0 -4
- package/dist/node/server/routes/address/get/get.d.ts.map +0 -1
- package/dist/node/server/routes/address/get/index.d.ts +0 -2
- package/dist/node/server/routes/address/get/index.d.ts.map +0 -1
- package/dist/node/server/routes/address/index.d.ts +0 -2
- package/dist/node/server/routes/address/index.d.ts.map +0 -1
- package/dist/node/server/routes/address/post/getQueryConfig.d.ts +0 -6
- package/dist/node/server/routes/address/post/getQueryConfig.d.ts.map +0 -1
- package/dist/node/server/routes/address/post/index.d.ts +0 -2
- package/dist/node/server/routes/address/post/index.d.ts.map +0 -1
- package/dist/node/server/routes/address/post/post.d.ts +0 -8
- package/dist/node/server/routes/address/post/post.d.ts.map +0 -1
- package/src/manifest/public/Chain.json +0 -32
- package/src/modules/XL1toEvmBridgeSentinel/XL1toEvmBridgeSentinel.ts +0 -156
- package/src/modules/XL1toEvmBridgeSentinel/index.ts +0 -1
- package/src/server/routes/address/AddressPathParams.ts +0 -3
- package/src/server/routes/address/addNodeRoutes.ts +0 -21
- package/src/server/routes/address/get/get.ts +0 -30
- package/src/server/routes/address/get/index.ts +0 -1
- package/src/server/routes/address/index.ts +0 -1
- package/src/server/routes/address/post/getQueryConfig.ts +0 -23
- package/src/server/routes/address/post/index.ts +0 -1
- 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'
|
package/src/modules/index.ts
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
export * from './
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
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
|
-
|
|
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
|
-
|
|
7
|
+
import { getRemoteChainId } from '../../../../../config/index.ts'
|
|
8
8
|
|
|
9
|
-
export const
|
|
10
|
-
(
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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 {
|
|
13
|
+
import { getBridgeSettings } from '../../../../../config/index.ts'
|
|
14
|
+
import { getRemoteChainIdZod } from '../pathParams/index.ts'
|
|
13
15
|
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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
|
-
|
|
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
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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
|
-
|
|
39
|
-
|
|
40
|
+
const confirmed = rand > 0.8 // simulate pending/confirmed
|
|
41
|
+
if (!confirmed) return res.sendStatus(204)
|
|
40
42
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
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 {
|
|
3
|
+
import { asAddress, assertEx } from '@xylabs/sdk-js'
|
|
4
4
|
import { PayloadBuilder } from '@xyo-network/payload-builder'
|
|
5
|
-
import {
|
|
6
|
-
import
|
|
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
|
-
|
|
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 {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
})
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
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
|
}
|