@xyo-network/chain-bridge 1.16.15 → 1.16.17
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/package.json +11 -8
- package/dist/node/driver/indexer/spec/ChainBlocksObservable.spec.d.ts +0 -2
- package/dist/node/driver/indexer/spec/ChainBlocksObservable.spec.d.ts.map +0 -1
- package/dist/node/driver/indexer/spec/ChainHydratedBlocksObservable.spec.d.ts +0 -2
- package/dist/node/driver/indexer/spec/ChainHydratedBlocksObservable.spec.d.ts.map +0 -1
- package/dist/node/interface/service/Observer/ERC20TransferObserver/spec/ERC20TransferObserver.spec.d.ts +0 -2
- package/dist/node/interface/service/Observer/ERC20TransferObserver/spec/ERC20TransferObserver.spec.d.ts.map +0 -1
- package/dist/node/interface/service/Observer/LiquidityPoolBridgeObserver/spec/LiquidityPoolBridgeObserver.spec.d.ts +0 -2
- package/dist/node/interface/service/Observer/LiquidityPoolBridgeObserver/spec/LiquidityPoolBridgeObserver.spec.d.ts.map +0 -1
- package/dist/node/interface/service/Relay/ChainBridgeRelay/spec/ChainBridgeRelayService.spec.d.ts +0 -2
- package/dist/node/interface/service/Relay/ChainBridgeRelay/spec/ChainBridgeRelayService.spec.d.ts.map +0 -1
- package/dist/node/interface/service/Relay/LiquidityPoolBridgeRelay/spec/LiquidityPoolBridgeRelay.spec.d.ts +0 -2
- package/dist/node/interface/service/Relay/LiquidityPoolBridgeRelay/spec/LiquidityPoolBridgeRelay.spec.d.ts.map +0 -1
- package/dist/node/manifest/public/spec/Node.spec.d.ts +0 -2
- package/dist/node/manifest/public/spec/Node.spec.d.ts.map +0 -1
- package/src/driver/indexer/spec/ChainBlocksObservable.spec.ts +0 -62
- package/src/driver/indexer/spec/ChainHydratedBlocksObservable.spec.ts +0 -64
- package/src/interface/service/Observer/ERC20TransferObserver/spec/ERC20TransferObserver.spec.ts +0 -272
- package/src/interface/service/Observer/LiquidityPoolBridgeObserver/spec/LiquidityPoolBridgeObserver.spec.ts +0 -314
- package/src/interface/service/Relay/ChainBridgeRelay/spec/ChainBridgeRelayService.spec.ts +0 -266
- package/src/interface/service/Relay/LiquidityPoolBridgeRelay/spec/LiquidityPoolBridgeRelay.spec.ts +0 -238
- package/src/manifest/public/spec/Node.spec.ts +0 -32
|
@@ -1,314 +0,0 @@
|
|
|
1
|
-
import type { Address } from '@xylabs/sdk-js'
|
|
2
|
-
import {
|
|
3
|
-
assertEx, delay,
|
|
4
|
-
toAddress, toHex,
|
|
5
|
-
} from '@xylabs/sdk-js'
|
|
6
|
-
import { Account } from '@xyo-network/account'
|
|
7
|
-
import type { BridgeableToken, LiquidityPoolBridge } from '@xyo-network/typechain'
|
|
8
|
-
import { BridgeableToken__factory, LiquidityPoolBridge__factory } from '@xyo-network/typechain'
|
|
9
|
-
import type {
|
|
10
|
-
BridgeDetailsFields, BridgeIntent, ChainId,
|
|
11
|
-
} from '@xyo-network/xl1-protocol'
|
|
12
|
-
import {
|
|
13
|
-
AttoXL1ConvertFactor, BridgeIntentSchema, BridgeSourceObservationSchema,
|
|
14
|
-
} from '@xyo-network/xl1-protocol'
|
|
15
|
-
import {
|
|
16
|
-
getAddress,
|
|
17
|
-
parseEther, Wallet, WebSocketProvider,
|
|
18
|
-
} from 'ethers'
|
|
19
|
-
import {
|
|
20
|
-
beforeAll, beforeEach, describe, expect, it, vi,
|
|
21
|
-
} from 'vitest'
|
|
22
|
-
|
|
23
|
-
import type {
|
|
24
|
-
BridgeDestinationObservationIndexerInterface, BridgeIntentIndexerInterface, BridgeSourceObservationIndexerInterface,
|
|
25
|
-
} from '../../../../interface/index.ts'
|
|
26
|
-
import { LiquidityPoolBridgeObserver } from '../LiquidityPoolBridgeObserver.ts'
|
|
27
|
-
|
|
28
|
-
describe.skip('LiquidityPoolBridgeObserver', () => {
|
|
29
|
-
// Test ERC-20 deployed to Hardhat local chain
|
|
30
|
-
const TOKEN_ADDRESS = '0x5FbDB2315678afecb367f032d93F642f64180aa3'
|
|
31
|
-
const bridgeAddress = '0xa85233C63b9Ee964Add6F2cffe00Fd84eb32338f'
|
|
32
|
-
const WS_URL = 'ws://127.0.0.1:8545'
|
|
33
|
-
const provider = new WebSocketProvider(WS_URL)
|
|
34
|
-
let ethBridgeSender: Wallet
|
|
35
|
-
let ethBridgeReceiver: Wallet
|
|
36
|
-
let token: BridgeableToken
|
|
37
|
-
let bridge: LiquidityPoolBridge
|
|
38
|
-
let xl1Address: Address
|
|
39
|
-
const xl1ChainId: ChainId = toAddress('0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9')
|
|
40
|
-
let sourceObservations: BridgeSourceObservationIndexerInterface
|
|
41
|
-
let destinationObservations: BridgeDestinationObservationIndexerInterface
|
|
42
|
-
let intents: BridgeIntentIndexerInterface
|
|
43
|
-
|
|
44
|
-
const srcAmountBigint = 100n * AttoXL1ConvertFactor.xl1
|
|
45
|
-
const srcAmount = toHex(srcAmountBigint)
|
|
46
|
-
const destAmount = srcAmount // 1:1 for test
|
|
47
|
-
const ethChainId = toHex('0x7A69')
|
|
48
|
-
const bridgeableTokenContract = toHex(TOKEN_ADDRESS)
|
|
49
|
-
|
|
50
|
-
const createRandomWallet = async (): Promise<Wallet> => {
|
|
51
|
-
// Create random account
|
|
52
|
-
const account = await Account.random()
|
|
53
|
-
expect(account.private?.hex).toBeDefined()
|
|
54
|
-
const key = assertEx(account.private?.hex)
|
|
55
|
-
|
|
56
|
-
// Create a wallet from the private key
|
|
57
|
-
const wallet = new Wallet(key, provider)
|
|
58
|
-
const deployer = await provider.getSigner(0)
|
|
59
|
-
|
|
60
|
-
// Fund the wallet with some ETH for gas
|
|
61
|
-
const fundTx = await deployer.sendTransaction({ to: wallet.address, value: parseEther('1') })
|
|
62
|
-
await fundTx.wait()
|
|
63
|
-
|
|
64
|
-
// Ensure wallet has ETH
|
|
65
|
-
const balance = await provider.getBalance(wallet.address)
|
|
66
|
-
expect(balance).toBeGreaterThan(0n)
|
|
67
|
-
|
|
68
|
-
// Return the created wallet
|
|
69
|
-
return wallet
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
const bridgeFromRemote = async (xl1Address: Address, ethBridgeReceiver: Wallet, srcAmountBigint: bigint) => {
|
|
73
|
-
const balance = await token.balanceOf(await bridge.getAddress())
|
|
74
|
-
expect(balance).toBeGreaterThanOrEqual(srcAmountBigint)
|
|
75
|
-
await bridge.bridgeFromRemote(getAddress(xl1Address), ethBridgeReceiver.address, srcAmountBigint)
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
const bridgeToRemote = async (ethBridgeSender: Wallet, xl1Address: Address, srcAmountBigint: bigint) => {
|
|
79
|
-
const balance = await token.balanceOf(ethBridgeSender.address)
|
|
80
|
-
expect(balance).toBeGreaterThanOrEqual(srcAmountBigint)
|
|
81
|
-
const destAddress = getAddress(xl1Address)
|
|
82
|
-
await token.connect(ethBridgeSender).approve(bridge.getAddress(), srcAmountBigint)
|
|
83
|
-
const nonce = await ethBridgeSender.getNonce()
|
|
84
|
-
await bridge.connect(ethBridgeSender).bridgeToRemote(destAddress, srcAmountBigint, { nonce })
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
beforeAll(async () => {
|
|
88
|
-
const deployer = await provider.getSigner(0)
|
|
89
|
-
ethBridgeSender = await createRandomWallet()
|
|
90
|
-
|
|
91
|
-
token = BridgeableToken__factory.connect(TOKEN_ADDRESS, deployer)
|
|
92
|
-
bridge = LiquidityPoolBridge__factory.connect(bridgeAddress, deployer)
|
|
93
|
-
const owner = await bridge.owner()
|
|
94
|
-
expect(owner).toBeDefined()
|
|
95
|
-
expect(owner).to.eq(deployer.address)
|
|
96
|
-
const amount = srcAmountBigint * 2n
|
|
97
|
-
await token.mint(await bridge.getAddress(), parseEther(amount.toString()))
|
|
98
|
-
expect(await token.balanceOf(await bridge.getAddress())).toBeGreaterThanOrEqual(amount)
|
|
99
|
-
await token.mint(ethBridgeSender.address, parseEther(amount.toString()))
|
|
100
|
-
expect(await token.balanceOf(ethBridgeSender.address)).toBeGreaterThanOrEqual(amount)
|
|
101
|
-
})
|
|
102
|
-
|
|
103
|
-
describe('when bridging from Ethereum', () => {
|
|
104
|
-
beforeEach(async () => {
|
|
105
|
-
xl1Address = (await Account.random()).address
|
|
106
|
-
ethBridgeReceiver = await createRandomWallet()
|
|
107
|
-
sourceObservations = {
|
|
108
|
-
addObservation: vi.fn().mockResolvedValue(true),
|
|
109
|
-
getObservationForIntent: vi.fn().mockResolvedValue(null),
|
|
110
|
-
getIntentForObservation: vi.fn().mockResolvedValue(null),
|
|
111
|
-
}
|
|
112
|
-
destinationObservations = {
|
|
113
|
-
addObservation: vi.fn().mockResolvedValue(true),
|
|
114
|
-
getObservationForIntent: vi.fn().mockResolvedValue(null),
|
|
115
|
-
getIntentForObservation: vi.fn().mockResolvedValue(null),
|
|
116
|
-
}
|
|
117
|
-
intents = {
|
|
118
|
-
addIntent: vi.fn().mockResolvedValue(true),
|
|
119
|
-
getIntentByNonce: vi.fn(),
|
|
120
|
-
getIntentsForDestination: vi.fn().mockResolvedValue([]),
|
|
121
|
-
getIntentsForSource: vi.fn().mockResolvedValue([]),
|
|
122
|
-
}
|
|
123
|
-
})
|
|
124
|
-
describe('for new transfers to XL1', () => {
|
|
125
|
-
it('should observe transfer', async () => {
|
|
126
|
-
// Arrange
|
|
127
|
-
// Create observer before transfer
|
|
128
|
-
const observer = await LiquidityPoolBridgeObserver.create({
|
|
129
|
-
destinationObservations,
|
|
130
|
-
intents,
|
|
131
|
-
provider,
|
|
132
|
-
sourceObservations,
|
|
133
|
-
bridgeAddress,
|
|
134
|
-
})
|
|
135
|
-
expect(observer).toBeDefined()
|
|
136
|
-
|
|
137
|
-
// Act
|
|
138
|
-
await bridgeToRemote(ethBridgeSender, xl1Address, srcAmountBigint)
|
|
139
|
-
|
|
140
|
-
// Wait for event
|
|
141
|
-
await delay(2000)
|
|
142
|
-
|
|
143
|
-
// Assert
|
|
144
|
-
// Ensure transfer was observed
|
|
145
|
-
const fields: BridgeDetailsFields = {
|
|
146
|
-
// Source
|
|
147
|
-
src: ethChainId,
|
|
148
|
-
srcAddress: toAddress(ethBridgeSender.address),
|
|
149
|
-
srcAmount,
|
|
150
|
-
srcToken: bridgeableTokenContract,
|
|
151
|
-
|
|
152
|
-
// Destination
|
|
153
|
-
dest: xl1ChainId,
|
|
154
|
-
destAddress: xl1Address,
|
|
155
|
-
destAmount,
|
|
156
|
-
destToken: xl1ChainId,
|
|
157
|
-
}
|
|
158
|
-
expect(intents.addIntent).toHaveBeenCalledWith({
|
|
159
|
-
...fields,
|
|
160
|
-
nonce: expect.any(String),
|
|
161
|
-
schema: BridgeIntentSchema,
|
|
162
|
-
})
|
|
163
|
-
expect(sourceObservations.addObservation).toHaveBeenCalledWith({
|
|
164
|
-
...fields,
|
|
165
|
-
nonce: expect.any(String),
|
|
166
|
-
schema: BridgeSourceObservationSchema,
|
|
167
|
-
}, {
|
|
168
|
-
...fields,
|
|
169
|
-
nonce: expect.any(String),
|
|
170
|
-
schema: BridgeIntentSchema,
|
|
171
|
-
})
|
|
172
|
-
})
|
|
173
|
-
})
|
|
174
|
-
describe('for previous transfers to XL1', () => {
|
|
175
|
-
it('should observe transfer', async () => {
|
|
176
|
-
// Arrange
|
|
177
|
-
await bridgeToRemote(ethBridgeSender, xl1Address, srcAmountBigint)
|
|
178
|
-
// Wait for transaction to be mined
|
|
179
|
-
await delay(2000)
|
|
180
|
-
|
|
181
|
-
// Act
|
|
182
|
-
// Create observer after transfer
|
|
183
|
-
const observer = await LiquidityPoolBridgeObserver.create({
|
|
184
|
-
destinationObservations,
|
|
185
|
-
intents,
|
|
186
|
-
provider,
|
|
187
|
-
sourceObservations,
|
|
188
|
-
bridgeAddress,
|
|
189
|
-
})
|
|
190
|
-
expect(observer).toBeDefined()
|
|
191
|
-
|
|
192
|
-
// Assert
|
|
193
|
-
// Ensure transfer was observed
|
|
194
|
-
// Ensure transfer was observed
|
|
195
|
-
const fields: BridgeDetailsFields = {
|
|
196
|
-
// Source
|
|
197
|
-
src: ethChainId,
|
|
198
|
-
srcAddress: toAddress(ethBridgeSender.address),
|
|
199
|
-
srcAmount,
|
|
200
|
-
srcToken: bridgeableTokenContract,
|
|
201
|
-
|
|
202
|
-
// Destination
|
|
203
|
-
dest: xl1ChainId,
|
|
204
|
-
destAddress: xl1Address,
|
|
205
|
-
destAmount,
|
|
206
|
-
destToken: xl1ChainId,
|
|
207
|
-
}
|
|
208
|
-
expect(intents.addIntent).toHaveBeenCalledWith({
|
|
209
|
-
...fields,
|
|
210
|
-
nonce: expect.any(String),
|
|
211
|
-
schema: BridgeIntentSchema,
|
|
212
|
-
})
|
|
213
|
-
expect(sourceObservations.addObservation).toHaveBeenCalledWith({
|
|
214
|
-
...fields,
|
|
215
|
-
nonce: expect.any(String),
|
|
216
|
-
schema: BridgeSourceObservationSchema,
|
|
217
|
-
}, {
|
|
218
|
-
...fields,
|
|
219
|
-
nonce: expect.any(String),
|
|
220
|
-
schema: BridgeIntentSchema,
|
|
221
|
-
})
|
|
222
|
-
})
|
|
223
|
-
})
|
|
224
|
-
})
|
|
225
|
-
|
|
226
|
-
describe('when bridging to Ethereum', () => {
|
|
227
|
-
beforeEach(async () => {
|
|
228
|
-
xl1Address = (await Account.random()).address
|
|
229
|
-
ethBridgeReceiver = await createRandomWallet()
|
|
230
|
-
sourceObservations = {
|
|
231
|
-
addObservation: vi.fn().mockResolvedValue(true),
|
|
232
|
-
getObservationForIntent: vi.fn().mockResolvedValue(null),
|
|
233
|
-
getIntentForObservation: vi.fn().mockResolvedValue(null),
|
|
234
|
-
}
|
|
235
|
-
destinationObservations = {
|
|
236
|
-
addObservation: vi.fn().mockResolvedValue(true),
|
|
237
|
-
getObservationForIntent: vi.fn().mockResolvedValue(null),
|
|
238
|
-
getIntentForObservation: vi.fn().mockResolvedValue(null),
|
|
239
|
-
}
|
|
240
|
-
const nonce = Date.now().toString()
|
|
241
|
-
const intent: BridgeIntent = {
|
|
242
|
-
// Source
|
|
243
|
-
src: xl1ChainId, // From XL1
|
|
244
|
-
srcAddress: xl1Address, // From XL1 sender
|
|
245
|
-
srcAmount,
|
|
246
|
-
srcToken: xl1ChainId, // In XL1
|
|
247
|
-
|
|
248
|
-
// Destination
|
|
249
|
-
dest: ethChainId, // To Ethereum
|
|
250
|
-
destAddress: toAddress(ethBridgeReceiver.address),
|
|
251
|
-
destAmount,
|
|
252
|
-
destToken: bridgeableTokenContract,
|
|
253
|
-
|
|
254
|
-
// Details
|
|
255
|
-
nonce,
|
|
256
|
-
|
|
257
|
-
schema: BridgeIntentSchema,
|
|
258
|
-
}
|
|
259
|
-
intents = {
|
|
260
|
-
addIntent: vi.fn().mockResolvedValue(true),
|
|
261
|
-
getIntentByNonce: vi.fn().mockResolvedValue(intent),
|
|
262
|
-
getIntentsForDestination: vi.fn().mockResolvedValue([intent]),
|
|
263
|
-
getIntentsForSource: vi.fn().mockResolvedValue([]),
|
|
264
|
-
}
|
|
265
|
-
})
|
|
266
|
-
describe('for new transfers from xl1 address', () => {
|
|
267
|
-
it('should observe transfer', async () => {
|
|
268
|
-
// Arrange
|
|
269
|
-
// Create observer before transfer
|
|
270
|
-
const observer = await LiquidityPoolBridgeObserver.create({
|
|
271
|
-
destinationObservations,
|
|
272
|
-
intents,
|
|
273
|
-
provider,
|
|
274
|
-
sourceObservations,
|
|
275
|
-
bridgeAddress,
|
|
276
|
-
})
|
|
277
|
-
expect(observer).toBeDefined()
|
|
278
|
-
|
|
279
|
-
// Act
|
|
280
|
-
await bridgeFromRemote(xl1Address, ethBridgeReceiver, srcAmountBigint)
|
|
281
|
-
|
|
282
|
-
// Wait for event
|
|
283
|
-
await delay(2000)
|
|
284
|
-
|
|
285
|
-
// Assert
|
|
286
|
-
// Ensure transfer was observed
|
|
287
|
-
expect(destinationObservations.addObservation).toHaveBeenCalled()
|
|
288
|
-
})
|
|
289
|
-
})
|
|
290
|
-
describe('for previous transfers from xl1 address', () => {
|
|
291
|
-
it('should observe transfer', async () => {
|
|
292
|
-
// Arrange
|
|
293
|
-
await bridgeFromRemote(xl1Address, ethBridgeReceiver, srcAmountBigint)
|
|
294
|
-
// Wait for transaction to be mined
|
|
295
|
-
await delay(2000)
|
|
296
|
-
|
|
297
|
-
// Act
|
|
298
|
-
// Create observer after transfer
|
|
299
|
-
const observer = await LiquidityPoolBridgeObserver.create({
|
|
300
|
-
destinationObservations,
|
|
301
|
-
intents,
|
|
302
|
-
provider,
|
|
303
|
-
sourceObservations,
|
|
304
|
-
bridgeAddress,
|
|
305
|
-
})
|
|
306
|
-
expect(observer).toBeDefined()
|
|
307
|
-
|
|
308
|
-
// Assert
|
|
309
|
-
// Ensure transfer was observed
|
|
310
|
-
expect(destinationObservations.addObservation).toHaveBeenCalled()
|
|
311
|
-
})
|
|
312
|
-
})
|
|
313
|
-
})
|
|
314
|
-
})
|
|
@@ -1,266 +0,0 @@
|
|
|
1
|
-
import { toAddress, toHex } from '@xylabs/sdk-js'
|
|
2
|
-
import { HDWallet } from '@xyo-network/wallet'
|
|
3
|
-
import type { WalletInstance } from '@xyo-network/wallet-model'
|
|
4
|
-
import type {
|
|
5
|
-
BridgeDestinationObservation, BridgeIntent, BridgeSourceObservation, ChainId,
|
|
6
|
-
} from '@xyo-network/xl1-protocol'
|
|
7
|
-
import {
|
|
8
|
-
AttoXL1ConvertFactor, BridgeDestinationObservationSchema, BridgeIntentSchema,
|
|
9
|
-
BridgeSourceObservationSchema,
|
|
10
|
-
} from '@xyo-network/xl1-protocol'
|
|
11
|
-
import type { Config } from '@xyo-network/xl1-protocol-sdk'
|
|
12
|
-
import { getDefaultConfig } from '@xyo-network/xl1-protocol-sdk'
|
|
13
|
-
import {
|
|
14
|
-
beforeAll, describe, expect, it, vi,
|
|
15
|
-
} from 'vitest'
|
|
16
|
-
|
|
17
|
-
import type {
|
|
18
|
-
BridgeDestinationObservationIndexerInterface, BridgeIntentIndexerInterface, BridgeServiceParams,
|
|
19
|
-
BridgeSourceObservationIndexerInterface,
|
|
20
|
-
ChainBridgeRelayInterface,
|
|
21
|
-
LockingBridgeIntentProcessorInterface, UnlockingBridgeIntentProcessorInterface,
|
|
22
|
-
} from '../../../../interface/index.ts'
|
|
23
|
-
import { ChainBridgeRelayService } from '../ChainBridgeRelayService.ts'
|
|
24
|
-
|
|
25
|
-
describe('ChainBridgeRelayService', () => {
|
|
26
|
-
let account: WalletInstance
|
|
27
|
-
let config: Config
|
|
28
|
-
let destinationObservations: BridgeDestinationObservationIndexerInterface
|
|
29
|
-
let destinationRelay: ChainBridgeRelayInterface
|
|
30
|
-
let intentProcessed: LockingBridgeIntentProcessorInterface
|
|
31
|
-
let intentProcessing: UnlockingBridgeIntentProcessorInterface
|
|
32
|
-
let intents: BridgeIntentIndexerInterface
|
|
33
|
-
let sourceObservations: BridgeSourceObservationIndexerInterface
|
|
34
|
-
let relay: ChainBridgeRelayService
|
|
35
|
-
|
|
36
|
-
const srcAmount = toHex(100n * AttoXL1ConvertFactor.xl1) // 100 XL1 in AttoXL1
|
|
37
|
-
const destAmount = srcAmount // 1:1 for test
|
|
38
|
-
|
|
39
|
-
const xl1ChainId: ChainId = toHex('dd381fbb392c85160d8b0453e446757b12384046')
|
|
40
|
-
const ethChainId = toHex('0x1')
|
|
41
|
-
|
|
42
|
-
const xl1Address = toAddress('1111111111111111111111111111111111111111')
|
|
43
|
-
const ethAddress = toAddress('0x2222222222222222222222222222222222222222')
|
|
44
|
-
|
|
45
|
-
const bridgeableTokenContract = toHex('0x3333333333333333333333333333333333333333')
|
|
46
|
-
|
|
47
|
-
const nonce = 'd5eeff33-d5bc-4aca-9ecb-3406c02a5dc4'
|
|
48
|
-
|
|
49
|
-
const xl1TxHash = toHex('0x4444444444444444444444444444444444444444444444444444444444444444') // Some XL1 tx hash
|
|
50
|
-
const ethTxHash = toHex('0x5555555555555555555555555555555555555555555555555555555555555555') // Some Eth tx hash
|
|
51
|
-
|
|
52
|
-
const intent: BridgeIntent = {
|
|
53
|
-
// Source
|
|
54
|
-
src: xl1ChainId, // From XL1
|
|
55
|
-
srcAddress: xl1Address, // From XL1 sender
|
|
56
|
-
srcAmount,
|
|
57
|
-
srcToken: xl1ChainId, // In XL1
|
|
58
|
-
|
|
59
|
-
// Destination
|
|
60
|
-
dest: ethChainId, // To Ethereum
|
|
61
|
-
destAddress: ethAddress,
|
|
62
|
-
destAmount,
|
|
63
|
-
destToken: bridgeableTokenContract,
|
|
64
|
-
|
|
65
|
-
// Details
|
|
66
|
-
nonce,
|
|
67
|
-
|
|
68
|
-
schema: BridgeIntentSchema,
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
const srcObservation: BridgeSourceObservation = {
|
|
72
|
-
// Source
|
|
73
|
-
src: xl1ChainId, // From XL1
|
|
74
|
-
srcAddress: xl1Address, // From XL1 sender
|
|
75
|
-
srcAmount,
|
|
76
|
-
srcToken: xl1ChainId, // In XL1
|
|
77
|
-
|
|
78
|
-
// Destination
|
|
79
|
-
dest: ethChainId, // To Ethereum
|
|
80
|
-
destAddress: ethAddress,
|
|
81
|
-
destAmount,
|
|
82
|
-
destToken: bridgeableTokenContract,
|
|
83
|
-
|
|
84
|
-
// Observation
|
|
85
|
-
srcConfirmation: xl1TxHash,
|
|
86
|
-
|
|
87
|
-
schema: BridgeSourceObservationSchema,
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
const destObservation: BridgeDestinationObservation = {
|
|
91
|
-
// Source
|
|
92
|
-
src: xl1ChainId, // From XL1
|
|
93
|
-
srcAddress: xl1Address, // From XL1 sender
|
|
94
|
-
srcAmount,
|
|
95
|
-
srcToken: xl1ChainId, // In XL1
|
|
96
|
-
|
|
97
|
-
// Destination
|
|
98
|
-
dest: ethChainId, // To Ethereum
|
|
99
|
-
destAddress: ethAddress,
|
|
100
|
-
destAmount,
|
|
101
|
-
destToken: bridgeableTokenContract,
|
|
102
|
-
|
|
103
|
-
// Observation
|
|
104
|
-
destConfirmation: ethTxHash,
|
|
105
|
-
|
|
106
|
-
schema: BridgeDestinationObservationSchema,
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
beforeAll(async () => {
|
|
110
|
-
account = await HDWallet.random()
|
|
111
|
-
config = getDefaultConfig()
|
|
112
|
-
|
|
113
|
-
intents = {
|
|
114
|
-
addIntent: vi.fn().mockResolvedValue(true),
|
|
115
|
-
getIntentByNonce: vi.fn(),
|
|
116
|
-
getIntentsForDestination: vi.fn().mockResolvedValue([]),
|
|
117
|
-
getIntentsForSource: vi.fn().mockResolvedValue([]),
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
sourceObservations = {
|
|
121
|
-
addObservation: vi.fn().mockResolvedValue(true),
|
|
122
|
-
getIntentForObservation: vi.fn().mockResolvedValue(null),
|
|
123
|
-
getObservationForIntent: vi.fn().mockResolvedValue(null),
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
destinationObservations = {
|
|
127
|
-
addObservation: vi.fn().mockResolvedValue(true),
|
|
128
|
-
getIntentForObservation: vi.fn().mockResolvedValue(null),
|
|
129
|
-
getObservationForIntent: vi.fn().mockResolvedValue(null),
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
intentProcessed = {
|
|
133
|
-
isLocked: vi.fn().mockResolvedValue(null),
|
|
134
|
-
lock: vi.fn().mockResolvedValue(true),
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
intentProcessing = {
|
|
138
|
-
isLocked: vi.fn().mockResolvedValue(null),
|
|
139
|
-
lock: vi.fn().mockResolvedValue(true),
|
|
140
|
-
unlock: vi.fn().mockResolvedValue(true),
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
destinationRelay = {
|
|
144
|
-
beginRelay: vi.fn().mockResolvedValue(true),
|
|
145
|
-
relaySync: vi.fn().mockResolvedValue(null),
|
|
146
|
-
onDestinationObservation: vi.fn().mockResolvedValue(false),
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
const params: BridgeServiceParams = {
|
|
150
|
-
account,
|
|
151
|
-
config,
|
|
152
|
-
destinationObservations,
|
|
153
|
-
destinationRelay,
|
|
154
|
-
intentProcessed,
|
|
155
|
-
intentProcessing,
|
|
156
|
-
intents,
|
|
157
|
-
sourceObservations,
|
|
158
|
-
}
|
|
159
|
-
relay = await ChainBridgeRelayService.create(params)
|
|
160
|
-
})
|
|
161
|
-
describe('beginRelay', () => {
|
|
162
|
-
it('should do nothing if source observation is null', async () => {
|
|
163
|
-
// Arrange
|
|
164
|
-
sourceObservations.getObservationForIntent = vi.fn().mockResolvedValue(null)
|
|
165
|
-
|
|
166
|
-
// Act
|
|
167
|
-
const result = await relay.beginRelay(intent)
|
|
168
|
-
|
|
169
|
-
// Assert
|
|
170
|
-
expect(intentProcessing.lock).not.toHaveBeenCalled()
|
|
171
|
-
expect(result).toBe(false)
|
|
172
|
-
})
|
|
173
|
-
|
|
174
|
-
it('should lock and call destinationRelay.beginRelay if observation exists', async () => {
|
|
175
|
-
// Arrange
|
|
176
|
-
sourceObservations.getObservationForIntent = vi.fn().mockResolvedValue(srcObservation)
|
|
177
|
-
intentProcessing.lock = vi.fn().mockResolvedValue(true)
|
|
178
|
-
destinationRelay.beginRelay = vi.fn().mockResolvedValue(true)
|
|
179
|
-
|
|
180
|
-
// Act
|
|
181
|
-
const result = await relay.beginRelay(intent)
|
|
182
|
-
|
|
183
|
-
// Assert
|
|
184
|
-
expect(sourceObservations.getObservationForIntent).toHaveBeenCalledWith(intent)
|
|
185
|
-
expect(intentProcessing.lock).toHaveBeenCalledWith(account.address, intent)
|
|
186
|
-
expect(destinationRelay.beginRelay).toHaveBeenCalledWith(intent)
|
|
187
|
-
expect(result).toBe(true)
|
|
188
|
-
})
|
|
189
|
-
|
|
190
|
-
it('should unlock if an exception is thrown', async () => {
|
|
191
|
-
// Arrange
|
|
192
|
-
sourceObservations.getObservationForIntent = vi.fn().mockResolvedValue(srcObservation)
|
|
193
|
-
intentProcessing.lock = vi.fn().mockResolvedValue(true)
|
|
194
|
-
destinationRelay.beginRelay = vi.fn().mockImplementation(() => {
|
|
195
|
-
throw new Error('boom')
|
|
196
|
-
})
|
|
197
|
-
intentProcessing.unlock = vi.fn()
|
|
198
|
-
|
|
199
|
-
// Act
|
|
200
|
-
const result = await relay.beginRelay(intent)
|
|
201
|
-
|
|
202
|
-
// Assert
|
|
203
|
-
expect(intentProcessing.unlock).toHaveBeenCalledWith(account.address, intent)
|
|
204
|
-
expect(result).toBe(false)
|
|
205
|
-
})
|
|
206
|
-
})
|
|
207
|
-
describe('onBridgeDestinationObservation', () => {
|
|
208
|
-
it('should return false if no intent exists for observation', async () => {
|
|
209
|
-
// Arrange
|
|
210
|
-
destinationObservations.getIntentForObservation = vi.fn().mockResolvedValue(null)
|
|
211
|
-
|
|
212
|
-
// Act
|
|
213
|
-
const result = await relay.onDestinationObservation(destObservation)
|
|
214
|
-
|
|
215
|
-
// Assert
|
|
216
|
-
expect(intentProcessed.isLocked).not.toHaveBeenCalled()
|
|
217
|
-
expect(result).toBe(false)
|
|
218
|
-
})
|
|
219
|
-
|
|
220
|
-
it('should return false if already processed', async () => {
|
|
221
|
-
// Arrange
|
|
222
|
-
const other = await HDWallet.random()
|
|
223
|
-
destinationObservations.getIntentForObservation = vi.fn().mockResolvedValue(intent)
|
|
224
|
-
intentProcessed.isLocked = vi.fn().mockResolvedValue(other.address)
|
|
225
|
-
|
|
226
|
-
// Act
|
|
227
|
-
const result = await relay.onDestinationObservation(destObservation)
|
|
228
|
-
|
|
229
|
-
// Assert
|
|
230
|
-
expect(intentProcessed.isLocked).toHaveBeenCalledWith(intent)
|
|
231
|
-
expect(result).toBe(false)
|
|
232
|
-
})
|
|
233
|
-
|
|
234
|
-
it('should return false if not the processor', async () => {
|
|
235
|
-
// Arrange
|
|
236
|
-
const other = await HDWallet.random()
|
|
237
|
-
destinationObservations.getIntentForObservation = vi.fn().mockResolvedValue(intent)
|
|
238
|
-
intentProcessed.isLocked = vi.fn().mockResolvedValue(null)
|
|
239
|
-
intentProcessing.isLocked = vi.fn().mockResolvedValue(other.address)
|
|
240
|
-
|
|
241
|
-
// Act
|
|
242
|
-
const result = await relay.onDestinationObservation(destObservation)
|
|
243
|
-
|
|
244
|
-
// Assert
|
|
245
|
-
expect(intentProcessing.isLocked).toHaveBeenCalledWith(intent)
|
|
246
|
-
expect(result).toBe(false)
|
|
247
|
-
})
|
|
248
|
-
|
|
249
|
-
it('should process if we are the processor', async () => {
|
|
250
|
-
// Arrange
|
|
251
|
-
destinationObservations.getIntentForObservation = vi.fn().mockResolvedValue(intent)
|
|
252
|
-
intentProcessed.isLocked = vi.fn().mockResolvedValue(null)
|
|
253
|
-
intentProcessing.isLocked = vi.fn().mockResolvedValue(account.address)
|
|
254
|
-
intentProcessed.lock = vi.fn().mockResolvedValue(true)
|
|
255
|
-
intentProcessing.unlock = vi.fn().mockResolvedValue(true)
|
|
256
|
-
|
|
257
|
-
// Act
|
|
258
|
-
const result = await relay.onDestinationObservation(destObservation)
|
|
259
|
-
|
|
260
|
-
// Assert
|
|
261
|
-
expect(intentProcessed.lock).toHaveBeenCalledWith(account.address, intent)
|
|
262
|
-
expect(intentProcessing.unlock).toHaveBeenCalledWith(account.address, intent)
|
|
263
|
-
expect(result).toBe(true)
|
|
264
|
-
})
|
|
265
|
-
})
|
|
266
|
-
})
|