@xyo-network/chain-bridge 1.17.2 → 1.17.6

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 (163) 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 +1155 -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 +6 -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/dist/node/util/validateBridgeTransaction.d.ts +15 -0
  86. package/dist/node/util/validateBridgeTransaction.d.ts.map +1 -0
  87. package/package.json +31 -15
  88. package/src/config/asChainId.ts +7 -0
  89. package/src/config/asToken.ts +7 -0
  90. package/src/config/getBridgeEscrowAddress.ts +13 -0
  91. package/src/config/getBridgeFeesAddress.ts +13 -0
  92. package/src/config/getBridgeSettings.ts +24 -0
  93. package/src/config/getBridgeWalletAccount.ts +34 -0
  94. package/src/config/getFeeStructure.ts +8 -0
  95. package/src/config/getGateway.ts +19 -0
  96. package/src/config/getMaxBridgeAmount.ts +7 -0
  97. package/src/config/getMinBridgeAmount.ts +7 -0
  98. package/src/config/getRemoteChainId.ts +10 -0
  99. package/src/config/getRemoteTokenAddress.ts +10 -0
  100. package/src/config/getTransferAddresses.ts +17 -0
  101. package/src/config/getXl1ChainId.ts +13 -0
  102. package/src/config/getXl1TokenAddress.ts +12 -0
  103. package/src/config/index.ts +15 -0
  104. package/src/interface/service/Observer/LiquidityPoolBridgeObserver/LiquidityPoolBridgeObserver.ts +1 -2
  105. package/src/manifest/getLocator.ts +97 -34
  106. package/src/manifest/public/Ethereum.json +24 -64
  107. package/src/manifest/public/XL1.json +24 -64
  108. package/src/manifest/public/index.ts +0 -6
  109. package/src/modules/EVMLiquidityBridgeTransactionCompletionMonitorSentinel/EVMLiquidityBridgeTransactionCompletionMonitorSentinel.ts +234 -0
  110. package/src/modules/EVMLiquidityBridgeTransactionCompletionMonitorSentinel/index.ts +1 -0
  111. package/src/modules/XL1TransactionCompletionMonitorSentinel/XL1TransactionCompletionMonitorSentinel.ts +166 -0
  112. package/src/modules/XL1TransactionCompletionMonitorSentinel/index.ts +1 -0
  113. package/src/modules/index.ts +2 -1
  114. package/src/server/app.ts +5 -4
  115. package/src/server/routes/addRoutes.ts +3 -2
  116. package/src/server/routes/bridge/addBridgeRoutes.ts +3 -2
  117. package/src/server/routes/bridge/routeDefinitions/getRouteDefinitions.ts +8 -6
  118. package/src/server/routes/bridge/routeDefinitions/pathParams/ChainIdPathParam.ts +16 -13
  119. package/src/server/routes/bridge/routeDefinitions/routes/bridgeConfig.ts +43 -0
  120. package/src/server/routes/bridge/routeDefinitions/routes/bridgeFromRemoteStatus.ts +40 -37
  121. package/src/server/routes/bridge/routeDefinitions/routes/bridgeToRemote.ts +68 -45
  122. package/src/server/routes/bridge/routeDefinitions/routes/bridgeToRemoteEstimate.ts +48 -75
  123. package/src/server/routes/bridge/routeDefinitions/routes/bridgeToRemoteStatus.ts +95 -47
  124. package/src/server/routes/bridge/routeDefinitions/routes/index.ts +1 -0
  125. package/src/server/routes/index.ts +0 -2
  126. package/src/server/server.ts +37 -31
  127. package/src/util/calculateBridgeFees.ts +39 -0
  128. package/src/util/generateBridgeEstimate.ts +64 -0
  129. package/src/util/index.ts +5 -0
  130. package/src/util/validateBridgeEstimate.ts +60 -0
  131. package/src/util/validateBridgeEstimateExact.ts +34 -0
  132. package/src/util/validateBridgeTransaction.ts +40 -0
  133. package/dist/node/modules/XL1toEvmBridgeSentinel/XL1toEvmBridgeSentinel.d.ts +0 -47
  134. package/dist/node/modules/XL1toEvmBridgeSentinel/XL1toEvmBridgeSentinel.d.ts.map +0 -1
  135. package/dist/node/modules/XL1toEvmBridgeSentinel/index.d.ts +0 -2
  136. package/dist/node/modules/XL1toEvmBridgeSentinel/index.d.ts.map +0 -1
  137. package/dist/node/server/routes/address/AddressPathParams.d.ts +0 -4
  138. package/dist/node/server/routes/address/AddressPathParams.d.ts.map +0 -1
  139. package/dist/node/server/routes/address/addNodeRoutes.d.ts +0 -3
  140. package/dist/node/server/routes/address/addNodeRoutes.d.ts.map +0 -1
  141. package/dist/node/server/routes/address/get/get.d.ts +0 -4
  142. package/dist/node/server/routes/address/get/get.d.ts.map +0 -1
  143. package/dist/node/server/routes/address/get/index.d.ts +0 -2
  144. package/dist/node/server/routes/address/get/index.d.ts.map +0 -1
  145. package/dist/node/server/routes/address/index.d.ts +0 -2
  146. package/dist/node/server/routes/address/index.d.ts.map +0 -1
  147. package/dist/node/server/routes/address/post/getQueryConfig.d.ts +0 -6
  148. package/dist/node/server/routes/address/post/getQueryConfig.d.ts.map +0 -1
  149. package/dist/node/server/routes/address/post/index.d.ts +0 -2
  150. package/dist/node/server/routes/address/post/index.d.ts.map +0 -1
  151. package/dist/node/server/routes/address/post/post.d.ts +0 -8
  152. package/dist/node/server/routes/address/post/post.d.ts.map +0 -1
  153. package/src/manifest/public/Chain.json +0 -32
  154. package/src/modules/XL1toEvmBridgeSentinel/XL1toEvmBridgeSentinel.ts +0 -156
  155. package/src/modules/XL1toEvmBridgeSentinel/index.ts +0 -1
  156. package/src/server/routes/address/AddressPathParams.ts +0 -3
  157. package/src/server/routes/address/addNodeRoutes.ts +0 -21
  158. package/src/server/routes/address/get/get.ts +0 -30
  159. package/src/server/routes/address/get/index.ts +0 -1
  160. package/src/server/routes/address/index.ts +0 -1
  161. package/src/server/routes/address/post/getQueryConfig.ts +0 -23
  162. package/src/server/routes/address/post/index.ts +0 -1
  163. package/src/server/routes/address/post/post.ts +0 -77
@@ -1,83 +1,56 @@
1
1
  import type { RouteDefinition } from '@xylabs/express'
2
2
  import { requestHandlerValidator } from '@xylabs/express'
3
- import {
4
- hexToBigInt, toAddress, toHex,
5
- } from '@xylabs/sdk-js'
6
- import { createTransferPayload } from '@xyo-network/chain-protocol'
7
- import { PayloadBuilder } from '@xyo-network/payload-builder'
3
+ import { assertEx, toAddress } from '@xylabs/sdk-js'
8
4
  import { PayloadZodLooseOfSchema, PayloadZodStrictOfSchema } from '@xyo-network/payload-model'
9
- import type {
10
- BridgeIntent, BridgeIntentFields, ChainId, Transfer,
11
- } from '@xyo-network/xl1-protocol'
12
5
  import {
13
- BridgeIntentFieldsZod, BridgeIntentSchema, TransferSchema,
6
+ BridgeIntentFieldsZod, BridgeIntentSchema, toXL1BlockNumber, TransactionBoundWitnessZod, TransferSchema,
14
7
  } from '@xyo-network/xl1-protocol'
15
- import { v4 } from 'uuid'
8
+ import { buildUnsignedTransaction, type Config } from '@xyo-network/xl1-protocol-sdk'
16
9
  import { z } from 'zod'
17
10
 
18
- import { ChainIdPathParam } from '../pathParams/index.ts'
19
-
20
- // TODO: Get from config
21
- const TOKEN_ADDRESS = '0x5FbDB2315678afecb367f032d93F642f64180aa3'
22
- const bridgeableTokenContract = toHex(TOKEN_ADDRESS)
23
- const xl1ChainId: ChainId = toAddress('0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9')
24
- const fixedFee: bigint = 1_000_000_000_000_000n
25
- const percentFee: bigint = 5n // 0.5%
26
- const bridgeEscrowAddress = toAddress('0x0a')
27
- const bridgeFeesAddress = toAddress('0x0b')
28
- const remoteChainId: ChainId = toHex('0x01')
29
-
30
- const params = z.object({ chainId: ChainIdPathParam })
31
- const body = BridgeIntentFieldsZod.pick({
32
- destAddress: true,
33
- srcAddress: true,
34
- srcAmount: true,
35
- })
36
- const response = z.tuple([
37
- PayloadZodStrictOfSchema(BridgeIntentSchema).extend(BridgeIntentFieldsZod.shape),
38
- PayloadZodLooseOfSchema(TransferSchema),
39
- ])
40
- const validateRequest = requestHandlerValidator({
41
- params, body, response,
42
- })
43
-
44
- export const bridgeToRemoteEstimate: RouteDefinition = {
45
- method: 'post',
46
- path: '/bridge/chains/:chainId/bridgeToRemote/estimate',
47
- handlers: validateRequest((req, res) => {
48
- const {
49
- srcAddress, srcAmount, destAddress,
50
- } = req.body
51
-
52
- const srcAmountBigInt = hexToBigInt(srcAmount)
53
- const feeAmount = fixedFee + ((srcAmountBigInt * percentFee) / 100n)
54
- const destAmountBigInt = srcAmountBigInt > feeAmount ? srcAmountBigInt - feeAmount : 0n
55
- const destAmount = toHex(destAmountBigInt)
56
- const nonce = v4()
57
-
58
- const sender = toAddress(srcAddress)
59
-
60
- const bridgeIntentFields: BridgeIntentFields = {
61
- // Source
62
- src: xl1ChainId,
63
- srcAddress,
64
- srcAmount,
65
- srcToken: xl1ChainId,
66
-
67
- // Destination
68
- dest: remoteChainId,
69
- destAddress,
70
- destAmount,
71
- destToken: bridgeableTokenContract,
72
- nonce,
73
- }
74
- const bridgeIntent: BridgeIntent = new PayloadBuilder<BridgeIntent>({ schema: BridgeIntentSchema }).fields(bridgeIntentFields).build()
75
-
76
- const transfer: Transfer = createTransferPayload(sender, {
77
- [bridgeEscrowAddress]: destAmountBigInt,
78
- [bridgeFeesAddress]: feeAmount,
79
- })
80
-
81
- res.json([bridgeIntent, transfer])
82
- }),
11
+ import { getGateway, getXl1ChainId } from '../../../../../config/index.ts'
12
+ import { generateBridgeEstimate } from '../../../../../util/index.ts'
13
+ import { getRemoteChainIdZod } from '../pathParams/index.ts'
14
+
15
+ export const makeBridgeToRemoteEstimateRoute = (config: Config): RouteDefinition => {
16
+ const params = z.object({ chainId: getRemoteChainIdZod(config) })
17
+ const body = BridgeIntentFieldsZod.pick({
18
+ destAddress: true,
19
+ srcAddress: true,
20
+ srcAmount: true,
21
+ })
22
+ const response = z.tuple([
23
+ TransactionBoundWitnessZod,
24
+ PayloadZodStrictOfSchema(BridgeIntentSchema).extend(BridgeIntentFieldsZod.shape),
25
+ PayloadZodLooseOfSchema(TransferSchema),
26
+ ])
27
+ const validateRequest = requestHandlerValidator({
28
+ params, body, response,
29
+ })
30
+
31
+ return {
32
+ method: 'post',
33
+ path: '/bridge/chains/:chainId/bridgeToRemote/estimate',
34
+ handlers: validateRequest(async (req, res) => {
35
+ const xl1ChainId = getXl1ChainId(config)
36
+ const {
37
+ srcAddress, srcAmount, destAddress,
38
+ } = req.body
39
+ const [bridgeIntent, transfer] = await generateBridgeEstimate(srcAddress, srcAmount, destAddress, config)
40
+ const sender = toAddress(srcAddress)
41
+
42
+ // Use viewer to get current block
43
+ const gateway = await getGateway(config)
44
+ const viewer = assertEx(gateway.connectionInstance.viewer, () => new Error('Viewer not available on gateway connection'))
45
+ const currentBlockNumber = await viewer.currentBlockNumber()
46
+ // Calculate nbf/exp
47
+ const nbf = toXL1BlockNumber(currentBlockNumber, true)
48
+ const exp = toXL1BlockNumber(currentBlockNumber + 1000, true)
49
+ // Build unsigned transaction representing the transfer that will be signed by srcAddress
50
+ const [txBw] = await buildUnsignedTransaction(xl1ChainId, [transfer], [bridgeIntent], nbf, exp, sender)
51
+
52
+ // Return the TX to the caller for signing
53
+ res.json([txBw, bridgeIntent, transfer])
54
+ }),
55
+ }
83
56
  }
@@ -1,55 +1,103 @@
1
1
  import type { RouteDefinition } from '@xylabs/express'
2
2
  import { requestHandlerValidator } from '@xylabs/express'
3
- import { toAddress, toHex } from '@xylabs/sdk-js'
3
+ import {
4
+ asAddress, asHex, toHex,
5
+ } from '@xylabs/sdk-js'
4
6
  import { PayloadZodStrictOfSchema } from '@xyo-network/payload-model'
5
- import type { BridgeDestinationObservation } from '@xyo-network/xl1-protocol'
7
+ import type { BridgeDestinationObservation, BridgeSourceObservation } from '@xyo-network/xl1-protocol'
6
8
  import {
7
- BridgeDestinationObservationFieldsZod,
8
- BridgeDestinationObservationSchema,
9
+ BridgeDestinationObservationFieldsZod, BridgeDestinationObservationSchema, BridgeIntentFieldsZod, BridgeIntentSchema, BridgeSourceObservationFieldsZod,
10
+ BridgeSourceObservationSchema,
9
11
  } from '@xyo-network/xl1-protocol'
12
+ import type { Config } from '@xyo-network/xl1-protocol-sdk'
10
13
  import { z } from 'zod'
11
14
 
12
- import { ChainIdPathParam } from '../pathParams/index.ts'
13
-
14
- const params = z.object({
15
- chainId: ChainIdPathParam,
16
- nonce: z.string(),
17
- })
18
- const response = PayloadZodStrictOfSchema(BridgeDestinationObservationSchema).extend(
19
- BridgeDestinationObservationFieldsZod.shape,
20
- )
21
-
22
- const validateRequest = requestHandlerValidator({
23
- params,
24
- response,
25
- })
26
-
27
- export const bridgeToRemoteStatus: RouteDefinition = {
28
- method: 'get',
29
- path: '/bridge/chains/:chainId/bridgeToRemote/status/:nonce',
30
- handlers: validateRequest(async (req, res) => {
31
- const { chainId } = req.params
32
- const rand = await Promise.resolve(Math.random())
33
-
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)
37
-
38
- const confirmed = rand > 0.8 // simulate pending/confirmed
39
- if (!confirmed) return res.sendStatus(204)
40
-
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
- }),
15
+ import { getBridgeSettings } from '../../../../../config/index.ts'
16
+ import { generateBridgeEstimate } from '../../../../../util/index.ts'
17
+ import { getRemoteChainIdZod } from '../pathParams/index.ts'
18
+
19
+ export const makeBridgeToRemoteStatusRoute = (config: Config): RouteDefinition => {
20
+ const params = z.object({
21
+ chainId: getRemoteChainIdZod(config),
22
+ nonce: z.string().nonempty(),
23
+ })
24
+ const query = z.object({ mockStatus: z.coerce.number().default(0) })
25
+ const response = z.union([
26
+ z.tuple([]),
27
+ z.tuple([PayloadZodStrictOfSchema(BridgeIntentSchema).extend(BridgeIntentFieldsZod.shape)]),
28
+ z.tuple([
29
+ PayloadZodStrictOfSchema(BridgeIntentSchema).extend(BridgeIntentFieldsZod.shape),
30
+ PayloadZodStrictOfSchema(BridgeSourceObservationSchema).extend(BridgeSourceObservationFieldsZod.shape),
31
+ ]),
32
+ z.tuple([
33
+ PayloadZodStrictOfSchema(BridgeIntentSchema).extend(BridgeIntentFieldsZod.shape),
34
+ PayloadZodStrictOfSchema(BridgeSourceObservationSchema).extend(BridgeSourceObservationFieldsZod.shape),
35
+ PayloadZodStrictOfSchema(BridgeDestinationObservationSchema).extend(BridgeDestinationObservationFieldsZod.shape),
36
+ ]),
37
+ ])
38
+
39
+ const validateRequest = requestHandlerValidator({
40
+ params, query, response,
41
+ })
42
+
43
+ return {
44
+ method: 'get',
45
+ path: '/bridge/chains/:chainId/bridgeToRemote/status/:nonce',
46
+ handlers: validateRequest(async (req, res) => {
47
+ const { chainId } = req.params
48
+ const { mockStatus = 0 } = req.query
49
+ const result: z.infer<typeof response> = [] as unknown as z.infer<typeof response>
50
+
51
+ const {
52
+ remoteTokenAddress, xl1ChainId, xl1TokenAddress,
53
+ } = await getBridgeSettings(config)
54
+
55
+ const src = xl1ChainId
56
+ const srcAddress = asAddress('2222222222222222222222222222222222222222', true)
57
+ const srcAmount = asHex('0x200', true)
58
+ const srcToken = xl1TokenAddress
59
+
60
+ const dest = chainId
61
+ const destAddress = asAddress('3333333333333333333333333333333333333333', true)
62
+ const destAmount = asHex('0x100', true)
63
+ const destToken = remoteTokenAddress
64
+
65
+ if (mockStatus === 0) return res.sendStatus(404)
66
+ if (mockStatus > 0) {
67
+ const [observation] = await generateBridgeEstimate(srcAddress, srcAmount, destAddress, config, req.params.nonce)
68
+ result[0] = observation
69
+ }
70
+ if (mockStatus > 1) {
71
+ const observation: BridgeSourceObservation = {
72
+ schema: BridgeSourceObservationSchema,
73
+ dest,
74
+ destAddress,
75
+ destAmount,
76
+ destToken,
77
+ src,
78
+ srcAddress,
79
+ srcAmount,
80
+ srcToken,
81
+ }
82
+ result[1] = observation
83
+ }
84
+ if (mockStatus > 2) {
85
+ const observation: BridgeDestinationObservation = {
86
+ schema: BridgeDestinationObservationSchema,
87
+ dest,
88
+ destAddress,
89
+ destAmount,
90
+ destToken,
91
+ src,
92
+ srcAddress,
93
+ srcAmount,
94
+ srcToken,
95
+ destConfirmation: toHex('0x9999'),
96
+ }
97
+ result[2] = observation
98
+ }
99
+
100
+ res.json(result)
101
+ }),
102
+ }
55
103
  }
@@ -1,3 +1,4 @@
1
+ export * from './bridgeConfig.ts'
1
2
  export * from './bridgeFromRemoteStatus.ts'
2
3
  export * from './bridgeToRemote.ts'
3
4
  export * from './bridgeToRemoteEstimate.ts'
@@ -1,3 +1 @@
1
- export * from './address/index.ts'
2
1
  export * from './addRoutes.ts'
3
- export * from './healthz/index.ts'
@@ -1,33 +1,39 @@
1
- import type { Logger } from '@xylabs/sdk-js'
1
+ import {
2
+ assertEx, isDefined, isString, type Logger,
3
+ } from '@xylabs/sdk-js'
4
+ import { boot } from '@xyo-network/bios'
5
+ import type { BiosExternalInterface } from '@xyo-network/bios-model'
2
6
  import type { NodeInstance } from '@xyo-network/node-model'
7
+ import { HDWallet } from '@xyo-network/wallet'
3
8
  import { type Config } from '@xyo-network/xl1-protocol-sdk'
4
9
 
10
+ import { getNode } from '../manifest/index.ts'
5
11
  import { getApp } from './app.ts'
6
12
 
7
13
  const hostname = '::'
8
14
  // const hostname = '0.0.0.0'
9
15
 
10
16
  // TODO: Make nodejs version of bios support round tripping mnemonic between boots
11
- // const getSeedPhrase = async (bios: BiosExternalInterface, config: Config, logger?: Logger): Promise<string> => {
12
- // const storedSeedPhrase = await bios.seedPhraseStore.get('os')
13
- // logger?.debug(`[Bridge] Stored mnemonic: ${storedSeedPhrase}`)
14
- // const { mnemonic } = config.api
15
- // if (isString(storedSeedPhrase) && isString(mnemonic)) {
16
- // logger?.warn('[Bridge] Stored mnemonic does not match supplied. Updating stored mnemonic to supplied.')
17
- // await bios.seedPhraseStore.set('os', mnemonic)
18
- // } else {
19
- // let seedPhrase: string
20
- // if (isString(mnemonic)) {
21
- // seedPhrase = mnemonic
22
- // } else {
23
- // seedPhrase = HDWallet.generateMnemonic()
24
- // logger?.log('[Bridge] No mnemonic provided, using random mnemonic. This is not recommended for production use.')
25
- // logger?.log(`[Bridge] Mnemonic: ${seedPhrase}`)
26
- // }
27
- // await bios.seedPhraseStore.set('os', seedPhrase)
28
- // }
29
- // return assertEx(await bios.seedPhraseStore.get('os'), () => 'Unable to acquire mnemonic from bios')
30
- // }
17
+ const getSeedPhrase = async (bios: BiosExternalInterface, config: Config, logger?: Logger): Promise<string> => {
18
+ const storedSeedPhrase = await bios.seedPhraseStore.get('os')
19
+ logger?.debug(`[Bridge] Stored mnemonic: ${storedSeedPhrase}`)
20
+ const { mnemonic } = config.api
21
+ if (isString(storedSeedPhrase) && isString(mnemonic)) {
22
+ logger?.warn('[Bridge] Stored mnemonic does not match supplied. Updating stored mnemonic to supplied.')
23
+ await bios.seedPhraseStore.set('os', mnemonic)
24
+ } else {
25
+ let seedPhrase: string
26
+ if (isString(mnemonic)) {
27
+ seedPhrase = mnemonic
28
+ } else {
29
+ seedPhrase = HDWallet.generateMnemonic()
30
+ logger?.log('[Bridge] No mnemonic provided, using random mnemonic. This is not recommended for production use.')
31
+ logger?.log(`[Bridge] Mnemonic: ${seedPhrase}`)
32
+ }
33
+ await bios.seedPhraseStore.set('os', seedPhrase)
34
+ }
35
+ return assertEx(await bios.seedPhraseStore.get('os'), () => 'Unable to acquire mnemonic from bios')
36
+ }
31
37
 
32
38
  interface GetServerContext {
33
39
  config: Config
@@ -36,16 +42,16 @@ interface GetServerContext {
36
42
  }
37
43
 
38
44
  export const getServer = async (context: GetServerContext) => {
39
- const { logger } = context
40
- const { port } = context.config.bridge
41
- await Promise.resolve() // bios booting is currently disabled
42
- // const bios = await boot()
43
- // const seedPhrase = isDefined(mnemonic) ? mnemonic : await getSeedPhrase(bios, config, logger)
44
- // const wallet = await HDWallet.fromPhrase(seedPhrase)
45
- // const nodeContext = {
46
- // wallet, logger, config,
47
- // }
48
- const app = getApp()
45
+ const { logger, config } = context
46
+ const { port, mnemonic } = config.bridge
47
+ const bios = await boot()
48
+ const seedPhrase = isDefined(mnemonic) ? mnemonic : await getSeedPhrase(bios, config, logger)
49
+ const wallet = await HDWallet.fromPhrase(seedPhrase)
50
+ const nodeContext = {
51
+ wallet, logger, config,
52
+ }
53
+ const node = context.node ?? await getNode(nodeContext)
54
+ const app = getApp(node, config)
49
55
  const server = app.listen(port, hostname, () => logger?.log(`[Bridge] Server listening at http://${hostname}:${port}`))
50
56
  server.setTimeout(20_000)
51
57
  return server
@@ -0,0 +1,39 @@
1
+ import type { Hex } from '@xylabs/sdk-js'
2
+ import { hexToBigInt, toHex } from '@xylabs/sdk-js'
3
+ import type { Config } from '@xyo-network/xl1-protocol-sdk'
4
+
5
+ export type FeeStructure = Pick<Config['bridge'], 'feeFixed' | 'feeRateBasisPoints'>
6
+
7
+ export interface FeeCalculationResult {
8
+ destAmount: Hex
9
+ feeFixed: Hex
10
+ feeVariable: Hex
11
+ }
12
+
13
+ export const calculateBridgeFees = (srcAmount: Hex, feeStructure: FeeStructure): FeeCalculationResult => {
14
+ const { feeFixed, feeRateBasisPoints } = feeStructure
15
+
16
+ // Format source input
17
+ const srcAmountBigInt = hexToBigInt(srcAmount)
18
+
19
+ // Calculate fixed fee
20
+ const feeFixedBigInt = hexToBigInt(feeFixed)
21
+
22
+ // Integer-safe basis point calculation (floor division)
23
+ const feeVariableBigInt
24
+ = (srcAmountBigInt * BigInt(feeRateBasisPoints)) / 10_000n
25
+ const feeVariable = toHex(feeVariableBigInt)
26
+
27
+ // Calculate total fee
28
+ const feeTotalBigInt = feeFixedBigInt + feeVariableBigInt
29
+
30
+ // Calculate destination amount
31
+ const destAmountBigInt = srcAmountBigInt > feeTotalBigInt ? srcAmountBigInt - feeTotalBigInt : 0n
32
+ const destAmount = toHex(destAmountBigInt)
33
+
34
+ return {
35
+ destAmount,
36
+ feeFixed,
37
+ feeVariable,
38
+ }
39
+ }
@@ -0,0 +1,64 @@
1
+ import type { Hex } from '@xylabs/sdk-js'
2
+ import { hexToBigInt, toAddress } from '@xylabs/sdk-js'
3
+ import { createTransferPayload } from '@xyo-network/chain-protocol'
4
+ import { PayloadBuilder } from '@xyo-network/payload-builder'
5
+ import type {
6
+ BridgeIntent, BridgeIntentFields, Transfer,
7
+ } from '@xyo-network/xl1-protocol'
8
+ import { BridgeIntentSchema } from '@xyo-network/xl1-protocol'
9
+ import { type Config } from '@xyo-network/xl1-protocol-sdk'
10
+ import { v4 } from 'uuid'
11
+
12
+ import { getBridgeSettings } from '../config/index.ts'
13
+ import { calculateBridgeFees } from './calculateBridgeFees.ts'
14
+
15
+ export const generateBridgeEstimate = async (
16
+ srcAddress: Hex,
17
+ srcAmount: Hex,
18
+ destAddress: Hex,
19
+ config: Config,
20
+ nonceOverride?: string,
21
+ ): Promise<[BridgeIntent, Transfer]> => {
22
+ const {
23
+ escrowAddress, feeFixed, feeRateBasisPoints, feesAddress, remoteChainId, remoteTokenAddress, xl1ChainId, xl1TokenAddress,
24
+ } = await getBridgeSettings(config)
25
+
26
+ const sender = toAddress(srcAddress)
27
+
28
+ // Calculate fees and destination amount
29
+ const fees = calculateBridgeFees(srcAmount, { feeFixed, feeRateBasisPoints })
30
+ const {
31
+ destAmount, feeFixed: feeFixedAmount, feeVariable,
32
+ } = fees
33
+
34
+ // Generate a unique nonce for the bridge intent
35
+ const nonce = nonceOverride ?? v4()
36
+
37
+ // Build the bridge intent
38
+ const bridgeIntentFields: BridgeIntentFields = {
39
+ // Source
40
+ src: xl1ChainId,
41
+ srcAddress: sender,
42
+ srcAmount,
43
+ srcToken: xl1TokenAddress,
44
+
45
+ // Destination
46
+ dest: remoteChainId,
47
+ destAddress,
48
+ destAmount,
49
+ destToken: remoteTokenAddress,
50
+ nonce,
51
+ }
52
+ const bridgeIntent: BridgeIntent = new PayloadBuilder<BridgeIntent>({ schema: BridgeIntentSchema }).fields(bridgeIntentFields).build()
53
+
54
+ // Build the transfer
55
+ const context = {
56
+ destAmount, feeFixed: feeFixedAmount, feeVariable,
57
+ }
58
+ const transfer: Transfer = createTransferPayload(sender, {
59
+ [escrowAddress]: hexToBigInt(destAmount),
60
+ [feesAddress]: hexToBigInt(feeFixedAmount) + hexToBigInt(feeVariable),
61
+ }, context)
62
+
63
+ return [bridgeIntent, transfer]
64
+ }
@@ -0,0 +1,5 @@
1
+ export * from './calculateBridgeFees.ts'
2
+ export * from './generateBridgeEstimate.ts'
3
+ export * from './validateBridgeEstimate.ts'
4
+ export * from './validateBridgeEstimateExact.ts'
5
+ export * from './validateBridgeTransaction.ts'
@@ -0,0 +1,60 @@
1
+ import { hexToBigInt, isUndefined } from '@xylabs/sdk-js'
2
+ import type { BridgeIntent, Transfer } from '@xyo-network/xl1-protocol'
3
+ import { type Config } from '@xyo-network/xl1-protocol-sdk'
4
+
5
+ import { getBridgeSettings } from '../config/index.ts'
6
+ import { calculateBridgeFees } from './calculateBridgeFees.js'
7
+
8
+ /**
9
+ * Validates a bridge estimate by checking the intent and transfer against the provided configuration. This method
10
+ * exists to allow for "at least" validation of a bridge estimates in case we want to allow for some flexibility in
11
+ * the bridge estimate.
12
+ * @param intent The BridgeIntent
13
+ * @param transfer The Transfer
14
+ * @param config The Config
15
+ * @returns True if the bridge estimate satisfies bridging conditions, false otherwise.
16
+ */
17
+ export const validateBridgeEstimate = async (
18
+ intent: BridgeIntent,
19
+ transfer: Transfer,
20
+ config: Config,
21
+ ): Promise<boolean> => {
22
+ const {
23
+ escrowAddress, feeFixed, feeRateBasisPoints, feesAddress, remoteChainId, remoteTokenAddress, xl1ChainId, xl1TokenAddress,
24
+ } = await getBridgeSettings(config)
25
+
26
+ // 1. Basic chain + token checks
27
+ if (intent.src !== xl1ChainId) return false
28
+ if (intent.dest !== remoteChainId) return false
29
+ if (intent.srcToken !== xl1TokenAddress) return false
30
+ if (intent.destToken !== remoteTokenAddress) return false
31
+
32
+ // 2. Validate transfer outputs: escrow receives destAmount,
33
+ // feesAddress receives feeFixed + variableFee.
34
+ const outputs = transfer?.transfers ?? {}
35
+ const escrowOut = outputs[escrowAddress]
36
+ const feeOut = outputs[feesAddress]
37
+ if (isUndefined(escrowOut) || isUndefined(feeOut)) return false
38
+
39
+ // Convert hex amounts
40
+ const destAmount = hexToBigInt(intent.destAmount)
41
+ const escrowAmount = hexToBigInt(escrowOut)
42
+
43
+ if (escrowAmount !== destAmount) return false
44
+
45
+ // 3. Recalculate fees and compare
46
+ const fees = calculateBridgeFees(intent.srcAmount, { feeFixed, feeRateBasisPoints })
47
+
48
+ const expectedFeeTotal
49
+ = hexToBigInt(fees.feeFixed) + hexToBigInt(fees.feeVariable)
50
+
51
+ const feeAmount = hexToBigInt(feeOut)
52
+ if (feeAmount < expectedFeeTotal) return false
53
+
54
+ // 4. Check derived dest amount
55
+ if (hexToBigInt(intent.destAmount) !== hexToBigInt(fees.destAmount)) {
56
+ return false
57
+ }
58
+
59
+ return true
60
+ }
@@ -0,0 +1,34 @@
1
+ import { isUndefined } from '@xylabs/sdk-js'
2
+ import { PayloadBuilder } from '@xyo-network/payload-builder'
3
+ import type { BridgeIntent, Transfer } from '@xyo-network/xl1-protocol'
4
+ import { type Config } from '@xyo-network/xl1-protocol-sdk'
5
+
6
+ import { generateBridgeEstimate } from './generateBridgeEstimate.ts'
7
+
8
+ /**
9
+ * Validates a bridge estimate by checking the intent and transfer against the provided configuration. This method
10
+ * only returns true if the bridge estimate matches exactly.
11
+ * @param intent The BridgeIntent
12
+ * @param transfer The Transfer
13
+ * @param config The Config
14
+ * @returns True if the bridge estimate satisfies bridging conditions, false otherwise.
15
+ */
16
+ export const validateBridgeEstimateExact = async (
17
+ intent: BridgeIntent,
18
+ transfer: Transfer,
19
+ config: Config,
20
+ ): Promise<boolean> => {
21
+ const {
22
+ srcAddress, srcAmount, destAddress,
23
+ } = intent
24
+ const [calculatedIntent, calculatedTransfer] = await generateBridgeEstimate(srcAddress, srcAmount, destAddress, config)
25
+ if (isUndefined(calculatedIntent) || isUndefined(calculatedTransfer)) return false
26
+ const { nonce: expectedIntentNonce, ...expectedIntentStatic } = calculatedIntent
27
+ const { nonce: actualIntentNonce, ...actualIntentStatic } = intent
28
+ if (await PayloadBuilder.dataHash(expectedIntentStatic) !== await PayloadBuilder.dataHash(actualIntentStatic)) return false
29
+ const { epoch: expectedTransferEpoch, ...expectedTransferStatic } = calculatedTransfer
30
+ const { epoch: actualTransferEpoch, ...actualTransferStatic } = transfer
31
+ if (await PayloadBuilder.dataHash(expectedTransferStatic) !== await PayloadBuilder.dataHash(actualTransferStatic)) return false
32
+
33
+ return true
34
+ }
@@ -0,0 +1,40 @@
1
+ import { asAddress, isDefined } from '@xylabs/sdk-js'
2
+ import {
3
+ addressesContains, BoundWitnessValidator, payloadHashesContainsAll,
4
+ } from '@xyo-network/boundwitness-validator'
5
+ import { PayloadBuilder } from '@xyo-network/payload-builder'
6
+ import type {
7
+ BridgeIntent, TransactionBoundWitness, Transfer,
8
+ } from '@xyo-network/xl1-protocol'
9
+ import { type Config } from '@xyo-network/xl1-protocol-sdk'
10
+
11
+ /**
12
+ * Validates a bridge estimate by checking the intent and transfer against the provided configuration. This method
13
+ * exists to allow for "at least" validation of a bridge estimates in case we want to allow for some flexibility in
14
+ * the bridge estimate.
15
+ * @ param signedTransaction The signed transaction bound witness
16
+ * @param signedTxBw The signed transaction bound witness
17
+ * @param intent The BridgeIntent
18
+ * @param transfer The Transfer
19
+ * @param config The Config
20
+ * @returns True if the bridge estimate satisfies bridging conditions, false otherwise.
21
+ */
22
+ export const validateBridgeTransaction = async (
23
+ signedTxBw: TransactionBoundWitness,
24
+ intent: BridgeIntent,
25
+ transfer: Transfer,
26
+ config: Config,
27
+ ): Promise<boolean> => {
28
+ const { srcAddress } = intent
29
+
30
+ const errors = await new BoundWitnessValidator(signedTxBw).validate()
31
+ if (isDefined(errors) && errors.length > 0) return false
32
+
33
+ const sender = asAddress(srcAddress, true)
34
+ if (!addressesContains(signedTxBw, sender)) return false
35
+
36
+ const hashes = await PayloadBuilder.hashes([intent, transfer])
37
+ if (!payloadHashesContainsAll(signedTxBw, hashes)) return false
38
+
39
+ return true
40
+ }