@gibs/bridge-sdk 1.6.36 → 1.7.2

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.
@@ -0,0 +1,853 @@
1
+ import { concatHex, encodeAbiParameters, encodeFunctionData, getAddress, type Hex, isAddress, zeroAddress } from "viem";
2
+ import { Chains, isNative, nativeAssetOut, type Pathway, pathway } from "./config.js";
3
+ import { FeeType } from "./fee-type.js";
4
+ import type { BridgeKey, Token } from "./types.js";
5
+ import type { TokenBridgeInfo } from "./chain-info.js";
6
+ import * as abis from "./abis.js";
7
+
8
+ export const oneEther = 10n ** 18n
9
+
10
+ export const basisPoints = 10_000n
11
+
12
+ /**
13
+ * Returns the bridge pathway (configuration) for a given bridge key, asset in, and whether to use the production pathway
14
+ * @param bridgeKey - the bridge key to use
15
+ * @param isProd - whether to use the production pathway
16
+ * @param assetIn - the asset in to bridge
17
+ * @returns the bridge pathway
18
+ */
19
+ export const bridgePathway = ({
20
+ bridgeKey,
21
+ isProd,
22
+ assetIn,
23
+ }: {
24
+ bridgeKey: BridgeKey
25
+ isProd: boolean
26
+ assetIn: Token | null
27
+ }) => (
28
+ pathway(bridgeKey, isProd, assetIn?.address) ?? null
29
+ )
30
+
31
+ /**
32
+ * Retrieves the amount to bridge from the amount and asset in. If either of them is nil, returns 0n
33
+ * @param amountIn - the amount to bridge
34
+ * @param assetIn - the asset in to bridge
35
+ * @returns the amount to bridge
36
+ */
37
+ export const amountToBridge = ({
38
+ amountIn,
39
+ assetIn,
40
+ }: {
41
+ amountIn: bigint | null
42
+ assetIn: Token | null
43
+ }) => {
44
+ if (!amountIn || amountIn === 0n || !assetIn) {
45
+ return 0n
46
+ }
47
+ return amountIn
48
+ }
49
+
50
+ /**
51
+ * Calculates the bridge cost from the amount to bridge and bridge fee
52
+ * @param amountToBridge - the amount to bridge
53
+ * @param bridgeFee - the bridge fee
54
+ * @returns the bridge cost
55
+ */
56
+ export const bridgeCost = ({
57
+ amountToBridge,
58
+ bridgeFee,
59
+ }: {
60
+ amountToBridge: bigint
61
+ bridgeFee: bigint | null
62
+ }) => {
63
+ if (bridgeFee === null) return null
64
+ return (amountToBridge * bridgeFee) / oneEther
65
+ }
66
+
67
+ /**
68
+ * Calculates the amount after bridge fee from the amount to bridge and bridge cost
69
+ * @param amountToBridge - the amount to bridge
70
+ * @param bridgeCost - the bridge cost
71
+ * @returns the amount after bridge fee
72
+ */
73
+ export const amountAfterBridgeFee = ({
74
+ amountToBridge,
75
+ bridgeCost,
76
+ }: {
77
+ amountToBridge: bigint
78
+ bridgeCost: bigint | null
79
+ }) => {
80
+ if (bridgeCost === null) return null
81
+ const afterFee = amountToBridge - bridgeCost
82
+ if (afterFee < 0n) return 0n
83
+ return afterFee
84
+ }
85
+
86
+ /**
87
+ * Calculates the estimated amount out from the amount after bridge fee and fee
88
+ * @param amountAfterBridgeFee - the amount after bridge fee
89
+ * @param fee - the fee
90
+ * @returns the estimated amount out
91
+ */
92
+ export const estimatedAmountOut = ({
93
+ amountAfterBridgeFee,
94
+ fee,
95
+ }: {
96
+ amountAfterBridgeFee: bigint | null
97
+ fee: bigint | null
98
+ }) => {
99
+ if (typeof fee !== 'bigint') return null
100
+ if (amountAfterBridgeFee === null) return null
101
+ if (fee > amountAfterBridgeFee) return 0n
102
+ return amountAfterBridgeFee - fee
103
+ }
104
+
105
+ /**
106
+ * Calculates the estimated fee from the amount after bridge fee, fee, percent fee, fee type, limit, and whether to deliver the costs
107
+ * @param amountAfterBridgeFee - the amount after bridge fee
108
+ * @param fee - the fee
109
+ * @param percentFee - the percent fee
110
+ * @param feeType - the fee type
111
+ * @param limit - the limit
112
+ * @param costsToDeliver - whether to deliver the costs
113
+ * @returns the estimated fee
114
+ */
115
+ export const estimatedFee = ({
116
+ amountAfterBridgeFee,
117
+ fee,
118
+ percentFee,
119
+ feeType,
120
+ limit,
121
+ costsToDeliver,
122
+ }: {
123
+ amountAfterBridgeFee: bigint | null
124
+ fee: bigint
125
+ percentFee: bigint
126
+ feeType: FeeType
127
+ limit: bigint | null
128
+ costsToDeliver: boolean
129
+ }) => {
130
+ const fixedFee = amountAfterBridgeFee ? (amountAfterBridgeFee * percentFee) / oneEther : null
131
+ if (!costsToDeliver) {
132
+ return 0n
133
+ }
134
+ if (feeType === FeeType.FIXED) {
135
+ return fee
136
+ } else if (feeType === FeeType.PERCENT) {
137
+ if (amountAfterBridgeFee === null) return null
138
+ return fixedFee
139
+ } else if (feeType === FeeType.GAS_TIP) {
140
+ return limit
141
+ }
142
+ return null
143
+ }
144
+
145
+ /**
146
+ * Calculates the estimated native network cost from the estimated gas and latest base fee per gas
147
+ * @param estimatedGas - the estimated gas
148
+ * @param latestBaseFeePerGas - the latest base fee per gas
149
+ * @param requiresDelivery - whether to deliver the costs
150
+ * @returns the estimated native network cost
151
+ */
152
+ export const estimatedNativeNetworkCost = ({
153
+ estimatedGas,
154
+ latestBaseFeePerGas,
155
+ requiresDelivery,
156
+ }: {
157
+ estimatedGas: bigint | null
158
+ latestBaseFeePerGas: bigint | null
159
+ requiresDelivery: boolean
160
+ }) => {
161
+ if (!estimatedGas || !latestBaseFeePerGas || !requiresDelivery) {
162
+ return null
163
+ }
164
+ return BigInt(estimatedGas * latestBaseFeePerGas)
165
+ }
166
+
167
+ /**
168
+ * Calculates the estimated token network cost from the estimated native
169
+ * network cost, price corrective, decimals, and one token int
170
+ * @param estimatedNativeNetworkCost - the estimated native network cost
171
+ * @param priceCorrective - the price corrective
172
+ * @param decimals - the decimals
173
+ * @param oneTokenInt - the one token int
174
+ * @returns the estimated token network cost
175
+ */
176
+ export const estimatedTokenNetworkCost = ({
177
+ estimatedNativeNetworkCost,
178
+ priceCorrective,
179
+ decimals,
180
+ oneTokenInt,
181
+ }: {
182
+ estimatedNativeNetworkCost: bigint | null
183
+ priceCorrective: bigint | null
184
+ decimals: number | null
185
+ oneTokenInt: bigint | null
186
+ }) => {
187
+ if (!priceCorrective || !oneTokenInt || !estimatedNativeNetworkCost || !decimals) {
188
+ return null
189
+ }
190
+ const tokenCost = (estimatedNativeNetworkCost * oneTokenInt) / priceCorrective
191
+ return tokenCost
192
+ }
193
+
194
+ /**
195
+ * Calculates one token of the asset in as an int
196
+ * @param assetIn - the asset in to bridge
197
+ * @returns the one token int
198
+ */
199
+ export const oneTokenInt = ({
200
+ assetIn,
201
+ }: {
202
+ assetIn: Token | null
203
+ }) => {
204
+ if (!assetIn) return 1n
205
+ return 10n ** BigInt(assetIn.decimals)
206
+ }
207
+
208
+ /**
209
+ * Returns the limit as a bigint. Nil uses 0n
210
+ * @param lim - the limit
211
+ * @returns the limit
212
+ */
213
+ export const limit = (lim: bigint | null) => {
214
+ if (!lim) {
215
+ return 0n
216
+ }
217
+ return lim
218
+ }
219
+
220
+ /**
221
+ * Returns the network switch asset out address from the asset out, unwrap, and to chain
222
+ * @param assetOut - the asset out
223
+ * @param unwrap - whether to unwrap
224
+ * @param toChain - the chain to switch to
225
+ * @returns the network switch asset out address
226
+ */
227
+ export const networkSwitchAssetOutAddress = ({
228
+ assetOut,
229
+ unwrap,
230
+ toChain,
231
+ }: {
232
+ assetOut: Token | null
233
+ unwrap: boolean
234
+ toChain: Chains
235
+ }) => {
236
+ if (!assetOut) return null
237
+ if (!unwrap) return assetOut.address
238
+ return nativeAssetOut[toChain] === assetOut.address ? zeroAddress : assetOut.address
239
+ }
240
+
241
+ /**
242
+ * Calculates the desired excess compensation basis points from the path, asset in, asset out, bridge key, fee type, list, and asset out address
243
+ * @param path - the path
244
+ * @param assetIn - the asset in to bridge
245
+ * @param assetOut - the asset out
246
+ * @param bridgeKey - the bridge key
247
+ * @param feeType - the fee type
248
+ * @param list - the list
249
+ * @param assetOutAddress - the asset out address
250
+ * @returns the desired excess compensation basis points
251
+ */
252
+ export const desiredExcessCompensationBasisPoints = ({
253
+ path,
254
+ assetIn,
255
+ assetOut,
256
+ bridgeKey,
257
+ feeType,
258
+ list,
259
+ assetOutAddress,
260
+ }: {
261
+ path: Pathway | null
262
+ assetIn: Token | null
263
+ assetOut: Token | null
264
+ bridgeKey: BridgeKey
265
+ feeType: FeeType
266
+ list: Set<string>
267
+ assetOutAddress: string | null
268
+ }) => {
269
+ if (!path?.requiresDelivery) {
270
+ return 0n
271
+ }
272
+ return (
273
+ !assetIn
274
+ ? 0n
275
+ : feeType === FeeType.PERCENT
276
+ ? 1_000n
277
+ : isNative(assetIn, bridgeKey) || isNative(assetOut, bridgeKey)
278
+ ? 1_000n
279
+ : list.has(getAddress(assetIn?.address ?? '')) ||
280
+ list.has(assetOutAddress ? getAddress(assetOutAddress) : '0x')
281
+ ? 5_000n
282
+ : 10_000n
283
+ )
284
+ }
285
+
286
+ /**
287
+ * Calculates the estimated cost from the should deliver, amount after bridge fee, percent fee,
288
+ * estimated token network cost, reasonable percent on top of gas fee, and fee type
289
+ * @param shouldDeliver - whether to deliver the costs
290
+ * @param amountAfterBridgeFee - the amount after bridge fee
291
+ * @param percentFee - the percent fee
292
+ * @param estimatedTokenNetworkCost - the estimated token network cost
293
+ * @param reasonablePercentOnTopOfGasFee - the reasonable percent on top of gas fee
294
+ * @param feeType - the fee type
295
+ * @returns the estimated cost
296
+ */
297
+ export const estimatedCost = ({
298
+ shouldDeliver,
299
+ amountAfterBridgeFee,
300
+ percentFee,
301
+ estimatedTokenNetworkCost,
302
+ reasonablePercentOnTopOfGasFee,
303
+ feeType,
304
+ }: {
305
+ shouldDeliver: boolean
306
+ amountAfterBridgeFee: bigint | null
307
+ percentFee: bigint | null
308
+ estimatedTokenNetworkCost: bigint | null
309
+ reasonablePercentOnTopOfGasFee: bigint | null
310
+ feeType: FeeType
311
+ }) => {
312
+ if (!shouldDeliver) {
313
+ return null
314
+ }
315
+ if (feeType === FeeType.PERCENT) {
316
+ if (amountAfterBridgeFee === null) return null
317
+ return (amountAfterBridgeFee * (percentFee ?? 0n)) / oneEther
318
+ }
319
+ // gas tip
320
+ if (!estimatedTokenNetworkCost) {
321
+ return null
322
+ }
323
+ if (!reasonablePercentOnTopOfGasFee) {
324
+ return null
325
+ }
326
+ return estimatedTokenNetworkCost * (reasonablePercentOnTopOfGasFee + oneEther)
327
+ }
328
+
329
+ /**
330
+ * Calculates the reasonable fixed fee from the estimated token network cost and desired excess compensation basis points
331
+ * @param estimatedTokenNetworkCost - the estimated token network cost
332
+ * @param desiredExcessCompensationBasisPoints - the desired excess compensation basis points
333
+ * @returns the reasonable fixed fee
334
+ */
335
+ export const reasonableFixedFee = ({
336
+ estimatedTokenNetworkCost,
337
+ desiredExcessCompensationBasisPoints,
338
+ }: {
339
+ estimatedTokenNetworkCost: bigint | null
340
+ desiredExcessCompensationBasisPoints: bigint
341
+ }) => {
342
+ if (!estimatedTokenNetworkCost) {
343
+ return null
344
+ }
345
+ return (
346
+ (estimatedTokenNetworkCost * (25_000n + desiredExcessCompensationBasisPoints)) /
347
+ basisPoints
348
+ )
349
+ }
350
+
351
+ /**
352
+ * Calculates the reasonable percent on gas limit from the gas tip fee and estimated token network cost
353
+ * @param gasTipFee - the gas tip fee
354
+ * @param estimatedTokenNetworkCost - the estimated token network cost
355
+ * @returns the reasonable percent on gas limit
356
+ */
357
+ export const reasonablePercentOnGasLimit = ({
358
+ gasTipFee,
359
+ estimatedTokenNetworkCost,
360
+ }: {
361
+ gasTipFee: bigint | null
362
+ estimatedTokenNetworkCost: bigint | null
363
+ }) => {
364
+ return (
365
+ (25_000n *
366
+ ((oneEther + (gasTipFee ?? 0n)) * (estimatedTokenNetworkCost ?? 0n))) /
367
+ (oneEther * basisPoints)
368
+ )
369
+ }
370
+
371
+ /**
372
+ * Calculates the reasonable percent fee from the reasonable fixed fee and amount after bridge fee
373
+ * @param reasonableFixedFee - the reasonable fixed fee
374
+ * @param amountAfterBridgeFee - the amount after bridge fee
375
+ * @returns the reasonable percent fee
376
+ */
377
+ export const reasonablePercentFee = ({
378
+ reasonableFixedFee,
379
+ amountAfterBridgeFee,
380
+ }: {
381
+ reasonableFixedFee: bigint | null
382
+ amountAfterBridgeFee: bigint | null
383
+ }) => {
384
+ if (!reasonableFixedFee) {
385
+ return null
386
+ }
387
+ if (!amountAfterBridgeFee) {
388
+ return null
389
+ }
390
+ const highFee = amountAfterBridgeFee / 10n
391
+ const basisFeeTruncator = 10n ** 14n
392
+ const max = 1_000n * basisFeeTruncator
393
+ const min = 5n * basisFeeTruncator
394
+ if (highFee < reasonableFixedFee) {
395
+ return max // 10%
396
+ }
397
+ const highResPercent = (reasonableFixedFee * oneEther) / amountAfterBridgeFee
398
+ if (highResPercent < min) {
399
+ return min
400
+ } else if (highResPercent > max) {
401
+ return max
402
+ }
403
+ const basisPoint = highResPercent / basisFeeTruncator
404
+ return basisPoint * basisFeeTruncator
405
+ }
406
+
407
+ /**
408
+ * Returns whether the asset in address is interacting with a bridge token
409
+ * @param assetLink - the asset link
410
+ * @param assetInAddress - the asset in address
411
+ * @returns whether the asset in address is interacting with a bridge token
412
+ */
413
+ export const interactingWithBridgeToken = ({
414
+ assetLink,
415
+ assetInAddress,
416
+ }: {
417
+ assetLink: TokenBridgeInfo | null
418
+ assetInAddress: string | null
419
+ }) => {
420
+ const { toForeign, toHome } = assetLink || {}
421
+ const { foreign } = toForeign || {}
422
+ const { home } = toHome || {}
423
+ if (!assetInAddress) return false
424
+ return !!(
425
+ (foreign && getAddress(foreign) === getAddress(assetInAddress)) ||
426
+ (home && getAddress(home) === getAddress(assetInAddress))
427
+ )
428
+ }
429
+
430
+ /**
431
+ * Calculates the fee director struct encoded from the recipient, bridge pathway, fee type, price corrective, gas tip fee, percent fee, fee type settings, limit, and asset out
432
+ * @param recipient - the recipient
433
+ * @param bridgePathway - the bridge pathway
434
+ * @param feeType - the fee type
435
+ * @param priceCorrective - the price corrective
436
+ * @param gasTipFee - the gas tip fee
437
+ * @param percentFee - the percent fee
438
+ * @param feeTypeSettings - the fee type settings
439
+ * @param limit - the limit
440
+ * @param assetOut - the asset out
441
+ * @returns the fee director struct encoded
442
+ */
443
+ export const feeDirectorStructEncoded = ({
444
+ recipient,
445
+ bridgePathway,
446
+ feeType,
447
+ priceCorrective,
448
+ gasTipFee,
449
+ percentFee,
450
+ feeTypeSettings,
451
+ limit,
452
+ assetOut,
453
+ }: {
454
+ recipient: Hex | null
455
+ feeType: FeeType
456
+ priceCorrective: bigint | null
457
+ gasTipFee: bigint | null
458
+ percentFee: bigint | null
459
+ feeTypeSettings: bigint
460
+ limit: bigint
461
+ bridgePathway: Pathway | null
462
+ assetOut: Token | null
463
+ }) => {
464
+ if (!assetOut || !bridgePathway) {
465
+ return null
466
+ }
467
+ if (!bridgePathway.requiresDelivery) {
468
+ return null
469
+ }
470
+ if (!priceCorrective) {
471
+ return null
472
+ }
473
+ let multiplier = 0n
474
+ if (feeType === FeeType.GAS_TIP && priceCorrective > 0n) {
475
+ multiplier =
476
+ ((oneEther + (gasTipFee ?? 0n)) * 10n ** BigInt(assetOut.decimals)) /
477
+ priceCorrective
478
+ } else if (feeType === FeeType.PERCENT) {
479
+ multiplier = percentFee ?? 0n
480
+ }
481
+ if (!recipient || !isAddress(recipient)) {
482
+ return null
483
+ }
484
+ return encodeAbiParameters(abis.feeDeliveryStruct, [
485
+ [recipient, feeTypeSettings, limit, multiplier],
486
+ ])
487
+ }
488
+
489
+ /**
490
+ * Calculates the destination data param from the recipient, bridge pathway, asset in, destination router, fee director struct encoded, asset link, should deliver, and unwrap
491
+ * @param recipient - the recipient
492
+ * @param bridgePathway - the bridge pathway
493
+ * @param assetIn - the asset in to bridge
494
+ * @param destinationRouter - the destination router
495
+ * @param feeDirectorStructEncoded - the fee director struct encoded
496
+ * @param assetLink - the asset link
497
+ * @param shouldDeliver - whether to deliver the costs
498
+ * @param unwrap - whether to unwrap
499
+ * @returns the destination data param
500
+ */
501
+ export const destinationDataParam = ({
502
+ recipient,
503
+ bridgePathway,
504
+ assetIn,
505
+ destinationRouter,
506
+ feeDirectorStructEncoded,
507
+ assetLink,
508
+ shouldDeliver,
509
+ unwrap,
510
+ }: {
511
+ recipient: Hex | null
512
+ bridgePathway: Pathway | null
513
+ assetIn: Token | null
514
+ destinationRouter: Hex | null
515
+ feeDirectorStructEncoded: Hex | null
516
+ assetLink: TokenBridgeInfo | null
517
+ shouldDeliver: boolean
518
+ unwrap: boolean
519
+ }) => {
520
+ // const recipient = input.recipient.value
521
+ if (!recipient) {
522
+ return null
523
+ }
524
+ if (!bridgePathway || !assetIn) {
525
+ return null
526
+ }
527
+ if (!destinationRouter) {
528
+ console.log('no destination router')
529
+ return null
530
+ }
531
+ if (bridgePathway.requiresDelivery && !feeDirectorStructEncoded) {
532
+ console.log('no fee director struct encoded')
533
+ return null
534
+ }
535
+ if (!assetLink) {
536
+ console.log('no asset link')
537
+ return null
538
+ }
539
+ if (bridgePathway.requiresDelivery) {
540
+ // going from home to foreign
541
+ if (!shouldDeliver) {
542
+ // act like a regular bridge
543
+ return recipient
544
+ }
545
+ // going from foreign to home
546
+ if (feeDirectorStructEncoded) {
547
+ return concatHex([destinationRouter, feeDirectorStructEncoded])
548
+ }
549
+ return recipient
550
+ }
551
+ if (!unwrap) {
552
+ return recipient
553
+ }
554
+ // unwrap wpls->pls
555
+ return concatHex([destinationRouter, recipient])
556
+ }
557
+
558
+ /**
559
+ * Converts a desired excess compensation basis point value into a percentage as an integer, with the denominator assumed to be 1e18
560
+ * @param desiredExcessCompensationBasisPoints - the desired excess compensation basis points
561
+ * @returns the reasonable percent on top of gas fee
562
+ */
563
+ export const reasonablePercentOnTopOfGasFee = ({
564
+ desiredExcessCompensationBasisPoints,
565
+ }: {
566
+ desiredExcessCompensationBasisPoints: bigint
567
+ }) => {
568
+ return (desiredExcessCompensationBasisPoints * (oneEther / basisPoints))
569
+ }
570
+
571
+ /**
572
+ * Calculates the desired compensation ratio from the desired excess compensation basis points
573
+ * @param desiredExcessCompensationBasisPoints - the desired excess compensation basis points
574
+ * @returns the desired compensation ratio
575
+ */
576
+ export const desiredCompensationRatio = ({
577
+ desiredExcessCompensationBasisPoints,
578
+ }: {
579
+ desiredExcessCompensationBasisPoints: bigint
580
+ }) => {
581
+ return oneEther + (desiredExcessCompensationBasisPoints * oneEther) / basisPoints
582
+ }
583
+
584
+ /**
585
+ * Calculates the available compensation maximum from the amount after bridge fee, percent fee, fee type, fixed fee, and limit
586
+ * @param amountAfterBridgeFee - the amount after bridge fee
587
+ * @param percentFee - the percent fee
588
+ * @param feeType - the fee type
589
+ * @param fixedFee - the fixed fee
590
+ * @param limit - the limit
591
+ * @returns the available compensation maximum
592
+ */
593
+ export const availableCompensationMaximum = ({
594
+ amountAfterBridgeFee,
595
+ percentFee,
596
+ feeType,
597
+ fixedFee,
598
+ limit,
599
+ }: {
600
+ amountAfterBridgeFee: bigint | null
601
+ percentFee: bigint | null
602
+ feeType: FeeType
603
+ fixedFee: bigint | null
604
+ limit: bigint
605
+ }) => {
606
+ if (feeType === FeeType.PERCENT) {
607
+ if (amountAfterBridgeFee === null) return null
608
+ return (amountAfterBridgeFee * (percentFee ?? 0n)) / oneEther
609
+ } else if (feeType === FeeType.GAS_TIP) {
610
+ return limit
611
+ } else if (feeType === FeeType.FIXED) {
612
+ return fixedFee ?? 0n
613
+ }
614
+ return 0n
615
+ }
616
+
617
+ /**
618
+ * Calculates the transaction inputs from the bridge pathway, asset in, recipient, account, asset link, destination data param, amount to bridge, fee director struct encoded, and should deliver
619
+ * @param bridgePathway - the bridge pathway to use
620
+ * @param assetIn - the asset in to bridge
621
+ * @param recipient - the recipient of the bridge
622
+ * @param account - the account to bridge from
623
+ * @param assetLink - the asset link to use
624
+ * @param destinationDataParam - the destination data param to use
625
+ * @param amountToBridge - the amount to bridge
626
+ * @param feeDirectorStructEncoded - the fee director struct encoded to use
627
+ * @param shouldDeliver - whether to deliver the tokens to the recipient
628
+ * @returns the transaction inputs
629
+ */
630
+ export const transactionInputs = ({
631
+ bridgePathway,
632
+ assetIn,
633
+ recipient,
634
+ account,
635
+ assetLink,
636
+ destinationDataParam,
637
+ amountToBridge,
638
+ feeDirectorStructEncoded,
639
+ shouldDeliver,
640
+ }: {
641
+ bridgePathway: Pathway | null
642
+ assetIn: Token | null
643
+ recipient: Hex | null
644
+ account: Hex | null
645
+ assetLink: TokenBridgeInfo | null
646
+ destinationDataParam: Hex | null
647
+ amountToBridge: bigint
648
+ feeDirectorStructEncoded: Hex | null
649
+ shouldDeliver: boolean
650
+ }) => {
651
+ if (!bridgePathway) {
652
+ console.log('no bridge pathway')
653
+ return null
654
+ }
655
+ // check that recipient is valid
656
+ if (
657
+ !recipient ||
658
+ !isAddress(recipient) ||
659
+ account === zeroAddress
660
+ ) {
661
+ console.log('no recipient')
662
+ return null
663
+ }
664
+ // check that wallet account is valid
665
+ if (
666
+ !account ||
667
+ !isAddress(account) ||
668
+ account === zeroAddress
669
+ ) {
670
+ console.log('no account')
671
+ return null
672
+ }
673
+ // check that asset in is valid
674
+ if (!assetIn) {
675
+ console.log('no asset in')
676
+ return null
677
+ }
678
+ // check that asset link is valid
679
+ if (!assetLink) {
680
+ console.log('no asset link')
681
+ return null
682
+ }
683
+ let value = 0n
684
+ // we are moving "from" this side, so we need to call a function on the "from" address
685
+ // only relevant for the relayTokens(AndCall) pathway outside of native tokens
686
+ let toAddress = bridgePathway.from
687
+ let data = '0x' as Hex
688
+ const inputIsBridgeToken = interactingWithBridgeToken({
689
+ assetLink,
690
+ assetInAddress: assetIn.address,
691
+ })
692
+ if (inputIsBridgeToken) {
693
+ // when interacting with a bridged token, we need to call the token address directly
694
+ toAddress = assetIn.address as Hex
695
+ value = 0n
696
+ // if we want delivery of the tokens (going from home to foreign) then we need to have the foreign data param
697
+ // and it needs to start with the destination router
698
+ if (!destinationDataParam) {
699
+ return null
700
+ }
701
+ data = bridgePathway.usesExtraParam
702
+ ? encodeFunctionData({
703
+ abi: abis.erc677ExtraInput,
704
+ functionName: 'transferAndCall',
705
+ args: [
706
+ bridgePathway.from,
707
+ amountToBridge,
708
+ destinationDataParam,
709
+ account,
710
+ ],
711
+ })
712
+ : encodeFunctionData({
713
+ abi: abis.erc677,
714
+ functionName: 'transferAndCall',
715
+ args: [bridgePathway.from, amountToBridge, destinationDataParam],
716
+ })
717
+ } else if (assetIn.address === zeroAddress) {
718
+ value = amountToBridge
719
+ toAddress = bridgePathway.nativeRouter
720
+ if (bridgePathway.feeManager === 'from' && shouldDeliver) {
721
+ // transferring native to foreign
722
+ if (!feeDirectorStructEncoded) return null
723
+ if (!bridgePathway.destinationRouter) return null
724
+ data = bridgePathway.usesExtraParam
725
+ ? encodeFunctionData({
726
+ abi: abis.nativeRouterExtraInput,
727
+ functionName: 'relayTokensAndCall',
728
+ args: [
729
+ bridgePathway.destinationRouter,
730
+ feeDirectorStructEncoded,
731
+ account,
732
+ ],
733
+ })
734
+ : encodeFunctionData({
735
+ abi: abis.nativeRouter,
736
+ functionName: 'relayTokensAndCall',
737
+ args: [bridgePathway.destinationRouter, feeDirectorStructEncoded],
738
+ })
739
+ } else {
740
+ // delivery always occurs when moving from foreign to home
741
+ data = bridgePathway.usesExtraParam
742
+ ? encodeFunctionData({
743
+ abi: abis.nativeRouterExtraInput,
744
+ functionName: 'wrapAndRelayTokens',
745
+ args: [recipient, account],
746
+ })
747
+ : encodeFunctionData({
748
+ abi: abis.nativeRouter,
749
+ functionName: 'wrapAndRelayTokens',
750
+ args: [recipient],
751
+ })
752
+ }
753
+ } else {
754
+ // tokens native to this side, entering the bridge
755
+ if (shouldDeliver && bridgePathway.requiresDelivery) {
756
+ if (!feeDirectorStructEncoded) return null
757
+ if (!bridgePathway.destinationRouter) return null
758
+ data = bridgePathway.usesExtraParam
759
+ ? encodeFunctionData({
760
+ abi: abis.inputBridgeExtraInput,
761
+ functionName: 'relayTokensAndCall',
762
+ args: [
763
+ assetIn.address as Hex,
764
+ bridgePathway.destinationRouter,
765
+ amountToBridge,
766
+ feeDirectorStructEncoded,
767
+ account,
768
+ ],
769
+ })
770
+ : encodeFunctionData({
771
+ abi: abis.inputBridge,
772
+ functionName: 'relayTokensAndCall',
773
+ args: [
774
+ assetIn.address as Hex,
775
+ bridgePathway.destinationRouter,
776
+ amountToBridge,
777
+ feeDirectorStructEncoded,
778
+ ],
779
+ })
780
+ } else {
781
+ data = bridgePathway.usesExtraParam
782
+ ? encodeFunctionData({
783
+ abi: abis.inputBridgeExtraInput,
784
+ functionName: 'relayTokens',
785
+ args: [
786
+ assetIn.address as Hex,
787
+ recipient,
788
+ amountToBridge,
789
+ account,
790
+ ],
791
+ })
792
+ : encodeFunctionData({
793
+ abi: abis.inputBridge,
794
+ functionName: 'relayTokens',
795
+ args: [assetIn.address as Hex, recipient, amountToBridge],
796
+ })
797
+ }
798
+ }
799
+ return {
800
+ to: toAddress,
801
+ value,
802
+ data,
803
+ }
804
+ }
805
+
806
+ /**
807
+ * Calculates the asset out key from the bridge key path, asset in address, and unwrap
808
+ * @param bridgeKeyPath - the bridge key path
809
+ * @param assetInAddress - the asset in address
810
+ * @param unwrap - whether to unwrap
811
+ * @returns the asset out key
812
+ */
813
+ export const assetOutKey = ({
814
+ bridgeKeyPath,
815
+ assetInAddress,
816
+ unwrap,
817
+ }: {
818
+ bridgeKeyPath: string
819
+ assetInAddress?: Hex | null
820
+ unwrap: boolean
821
+ }) => {
822
+ if (!bridgeKeyPath || !assetInAddress) return null
823
+ return `${bridgeKeyPath}/${unwrap ? 'native' : 'erc20'}/${assetInAddress.toLowerCase()}`
824
+ }
825
+
826
+ /**
827
+ * Returns the asset out from the asset in address, assets out, bridge key path, and unwrap
828
+ * @param assetInAddress - the asset in address
829
+ * @param assetsOut - the assets out
830
+ * @param bridgeKeyPath - the bridge key path
831
+ * @param unwrap - whether to unwrap
832
+ * @returns the asset out
833
+ */
834
+ export const assetOut = ({
835
+ assetInAddress,
836
+ assetsOut,
837
+ bridgeKeyPath,
838
+ unwrap,
839
+ }: {
840
+ assetInAddress: Hex | null
841
+ assetsOut: Map<string, Token>
842
+ bridgeKeyPath: string
843
+ unwrap: boolean
844
+ }) => {
845
+ if (!assetInAddress) return null
846
+ const key = assetOutKey({
847
+ bridgeKeyPath,
848
+ assetInAddress,
849
+ unwrap,
850
+ })
851
+ if (!key) return null
852
+ return assetsOut.get(key) ?? null
853
+ }