@gibs/bridge-sdk 1.9.1 → 1.12.0

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