@xyo-network/chain-bridge 1.15.2 → 1.15.4
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/README.md +1 -1
- package/dist/node/driver/indexer/ChainHydratedBlocksObservable.d.ts +4 -4
- package/dist/node/driver/indexer/ChainHydratedBlocksObservable.d.ts.map +1 -1
- package/dist/node/driver/mongo/MongoMap.d.ts +3 -2
- package/dist/node/driver/mongo/MongoMap.d.ts.map +1 -1
- package/dist/node/index.mjs +300 -683
- package/dist/node/index.mjs.map +1 -1
- package/dist/node/interface/interface/IntentIndexerInterface.d.ts +5 -3
- package/dist/node/interface/interface/IntentIndexerInterface.d.ts.map +1 -1
- package/dist/node/interface/service/Observer/ERC20TransferObserver/ERC20TransferObserver.d.ts +28 -0
- package/dist/node/interface/service/Observer/ERC20TransferObserver/ERC20TransferObserver.d.ts.map +1 -0
- package/dist/node/interface/service/Observer/ERC20TransferObserver/index.d.ts +2 -0
- package/dist/node/interface/service/Observer/ERC20TransferObserver/index.d.ts.map +1 -0
- package/dist/node/interface/service/Observer/ERC20TransferObserver/spec/ERC20TransferObserver.spec.d.ts +2 -0
- package/dist/node/interface/service/Observer/ERC20TransferObserver/spec/ERC20TransferObserver.spec.d.ts.map +1 -0
- package/dist/node/interface/service/Observer/LiquidityPoolBridgeObserver/LiquidityPoolBridgeObserver.d.ts +36 -0
- package/dist/node/interface/service/Observer/LiquidityPoolBridgeObserver/LiquidityPoolBridgeObserver.d.ts.map +1 -0
- package/dist/node/interface/service/Observer/LiquidityPoolBridgeObserver/index.d.ts +2 -0
- package/dist/node/interface/service/Observer/LiquidityPoolBridgeObserver/index.d.ts.map +1 -0
- package/dist/node/interface/service/Observer/LiquidityPoolBridgeObserver/spec/LiquidityPoolBridgeObserver.spec.d.ts +2 -0
- package/dist/node/interface/service/Observer/LiquidityPoolBridgeObserver/spec/LiquidityPoolBridgeObserver.spec.d.ts.map +1 -0
- package/dist/node/interface/service/Observer/Observer.d.ts +1 -1
- package/dist/node/interface/service/Observer/Observer.d.ts.map +1 -1
- package/dist/node/interface/service/{ChainBridgeRelay → Relay/ChainBridgeRelay}/ChainBridgeRelayInterface.d.ts +1 -1
- package/dist/node/interface/service/Relay/ChainBridgeRelay/ChainBridgeRelayInterface.d.ts.map +1 -0
- package/dist/node/interface/service/{ChainBridgeRelay → Relay/ChainBridgeRelay}/ChainBridgeRelayService.d.ts +1 -1
- package/dist/node/interface/service/Relay/ChainBridgeRelay/ChainBridgeRelayService.d.ts.map +1 -0
- package/dist/node/interface/service/Relay/ChainBridgeRelay/index.d.ts.map +1 -0
- package/dist/node/interface/service/Relay/ChainBridgeRelay/spec/ChainBridgeRelayService.spec.d.ts.map +1 -0
- package/dist/node/interface/service/Relay/LiquidityPoolBridgeRelay/LiquidityPoolBridgeRelay.d.ts +57 -0
- package/dist/node/interface/service/Relay/LiquidityPoolBridgeRelay/LiquidityPoolBridgeRelay.d.ts.map +1 -0
- package/dist/node/interface/service/Relay/LiquidityPoolBridgeRelay/index.d.ts +2 -0
- package/dist/node/interface/service/Relay/LiquidityPoolBridgeRelay/index.d.ts.map +1 -0
- package/dist/node/interface/service/Relay/LiquidityPoolBridgeRelay/spec/LiquidityPoolBridgeRelay.spec.d.ts +2 -0
- package/dist/node/interface/service/Relay/LiquidityPoolBridgeRelay/spec/LiquidityPoolBridgeRelay.spec.d.ts.map +1 -0
- package/dist/node/interface/service/Relay/index.d.ts +2 -0
- package/dist/node/interface/service/Relay/index.d.ts.map +1 -0
- package/dist/node/interface/service/index.d.ts +1 -1
- package/dist/node/interface/service/index.d.ts.map +1 -1
- package/dist/node/manifest/getLocator.d.ts.map +1 -1
- package/dist/node/manifest/public/index.d.ts +6 -2
- package/dist/node/manifest/public/index.d.ts.map +1 -1
- package/dist/node/server/app.d.ts +1 -2
- package/dist/node/server/app.d.ts.map +1 -1
- package/dist/node/server/routes/addRoutes.d.ts.map +1 -1
- package/dist/node/server/routes/bridge/addBridgeRoutes.d.ts +3 -0
- package/dist/node/server/routes/bridge/addBridgeRoutes.d.ts.map +1 -0
- package/dist/node/server/routes/bridge/index.d.ts +2 -0
- package/dist/node/server/routes/bridge/index.d.ts.map +1 -0
- package/dist/node/server/routes/bridge/middleware/index.d.ts +2 -0
- package/dist/node/server/routes/bridge/middleware/index.d.ts.map +1 -0
- package/dist/node/server/routes/bridge/middleware/requestHandlerValidator.d.ts +32 -0
- package/dist/node/server/routes/bridge/middleware/requestHandlerValidator.d.ts.map +1 -0
- package/dist/node/server/routes/bridge/routeDefinitions/getRouteDefinitions.d.ts +3 -0
- package/dist/node/server/routes/bridge/routeDefinitions/getRouteDefinitions.d.ts.map +1 -0
- package/dist/node/server/routes/bridge/routeDefinitions/index.d.ts +2 -0
- package/dist/node/server/routes/bridge/routeDefinitions/index.d.ts.map +1 -0
- package/dist/node/server/routes/bridge/routeDefinitions/pathParams/ChainIdPathParam.d.ts +6 -0
- package/dist/node/server/routes/bridge/routeDefinitions/pathParams/ChainIdPathParam.d.ts.map +1 -0
- package/dist/node/server/routes/bridge/routeDefinitions/pathParams/index.d.ts +2 -0
- package/dist/node/server/routes/bridge/routeDefinitions/pathParams/index.d.ts.map +1 -0
- package/dist/node/server/routes/bridge/routeDefinitions/routeDefinition.d.ts +8 -0
- package/dist/node/server/routes/bridge/routeDefinitions/routeDefinition.d.ts.map +1 -0
- package/dist/node/server/routes/bridge/routeDefinitions/routes/bridgeFromRemoteStatus.d.ts +3 -0
- package/dist/node/server/routes/bridge/routeDefinitions/routes/bridgeFromRemoteStatus.d.ts.map +1 -0
- package/dist/node/server/routes/bridge/routeDefinitions/routes/bridgeToRemote.d.ts +3 -0
- package/dist/node/server/routes/bridge/routeDefinitions/routes/bridgeToRemote.d.ts.map +1 -0
- package/dist/node/server/routes/bridge/routeDefinitions/routes/bridgeToRemoteEstimate.d.ts +3 -0
- package/dist/node/server/routes/bridge/routeDefinitions/routes/bridgeToRemoteEstimate.d.ts.map +1 -0
- package/dist/node/server/routes/bridge/routeDefinitions/routes/bridgeToRemoteStatus.d.ts +3 -0
- package/dist/node/server/routes/bridge/routeDefinitions/routes/bridgeToRemoteStatus.d.ts.map +1 -0
- package/dist/node/server/routes/bridge/routeDefinitions/routes/index.d.ts +5 -0
- package/dist/node/server/routes/bridge/routeDefinitions/routes/index.d.ts.map +1 -0
- package/dist/node/server/routes/healthz/get.d.ts +2 -1
- package/dist/node/server/routes/healthz/get.d.ts.map +1 -1
- package/dist/node/server/routes/index.d.ts +0 -1
- package/dist/node/server/routes/index.d.ts.map +1 -1
- package/dist/node/server/server.d.ts.map +1 -1
- package/package.json +62 -55
- package/src/driver/indexer/ChainHydratedBlocksObservable.ts +5 -5
- package/src/driver/indexer/spec/ChainBlocksObservable.spec.ts +6 -3
- package/src/driver/indexer/spec/ChainHydratedBlocksObservable.spec.ts +10 -4
- package/src/driver/mongo/MongoMap.ts +13 -3
- package/src/interface/interface/IntentIndexerInterface.ts +5 -4
- package/src/interface/service/Observer/ERC20TransferObserver/ERC20TransferObserver.ts +181 -0
- package/src/interface/service/Observer/ERC20TransferObserver/index.ts +1 -0
- package/src/interface/service/Observer/ERC20TransferObserver/spec/ERC20TransferObserver.spec.ts +271 -0
- package/src/interface/service/Observer/LiquidityPoolBridgeObserver/LiquidityPoolBridgeObserver.ts +212 -0
- package/src/interface/service/Observer/LiquidityPoolBridgeObserver/index.ts +1 -0
- package/src/interface/service/Observer/LiquidityPoolBridgeObserver/spec/LiquidityPoolBridgeObserver.spec.ts +313 -0
- package/src/interface/service/Observer/Observer.ts +1 -1
- package/src/interface/service/{ChainBridgeRelay → Relay/ChainBridgeRelay}/ChainBridgeRelayInterface.ts +1 -1
- package/src/interface/service/{ChainBridgeRelay → Relay/ChainBridgeRelay}/ChainBridgeRelayService.ts +1 -1
- package/src/interface/service/{ChainBridgeRelay → Relay/ChainBridgeRelay}/spec/ChainBridgeRelayService.spec.ts +7 -5
- package/src/interface/service/Relay/LiquidityPoolBridgeRelay/LiquidityPoolBridgeRelay.ts +227 -0
- package/src/interface/service/Relay/LiquidityPoolBridgeRelay/index.ts +1 -0
- package/src/interface/service/Relay/LiquidityPoolBridgeRelay/spec/LiquidityPoolBridgeRelay.spec.ts +237 -0
- package/src/interface/service/Relay/index.ts +1 -0
- package/src/interface/service/index.ts +1 -1
- package/src/manifest/getLocator.ts +7 -6
- package/src/manifest/node.json +1 -1
- package/src/manifest/public/Chain.json +3 -109
- package/src/manifest/public/Ethereum.json +88 -0
- package/src/manifest/public/XL1.json +88 -0
- package/src/manifest/public/index.ts +15 -6
- package/src/server/app.ts +5 -12
- package/src/server/routes/addRoutes.ts +2 -6
- package/src/server/routes/bridge/addBridgeRoutes.ts +10 -0
- package/src/server/routes/bridge/index.ts +1 -0
- package/src/server/routes/bridge/middleware/index.ts +1 -0
- package/src/server/routes/bridge/middleware/requestHandlerValidator.ts +120 -0
- package/src/server/routes/bridge/routeDefinitions/getRouteDefinitions.ts +13 -0
- package/src/server/routes/bridge/routeDefinitions/index.ts +1 -0
- package/src/server/routes/bridge/routeDefinitions/pathParams/ChainIdPathParam.ts +18 -0
- package/src/server/routes/bridge/routeDefinitions/pathParams/index.ts +1 -0
- package/src/server/routes/bridge/routeDefinitions/routeDefinition.ts +18 -0
- package/src/server/routes/bridge/routeDefinitions/routes/bridgeFromRemoteStatus.ts +55 -0
- package/src/server/routes/bridge/routeDefinitions/routes/bridgeToRemote.ts +58 -0
- package/src/server/routes/bridge/routeDefinitions/routes/bridgeToRemoteEstimate.ts +83 -0
- package/src/server/routes/bridge/routeDefinitions/routes/bridgeToRemoteStatus.ts +55 -0
- package/src/server/routes/bridge/routeDefinitions/routes/index.ts +4 -0
- package/src/server/routes/healthz/get.ts +1 -1
- package/src/server/routes/index.ts +0 -2
- package/src/server/server.ts +11 -14
- package/dist/node/interface/service/ChainBridgeRelay/ChainBridgeRelayInterface.d.ts.map +0 -1
- package/dist/node/interface/service/ChainBridgeRelay/ChainBridgeRelayService.d.ts.map +0 -1
- package/dist/node/interface/service/ChainBridgeRelay/index.d.ts.map +0 -1
- package/dist/node/interface/service/ChainBridgeRelay/spec/ChainBridgeRelayService.spec.d.ts.map +0 -1
- package/dist/node/server/routes/rpc/index.d.ts +0 -2
- package/dist/node/server/routes/rpc/index.d.ts.map +0 -1
- package/dist/node/server/routes/rpc/routes/addRpcRoutes.d.ts +0 -3
- package/dist/node/server/routes/rpc/routes/addRpcRoutes.d.ts.map +0 -1
- package/dist/node/server/routes/rpc/routes/index.d.ts +0 -2
- package/dist/node/server/routes/rpc/routes/index.d.ts.map +0 -1
- package/src/manifest/public/Pending.json +0 -35
- package/src/server/routes/rpc/index.ts +0 -1
- package/src/server/routes/rpc/routes/addRpcRoutes.ts +0 -22
- package/src/server/routes/rpc/routes/index.ts +0 -1
- /package/dist/node/interface/service/{ChainBridgeRelay → Relay/ChainBridgeRelay}/index.d.ts +0 -0
- /package/dist/node/interface/service/{ChainBridgeRelay → Relay/ChainBridgeRelay}/spec/ChainBridgeRelayService.spec.d.ts +0 -0
- /package/src/interface/service/{ChainBridgeRelay → Relay/ChainBridgeRelay}/index.ts +0 -0
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
import { assertEx } from '@xylabs/assert'
|
|
2
|
+
import { delay } from '@xylabs/delay'
|
|
3
|
+
import type { Address } from '@xylabs/hex'
|
|
4
|
+
import { toAddress, toHex } from '@xylabs/hex'
|
|
5
|
+
import { Account } from '@xyo-network/account'
|
|
6
|
+
import type { BridgeableToken, LiquidityPoolBridge } from '@xyo-network/typechain'
|
|
7
|
+
import { BridgeableToken__factory, LiquidityPoolBridge__factory } from '@xyo-network/typechain'
|
|
8
|
+
import type {
|
|
9
|
+
BridgeDetailsFields, BridgeIntent, ChainId,
|
|
10
|
+
} from '@xyo-network/xl1-protocol'
|
|
11
|
+
import {
|
|
12
|
+
AttoXL1ConvertFactor, BridgeIntentSchema, BridgeSourceObservationSchema,
|
|
13
|
+
} from '@xyo-network/xl1-protocol'
|
|
14
|
+
import {
|
|
15
|
+
getAddress,
|
|
16
|
+
parseEther, Wallet, WebSocketProvider,
|
|
17
|
+
} from 'ethers'
|
|
18
|
+
import {
|
|
19
|
+
beforeAll, beforeEach, describe, expect, it, vi,
|
|
20
|
+
} from 'vitest'
|
|
21
|
+
|
|
22
|
+
import type {
|
|
23
|
+
BridgeDestinationObservationIndexerInterface, BridgeIntentIndexerInterface, BridgeSourceObservationIndexerInterface,
|
|
24
|
+
} from '../../../../interface/index.ts'
|
|
25
|
+
import { LiquidityPoolBridgeObserver } from '../LiquidityPoolBridgeObserver.ts'
|
|
26
|
+
|
|
27
|
+
describe.skip('LiquidityPoolBridgeObserver', () => {
|
|
28
|
+
// Test ERC-20 deployed to Hardhat local chain
|
|
29
|
+
const TOKEN_ADDRESS = '0x5FbDB2315678afecb367f032d93F642f64180aa3'
|
|
30
|
+
const bridgeAddress = '0xa85233C63b9Ee964Add6F2cffe00Fd84eb32338f'
|
|
31
|
+
const WS_URL = 'ws://127.0.0.1:8545'
|
|
32
|
+
const provider = new WebSocketProvider(WS_URL)
|
|
33
|
+
let ethBridgeSender: Wallet
|
|
34
|
+
let ethBridgeReceiver: Wallet
|
|
35
|
+
let token: BridgeableToken
|
|
36
|
+
let bridge: LiquidityPoolBridge
|
|
37
|
+
let xl1Address: Address
|
|
38
|
+
const xl1ChainId: ChainId = toAddress('0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9')
|
|
39
|
+
let sourceObservations: BridgeSourceObservationIndexerInterface
|
|
40
|
+
let destinationObservations: BridgeDestinationObservationIndexerInterface
|
|
41
|
+
let intents: BridgeIntentIndexerInterface
|
|
42
|
+
|
|
43
|
+
const srcAmountBigint = 100n * AttoXL1ConvertFactor.xl1
|
|
44
|
+
const srcAmount = toHex(srcAmountBigint)
|
|
45
|
+
const destAmount = srcAmount // 1:1 for test
|
|
46
|
+
const ethChainId = toHex('0x7A69')
|
|
47
|
+
const bridgeableTokenContract = toHex(TOKEN_ADDRESS)
|
|
48
|
+
|
|
49
|
+
const createRandomWallet = async (): Promise<Wallet> => {
|
|
50
|
+
// Create random account
|
|
51
|
+
const account = await Account.random()
|
|
52
|
+
expect(account.private?.hex).toBeDefined()
|
|
53
|
+
const key = assertEx(account.private?.hex)
|
|
54
|
+
|
|
55
|
+
// Create a wallet from the private key
|
|
56
|
+
const wallet = new Wallet(key, provider)
|
|
57
|
+
const deployer = await provider.getSigner(0)
|
|
58
|
+
|
|
59
|
+
// Fund the wallet with some ETH for gas
|
|
60
|
+
const fundTx = await deployer.sendTransaction({ to: wallet.address, value: parseEther('1') })
|
|
61
|
+
await fundTx.wait()
|
|
62
|
+
|
|
63
|
+
// Ensure wallet has ETH
|
|
64
|
+
const balance = await provider.getBalance(wallet.address)
|
|
65
|
+
expect(balance).toBeGreaterThan(0n)
|
|
66
|
+
|
|
67
|
+
// Return the created wallet
|
|
68
|
+
return wallet
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const bridgeFromRemote = async (xl1Address: Address, ethBridgeReceiver: Wallet, srcAmountBigint: bigint) => {
|
|
72
|
+
const balance = await token.balanceOf(await bridge.getAddress())
|
|
73
|
+
expect(balance).toBeGreaterThanOrEqual(srcAmountBigint)
|
|
74
|
+
await bridge.bridgeFromRemote(getAddress(xl1Address), ethBridgeReceiver.address, srcAmountBigint)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const bridgeToRemote = async (ethBridgeSender: Wallet, xl1Address: Address, srcAmountBigint: bigint) => {
|
|
78
|
+
const balance = await token.balanceOf(ethBridgeSender.address)
|
|
79
|
+
expect(balance).toBeGreaterThanOrEqual(srcAmountBigint)
|
|
80
|
+
const destAddress = getAddress(xl1Address)
|
|
81
|
+
await token.connect(ethBridgeSender).approve(bridge.getAddress(), srcAmountBigint)
|
|
82
|
+
const nonce = await ethBridgeSender.getNonce()
|
|
83
|
+
await bridge.connect(ethBridgeSender).bridgeToRemote(destAddress, srcAmountBigint, { nonce })
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
beforeAll(async () => {
|
|
87
|
+
const deployer = await provider.getSigner(0)
|
|
88
|
+
ethBridgeSender = await createRandomWallet()
|
|
89
|
+
|
|
90
|
+
token = BridgeableToken__factory.connect(TOKEN_ADDRESS, deployer)
|
|
91
|
+
bridge = LiquidityPoolBridge__factory.connect(bridgeAddress, deployer)
|
|
92
|
+
const owner = await bridge.owner()
|
|
93
|
+
expect(owner).toBeDefined()
|
|
94
|
+
expect(owner).to.eq(deployer.address)
|
|
95
|
+
const amount = srcAmountBigint * 2n
|
|
96
|
+
await token.mint(await bridge.getAddress(), parseEther(amount.toString()))
|
|
97
|
+
expect(await token.balanceOf(await bridge.getAddress())).toBeGreaterThanOrEqual(amount)
|
|
98
|
+
await token.mint(ethBridgeSender.address, parseEther(amount.toString()))
|
|
99
|
+
expect(await token.balanceOf(ethBridgeSender.address)).toBeGreaterThanOrEqual(amount)
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
describe('when bridging from Ethereum', () => {
|
|
103
|
+
beforeEach(async () => {
|
|
104
|
+
xl1Address = (await Account.random()).address
|
|
105
|
+
ethBridgeReceiver = await createRandomWallet()
|
|
106
|
+
sourceObservations = {
|
|
107
|
+
addObservation: vi.fn().mockResolvedValue(true),
|
|
108
|
+
getObservationForIntent: vi.fn().mockResolvedValue(null),
|
|
109
|
+
getIntentForObservation: vi.fn().mockResolvedValue(null),
|
|
110
|
+
}
|
|
111
|
+
destinationObservations = {
|
|
112
|
+
addObservation: vi.fn().mockResolvedValue(true),
|
|
113
|
+
getObservationForIntent: vi.fn().mockResolvedValue(null),
|
|
114
|
+
getIntentForObservation: vi.fn().mockResolvedValue(null),
|
|
115
|
+
}
|
|
116
|
+
intents = {
|
|
117
|
+
addIntent: vi.fn().mockResolvedValue(true),
|
|
118
|
+
getIntentByNonce: vi.fn(),
|
|
119
|
+
getIntentsForDestination: vi.fn().mockResolvedValue([]),
|
|
120
|
+
getIntentsForSource: vi.fn().mockResolvedValue([]),
|
|
121
|
+
}
|
|
122
|
+
})
|
|
123
|
+
describe('for new transfers to XL1', () => {
|
|
124
|
+
it('should observe transfer', async () => {
|
|
125
|
+
// Arrange
|
|
126
|
+
// Create observer before transfer
|
|
127
|
+
const observer = await LiquidityPoolBridgeObserver.create({
|
|
128
|
+
destinationObservations,
|
|
129
|
+
intents,
|
|
130
|
+
provider,
|
|
131
|
+
sourceObservations,
|
|
132
|
+
bridgeAddress,
|
|
133
|
+
})
|
|
134
|
+
expect(observer).toBeDefined()
|
|
135
|
+
|
|
136
|
+
// Act
|
|
137
|
+
await bridgeToRemote(ethBridgeSender, xl1Address, srcAmountBigint)
|
|
138
|
+
|
|
139
|
+
// Wait for event
|
|
140
|
+
await delay(2000)
|
|
141
|
+
|
|
142
|
+
// Assert
|
|
143
|
+
// Ensure transfer was observed
|
|
144
|
+
const fields: BridgeDetailsFields = {
|
|
145
|
+
// Source
|
|
146
|
+
src: ethChainId,
|
|
147
|
+
srcAddress: toAddress(ethBridgeSender.address),
|
|
148
|
+
srcAmount,
|
|
149
|
+
srcToken: bridgeableTokenContract,
|
|
150
|
+
|
|
151
|
+
// Destination
|
|
152
|
+
dest: xl1ChainId,
|
|
153
|
+
destAddress: xl1Address,
|
|
154
|
+
destAmount,
|
|
155
|
+
destToken: xl1ChainId,
|
|
156
|
+
}
|
|
157
|
+
expect(intents.addIntent).toHaveBeenCalledWith({
|
|
158
|
+
...fields,
|
|
159
|
+
nonce: expect.any(String),
|
|
160
|
+
schema: BridgeIntentSchema,
|
|
161
|
+
})
|
|
162
|
+
expect(sourceObservations.addObservation).toHaveBeenCalledWith({
|
|
163
|
+
...fields,
|
|
164
|
+
nonce: expect.any(String),
|
|
165
|
+
schema: BridgeSourceObservationSchema,
|
|
166
|
+
}, {
|
|
167
|
+
...fields,
|
|
168
|
+
nonce: expect.any(String),
|
|
169
|
+
schema: BridgeIntentSchema,
|
|
170
|
+
})
|
|
171
|
+
})
|
|
172
|
+
})
|
|
173
|
+
describe('for previous transfers to XL1', () => {
|
|
174
|
+
it('should observe transfer', async () => {
|
|
175
|
+
// Arrange
|
|
176
|
+
await bridgeToRemote(ethBridgeSender, xl1Address, srcAmountBigint)
|
|
177
|
+
// Wait for transaction to be mined
|
|
178
|
+
await delay(2000)
|
|
179
|
+
|
|
180
|
+
// Act
|
|
181
|
+
// Create observer after transfer
|
|
182
|
+
const observer = await LiquidityPoolBridgeObserver.create({
|
|
183
|
+
destinationObservations,
|
|
184
|
+
intents,
|
|
185
|
+
provider,
|
|
186
|
+
sourceObservations,
|
|
187
|
+
bridgeAddress,
|
|
188
|
+
})
|
|
189
|
+
expect(observer).toBeDefined()
|
|
190
|
+
|
|
191
|
+
// Assert
|
|
192
|
+
// Ensure transfer was observed
|
|
193
|
+
// Ensure transfer was observed
|
|
194
|
+
const fields: BridgeDetailsFields = {
|
|
195
|
+
// Source
|
|
196
|
+
src: ethChainId,
|
|
197
|
+
srcAddress: toAddress(ethBridgeSender.address),
|
|
198
|
+
srcAmount,
|
|
199
|
+
srcToken: bridgeableTokenContract,
|
|
200
|
+
|
|
201
|
+
// Destination
|
|
202
|
+
dest: xl1ChainId,
|
|
203
|
+
destAddress: xl1Address,
|
|
204
|
+
destAmount,
|
|
205
|
+
destToken: xl1ChainId,
|
|
206
|
+
}
|
|
207
|
+
expect(intents.addIntent).toHaveBeenCalledWith({
|
|
208
|
+
...fields,
|
|
209
|
+
nonce: expect.any(String),
|
|
210
|
+
schema: BridgeIntentSchema,
|
|
211
|
+
})
|
|
212
|
+
expect(sourceObservations.addObservation).toHaveBeenCalledWith({
|
|
213
|
+
...fields,
|
|
214
|
+
nonce: expect.any(String),
|
|
215
|
+
schema: BridgeSourceObservationSchema,
|
|
216
|
+
}, {
|
|
217
|
+
...fields,
|
|
218
|
+
nonce: expect.any(String),
|
|
219
|
+
schema: BridgeIntentSchema,
|
|
220
|
+
})
|
|
221
|
+
})
|
|
222
|
+
})
|
|
223
|
+
})
|
|
224
|
+
|
|
225
|
+
describe('when bridging to Ethereum', () => {
|
|
226
|
+
beforeEach(async () => {
|
|
227
|
+
xl1Address = (await Account.random()).address
|
|
228
|
+
ethBridgeReceiver = await createRandomWallet()
|
|
229
|
+
sourceObservations = {
|
|
230
|
+
addObservation: vi.fn().mockResolvedValue(true),
|
|
231
|
+
getObservationForIntent: vi.fn().mockResolvedValue(null),
|
|
232
|
+
getIntentForObservation: vi.fn().mockResolvedValue(null),
|
|
233
|
+
}
|
|
234
|
+
destinationObservations = {
|
|
235
|
+
addObservation: vi.fn().mockResolvedValue(true),
|
|
236
|
+
getObservationForIntent: vi.fn().mockResolvedValue(null),
|
|
237
|
+
getIntentForObservation: vi.fn().mockResolvedValue(null),
|
|
238
|
+
}
|
|
239
|
+
const nonce = Date.now().toString()
|
|
240
|
+
const intent: BridgeIntent = {
|
|
241
|
+
// Source
|
|
242
|
+
src: xl1ChainId, // From XL1
|
|
243
|
+
srcAddress: xl1Address, // From XL1 sender
|
|
244
|
+
srcAmount,
|
|
245
|
+
srcToken: xl1ChainId, // In XL1
|
|
246
|
+
|
|
247
|
+
// Destination
|
|
248
|
+
dest: ethChainId, // To Ethereum
|
|
249
|
+
destAddress: toAddress(ethBridgeReceiver.address),
|
|
250
|
+
destAmount,
|
|
251
|
+
destToken: bridgeableTokenContract,
|
|
252
|
+
|
|
253
|
+
// Details
|
|
254
|
+
nonce,
|
|
255
|
+
|
|
256
|
+
schema: BridgeIntentSchema,
|
|
257
|
+
}
|
|
258
|
+
intents = {
|
|
259
|
+
addIntent: vi.fn().mockResolvedValue(true),
|
|
260
|
+
getIntentByNonce: vi.fn().mockResolvedValue(intent),
|
|
261
|
+
getIntentsForDestination: vi.fn().mockResolvedValue([intent]),
|
|
262
|
+
getIntentsForSource: vi.fn().mockResolvedValue([]),
|
|
263
|
+
}
|
|
264
|
+
})
|
|
265
|
+
describe('for new transfers from xl1 address', () => {
|
|
266
|
+
it('should observe transfer', async () => {
|
|
267
|
+
// Arrange
|
|
268
|
+
// Create observer before transfer
|
|
269
|
+
const observer = await LiquidityPoolBridgeObserver.create({
|
|
270
|
+
destinationObservations,
|
|
271
|
+
intents,
|
|
272
|
+
provider,
|
|
273
|
+
sourceObservations,
|
|
274
|
+
bridgeAddress,
|
|
275
|
+
})
|
|
276
|
+
expect(observer).toBeDefined()
|
|
277
|
+
|
|
278
|
+
// Act
|
|
279
|
+
await bridgeFromRemote(xl1Address, ethBridgeReceiver, srcAmountBigint)
|
|
280
|
+
|
|
281
|
+
// Wait for event
|
|
282
|
+
await delay(2000)
|
|
283
|
+
|
|
284
|
+
// Assert
|
|
285
|
+
// Ensure transfer was observed
|
|
286
|
+
expect(destinationObservations.addObservation).toHaveBeenCalled()
|
|
287
|
+
})
|
|
288
|
+
})
|
|
289
|
+
describe('for previous transfers from xl1 address', () => {
|
|
290
|
+
it('should observe transfer', async () => {
|
|
291
|
+
// Arrange
|
|
292
|
+
await bridgeFromRemote(xl1Address, ethBridgeReceiver, srcAmountBigint)
|
|
293
|
+
// Wait for transaction to be mined
|
|
294
|
+
await delay(2000)
|
|
295
|
+
|
|
296
|
+
// Act
|
|
297
|
+
// Create observer after transfer
|
|
298
|
+
const observer = await LiquidityPoolBridgeObserver.create({
|
|
299
|
+
destinationObservations,
|
|
300
|
+
intents,
|
|
301
|
+
provider,
|
|
302
|
+
sourceObservations,
|
|
303
|
+
bridgeAddress,
|
|
304
|
+
})
|
|
305
|
+
expect(observer).toBeDefined()
|
|
306
|
+
|
|
307
|
+
// Assert
|
|
308
|
+
// Ensure transfer was observed
|
|
309
|
+
expect(destinationObservations.addObservation).toHaveBeenCalled()
|
|
310
|
+
})
|
|
311
|
+
})
|
|
312
|
+
})
|
|
313
|
+
})
|
|
@@ -34,7 +34,7 @@ export class BridgeObserverService<TParams extends BridgeServiceParams = BridgeS
|
|
|
34
34
|
return assertEx(this.params.intentProcessing, () => 'intentProcessing is required')
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
protected get
|
|
37
|
+
protected get intents(): BridgeIntentIndexerInterface {
|
|
38
38
|
return assertEx(this.params.intents, () => 'intents is required')
|
|
39
39
|
}
|
|
40
40
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { BridgeDestinationObservation, BridgeIntent } from '@xyo-network/xl1-protocol'
|
|
2
2
|
|
|
3
|
-
import type { AsynchronousRelayInterface, SynchronousRelayInterface } from '
|
|
3
|
+
import type { AsynchronousRelayInterface, SynchronousRelayInterface } from '../../../interface/index.ts'
|
|
4
4
|
|
|
5
5
|
export interface BlockingChainBridgeRelay extends SynchronousRelayInterface<BridgeIntent, BridgeDestinationObservation> {}
|
|
6
6
|
|
package/src/interface/service/{ChainBridgeRelay → Relay/ChainBridgeRelay}/ChainBridgeRelayService.ts
RENAMED
|
@@ -8,7 +8,7 @@ import type {
|
|
|
8
8
|
BridgeServiceParams,
|
|
9
9
|
BridgeSourceObservationIndexerInterface, ChainBridgeRelayInterface, LockingBridgeIntentProcessorInterface,
|
|
10
10
|
UnlockingBridgeIntentProcessorInterface,
|
|
11
|
-
} from '
|
|
11
|
+
} from '../../../interface/index.ts'
|
|
12
12
|
|
|
13
13
|
export class ChainBridgeRelayService<TParams extends BridgeServiceParams = BridgeServiceParams>
|
|
14
14
|
extends BaseAccountableService<TParams> implements ChainBridgeRelayInterface {
|
|
@@ -2,7 +2,7 @@ import { toAddress, toHex } from '@xylabs/hex'
|
|
|
2
2
|
import { HDWallet } from '@xyo-network/wallet'
|
|
3
3
|
import type { WalletInstance } from '@xyo-network/wallet-model'
|
|
4
4
|
import type {
|
|
5
|
-
BridgeDestinationObservation, BridgeIntent, BridgeSourceObservation,
|
|
5
|
+
BridgeDestinationObservation, BridgeIntent, BridgeSourceObservation, ChainId,
|
|
6
6
|
} from '@xyo-network/xl1-protocol'
|
|
7
7
|
import {
|
|
8
8
|
AttoXL1ConvertFactor, BridgeDestinationObservationSchema, BridgeIntentSchema,
|
|
@@ -19,7 +19,7 @@ import type {
|
|
|
19
19
|
BridgeSourceObservationIndexerInterface,
|
|
20
20
|
ChainBridgeRelayInterface,
|
|
21
21
|
LockingBridgeIntentProcessorInterface, UnlockingBridgeIntentProcessorInterface,
|
|
22
|
-
} from '
|
|
22
|
+
} from '../../../../interface/index.ts'
|
|
23
23
|
import { ChainBridgeRelayService } from '../ChainBridgeRelayService.ts'
|
|
24
24
|
|
|
25
25
|
describe('ChainBridgeRelayService', () => {
|
|
@@ -36,7 +36,7 @@ describe('ChainBridgeRelayService', () => {
|
|
|
36
36
|
const srcAmount = toHex(100n * AttoXL1ConvertFactor.xl1) // 100 XL1 in AttoXL1
|
|
37
37
|
const destAmount = srcAmount // 1:1 for test
|
|
38
38
|
|
|
39
|
-
const xl1ChainId:
|
|
39
|
+
const xl1ChainId: ChainId = toHex('dd381fbb392c85160d8b0453e446757b12384046')
|
|
40
40
|
const ethChainId = toHex('0x1')
|
|
41
41
|
|
|
42
42
|
const xl1Address = toAddress('1111111111111111111111111111111111111111')
|
|
@@ -111,8 +111,10 @@ describe('ChainBridgeRelayService', () => {
|
|
|
111
111
|
config = getDefaultConfig()
|
|
112
112
|
|
|
113
113
|
intents = {
|
|
114
|
-
|
|
115
|
-
|
|
114
|
+
addIntent: vi.fn().mockResolvedValue(true),
|
|
115
|
+
getIntentByNonce: vi.fn(),
|
|
116
|
+
getIntentsForDestination: vi.fn().mockResolvedValue([]),
|
|
117
|
+
getIntentsForSource: vi.fn().mockResolvedValue([]),
|
|
116
118
|
}
|
|
117
119
|
|
|
118
120
|
sourceObservations = {
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
import { assertEx } from '@xylabs/assert'
|
|
2
|
+
import type { Address, Hex } from '@xylabs/hex'
|
|
3
|
+
import {
|
|
4
|
+
asHex, hexFromBigInt, hexToBigInt, toAddress,
|
|
5
|
+
} from '@xylabs/hex'
|
|
6
|
+
import { isNull } from '@xylabs/typeof'
|
|
7
|
+
import { BaseAccountableService } from '@xyo-network/chain-services'
|
|
8
|
+
import { PayloadBuilder } from '@xyo-network/payload-builder'
|
|
9
|
+
import type { LiquidityPoolBridge } from '@xyo-network/typechain'
|
|
10
|
+
import { LiquidityPoolBridge__factory } from '@xyo-network/typechain'
|
|
11
|
+
import {
|
|
12
|
+
type BridgeDestinationObservation, BridgeDestinationObservationSchema, type BridgeIntent,
|
|
13
|
+
} from '@xyo-network/xl1-protocol'
|
|
14
|
+
import type { WebSocketProvider } from 'ethers'
|
|
15
|
+
import { getAddress, Wallet } from 'ethers'
|
|
16
|
+
|
|
17
|
+
import type {
|
|
18
|
+
BridgeDestinationObservationIndexerInterface, BridgeIntentIndexerInterface, BridgeServiceParams, BridgeSourceObservationIndexerInterface,
|
|
19
|
+
ChainBridgeRelayInterface, LockingBridgeIntentProcessorInterface, UnlockingBridgeIntentProcessorInterface,
|
|
20
|
+
} from '../../../interface/index.ts'
|
|
21
|
+
|
|
22
|
+
export type LiquidityPoolBridgeRelayParams = BridgeServiceParams & {
|
|
23
|
+
/**
|
|
24
|
+
* The address to watch for incoming or outgoing ERC-20 token transfers.
|
|
25
|
+
*/
|
|
26
|
+
bridgeAddress: string
|
|
27
|
+
/**
|
|
28
|
+
* An ethers.js WebSocketProvider connected to the Ethereum network to monitor for ERC-20 transfers.
|
|
29
|
+
*/
|
|
30
|
+
provider: WebSocketProvider
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export class LiquidityPoolBridgeRelay<TParams extends LiquidityPoolBridgeRelayParams = LiquidityPoolBridgeRelayParams>
|
|
34
|
+
extends BaseAccountableService<TParams> implements ChainBridgeRelayInterface {
|
|
35
|
+
protected _bridge: LiquidityPoolBridge | undefined
|
|
36
|
+
protected _bridgeChainId: Hex | undefined
|
|
37
|
+
protected _bridgeRemoteChainId: Hex | undefined
|
|
38
|
+
protected _bridgeTokenAddress: Address | undefined
|
|
39
|
+
protected _wallet: Wallet | undefined
|
|
40
|
+
|
|
41
|
+
protected get account() {
|
|
42
|
+
return assertEx(this.params.account, () => 'account is required')
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
protected get bridge(): LiquidityPoolBridge {
|
|
46
|
+
return assertEx(this._bridge, () => new Error('Bridge contract not initialized'))
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
protected get bridgeChainId(): Hex {
|
|
50
|
+
return assertEx(this._bridgeChainId, () => new Error('Bridge chain ID not initialized'))
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
protected get bridgeRemoteChainId(): Hex {
|
|
54
|
+
return assertEx(this._bridgeRemoteChainId, () => new Error('Bridge remote chain ID not initialized'))
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
protected get bridgeTokenAddress(): Address {
|
|
58
|
+
return assertEx(this._bridgeTokenAddress, () => new Error('Bridge token address not initialized'))
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
protected get destinationObservations(): BridgeDestinationObservationIndexerInterface {
|
|
62
|
+
return assertEx(this.params.destinationObservations, () => 'destinationObservations is required')
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
protected get destinationRelay(): ChainBridgeRelayInterface {
|
|
66
|
+
return assertEx(this.params.destinationRelay, () => 'destinationRelay is required')
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
protected get intentProcessed(): LockingBridgeIntentProcessorInterface {
|
|
70
|
+
return assertEx(this.params.intentProcessed, () => 'intentProcessed is required')
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
protected get intentProcessing(): UnlockingBridgeIntentProcessorInterface {
|
|
74
|
+
return assertEx(this.params.intentProcessing, () => 'intentProcessing is required')
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
protected get intentResourceAccess(): BridgeIntentIndexerInterface {
|
|
78
|
+
return assertEx(this.params.intents, () => 'intents is required')
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
protected get provider(): WebSocketProvider {
|
|
82
|
+
return assertEx(this.params.provider, () => new Error('Provider not initialized'))
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
protected get sourceObservations(): BridgeSourceObservationIndexerInterface {
|
|
86
|
+
return assertEx(this.params.sourceObservations, () => 'sourceObservations is required')
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
protected get wallet(): Wallet {
|
|
90
|
+
return assertEx(this._wallet, () => 'wallet is required')
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Begins the relay process for a given BridgeIntent.
|
|
95
|
+
* @param bridgeIntent The bridgeIntent to begin relaying
|
|
96
|
+
* @returns True if the relay was started, false otherwise
|
|
97
|
+
*/
|
|
98
|
+
async beginRelay(bridgeIntent: BridgeIntent): Promise<boolean> {
|
|
99
|
+
try {
|
|
100
|
+
// Ensure source observation exists
|
|
101
|
+
const bridgeSourceObservation = await this.sourceObservations.getObservationForIntent(bridgeIntent)
|
|
102
|
+
if (!isNull(bridgeSourceObservation)) {
|
|
103
|
+
const canProcess = await this.intentProcessing.lock(this.account.address, bridgeIntent)
|
|
104
|
+
if (canProcess) {
|
|
105
|
+
const amount = hexToBigInt(bridgeIntent.destAmount)
|
|
106
|
+
const nonce = await this.wallet.getNonce()
|
|
107
|
+
await this.bridge.bridgeFromRemote(
|
|
108
|
+
getAddress(bridgeIntent.srcAddress),
|
|
109
|
+
getAddress(bridgeIntent.destAddress),
|
|
110
|
+
amount,
|
|
111
|
+
{ nonce },
|
|
112
|
+
)
|
|
113
|
+
return true
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
} catch (error) {
|
|
117
|
+
console.error('Error occurred while beginning relay:', error)
|
|
118
|
+
await this.intentProcessing.unlock(this.account.address, bridgeIntent)
|
|
119
|
+
}
|
|
120
|
+
return false
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
override async createHandler(): Promise<void> {
|
|
124
|
+
const { provider, bridgeAddress } = this.params
|
|
125
|
+
|
|
126
|
+
// Connect to the bridge contract
|
|
127
|
+
// Create a wallet bound to the provider (signer + provider)
|
|
128
|
+
const key = assertEx(this.account?.private?.hex, () => new Error('Account private key is required'))
|
|
129
|
+
this._wallet = new Wallet(key, provider)
|
|
130
|
+
this._bridge = LiquidityPoolBridge__factory.connect(getAddress(bridgeAddress), this._wallet)
|
|
131
|
+
|
|
132
|
+
// Parse bridge network chain ID
|
|
133
|
+
const network = await provider.getNetwork()
|
|
134
|
+
this._bridgeChainId = assertEx(hexFromBigInt(network.chainId), () => new Error('Failed to parse bridgeChainId'))
|
|
135
|
+
|
|
136
|
+
// Parse bridge token address
|
|
137
|
+
const tokenAddress = await this.bridge.token()
|
|
138
|
+
this._bridgeTokenAddress = toAddress(tokenAddress)
|
|
139
|
+
|
|
140
|
+
// Parse bridge remote chain ID
|
|
141
|
+
const bridgeRemoteChain = await this.bridge.remoteChain()
|
|
142
|
+
this._bridgeRemoteChainId = asHex(bridgeRemoteChain)
|
|
143
|
+
|
|
144
|
+
await this.bridge.on(this.bridge.getEvent('BridgedFromRemote'), (id, from, to, amount, remoteChain, args) => {
|
|
145
|
+
const txHash = args.transactionHash
|
|
146
|
+
const destConfirmation = asHex(txHash)
|
|
147
|
+
const observation: BridgeDestinationObservation = new PayloadBuilder<BridgeDestinationObservation>({ schema: BridgeDestinationObservationSchema })
|
|
148
|
+
.fields({
|
|
149
|
+
src: this.bridgeRemoteChainId,
|
|
150
|
+
dest: this.bridgeChainId,
|
|
151
|
+
srcAddress: toAddress(from),
|
|
152
|
+
destAddress: toAddress(to),
|
|
153
|
+
srcToken: this.bridgeTokenAddress,
|
|
154
|
+
destToken: this.bridgeTokenAddress,
|
|
155
|
+
srcAmount: amount.toString(),
|
|
156
|
+
destAmount: amount.toString(),
|
|
157
|
+
destConfirmation,
|
|
158
|
+
}).build()
|
|
159
|
+
this.onDestinationObservation(observation).catch(console.error)
|
|
160
|
+
})
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Handles a BridgeDestinationObservation.
|
|
165
|
+
* @param bridgeDestinationObservation The BridgeDestinationObservation to process
|
|
166
|
+
* @returns True if the observation was processed as a completion for an outstanding relay, false otherwise
|
|
167
|
+
*/
|
|
168
|
+
async onDestinationObservation(bridgeDestinationObservation: BridgeDestinationObservation): Promise<boolean> {
|
|
169
|
+
// Ensure intent exists
|
|
170
|
+
const bridgeIntent = await this.destinationObservations.getIntentForObservation(bridgeDestinationObservation)
|
|
171
|
+
if (!isNull(bridgeIntent)) {
|
|
172
|
+
// Ensure not already processed
|
|
173
|
+
const processed = await this.intentProcessed.isLocked(bridgeIntent)
|
|
174
|
+
if (isNull(processed)) {
|
|
175
|
+
// Ensure we are the processor
|
|
176
|
+
const processor = await this.intentProcessing.isLocked(bridgeIntent)
|
|
177
|
+
if (!isNull(processor) && processor === this.account.address) {
|
|
178
|
+
// Mark as completed
|
|
179
|
+
await this.intentProcessed.lock(this.account.address, bridgeIntent)
|
|
180
|
+
await this.intentProcessing.unlock(this.account.address, bridgeIntent)
|
|
181
|
+
return true
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return false
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Relays a given BridgeIntent.
|
|
190
|
+
* @param bridgeIntent The BridgeIntent to relay
|
|
191
|
+
* @returns Relays the intent in a blocking manner, returning the resulting BridgeDestinationObservation if successful
|
|
192
|
+
*/
|
|
193
|
+
async relaySync(bridgeIntent: BridgeIntent): Promise<BridgeDestinationObservation | null> {
|
|
194
|
+
// Ensure source observation exists
|
|
195
|
+
const bridgeSourceObservation = await this.sourceObservations.getObservationForIntent(bridgeIntent)
|
|
196
|
+
if (!isNull(bridgeSourceObservation)) {
|
|
197
|
+
let canProcess = isNull(await this.intentProcessing.isLocked(bridgeIntent))
|
|
198
|
+
try {
|
|
199
|
+
canProcess = await this.intentProcessing.lock(this.account.address, bridgeIntent)
|
|
200
|
+
if (canProcess) {
|
|
201
|
+
const amount = hexToBigInt(bridgeIntent.destAmount)
|
|
202
|
+
const nonce = await this.wallet.getNonce()
|
|
203
|
+
const tx = await this.bridge.bridgeFromRemote(
|
|
204
|
+
getAddress(bridgeIntent.srcAddress),
|
|
205
|
+
getAddress(bridgeIntent.destAddress),
|
|
206
|
+
amount,
|
|
207
|
+
{ nonce },
|
|
208
|
+
)
|
|
209
|
+
const confirmation = await tx.wait()
|
|
210
|
+
const transactionResponse = await confirmation?.getTransaction()
|
|
211
|
+
const destConfirmation = asHex(transactionResponse?.hash ?? '')
|
|
212
|
+
const { schema, ...rest } = bridgeIntent
|
|
213
|
+
const result: BridgeDestinationObservation = new PayloadBuilder<BridgeDestinationObservation>({ schema: BridgeDestinationObservationSchema })
|
|
214
|
+
.fields({ ...rest, destConfirmation }).build()
|
|
215
|
+
await this.destinationObservations.addObservation(result, bridgeIntent)
|
|
216
|
+
await this.intentProcessed.lock(this.account.address, bridgeIntent)
|
|
217
|
+
return result
|
|
218
|
+
}
|
|
219
|
+
} finally {
|
|
220
|
+
if (!isNull(bridgeIntent)) {
|
|
221
|
+
await this.intentProcessing.unlock(this.account.address, bridgeIntent)
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
return null
|
|
226
|
+
}
|
|
227
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './LiquidityPoolBridgeRelay.ts'
|