@gibs/bridge-sdk 1.18.0 → 1.20.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.
Files changed (120) hide show
  1. package/README.md +33 -0
  2. package/dist/abis.js +0 -2
  3. package/dist/bridge-limits.js +0 -38
  4. package/dist/chain-info.js +0 -116
  5. package/dist/chain-names.js +0 -151
  6. package/dist/chains.js +0 -198
  7. package/dist/cjs/abis.js +0 -2
  8. package/dist/cjs/bridge-limits.js +0 -38
  9. package/dist/cjs/chain-info.js +0 -116
  10. package/dist/cjs/chain-names.js +0 -151
  11. package/dist/cjs/chains.js +0 -198
  12. package/dist/cjs/claims.js +0 -60
  13. package/dist/cjs/config.js +1 -208
  14. package/dist/cjs/consolidated-quote.js +2 -464
  15. package/dist/cjs/destination-calldata.js +0 -71
  16. package/dist/cjs/ecosystems.js +0 -183
  17. package/dist/cjs/execution.js +0 -92
  18. package/dist/cjs/fee-type.js +0 -1
  19. package/dist/cjs/hyperliquid-execution.js +0 -98
  20. package/dist/cjs/image-links.js +0 -108
  21. package/dist/cjs/lifi-execution-guard.js +65 -172
  22. package/dist/cjs/near-intents-conformance.js +0 -110
  23. package/dist/cjs/near-intents-route.d.ts +13 -0
  24. package/dist/cjs/near-intents-route.js +7 -140
  25. package/dist/cjs/near-intents.js +0 -562
  26. package/dist/cjs/origin-deposit.js +0 -56
  27. package/dist/cjs/pre-quote.js +0 -80
  28. package/dist/cjs/prices.js +0 -113
  29. package/dist/cjs/providers.js +0 -83
  30. package/dist/cjs/quote-fees.js +0 -80
  31. package/dist/cjs/referral.js +0 -75
  32. package/dist/cjs/relay-currencies.js +0 -31
  33. package/dist/cjs/relay-depository.js +52 -77
  34. package/dist/cjs/relay-quote.js +0 -394
  35. package/dist/cjs/route-steps.js +0 -100
  36. package/dist/cjs/routing/amounts.js +0 -83
  37. package/dist/cjs/routing/candidate-route.d.ts +46 -1
  38. package/dist/cjs/routing/candidate-route.js +12 -40
  39. package/dist/cjs/routing/candidate.js +0 -46
  40. package/dist/cjs/routing/carrier-provider-key.js +0 -27
  41. package/dist/cjs/routing/carriers/omnibridge.js +0 -120
  42. package/dist/cjs/routing/carriers/pulsex-paths.js +0 -57
  43. package/dist/cjs/routing/carriers/pulsex-split.js +0 -92
  44. package/dist/cjs/routing/carriers/pulsex.js +0 -279
  45. package/dist/cjs/routing/carriers/wrap.js +0 -57
  46. package/dist/cjs/routing/composed-route-quality.js +0 -95
  47. package/dist/cjs/routing/entry-chain-anchor.js +0 -27
  48. package/dist/cjs/routing/format.js +0 -50
  49. package/dist/cjs/routing/index.d.ts +1 -1
  50. package/dist/cjs/routing/index.js +3 -30
  51. package/dist/cjs/routing/producers.js +0 -854
  52. package/dist/cjs/routing/providers.js +0 -27
  53. package/dist/cjs/routing/search/compose.js +0 -56
  54. package/dist/cjs/routing/search/graph.js +0 -364
  55. package/dist/cjs/routing/search/plan-route-data.js +5 -510
  56. package/dist/cjs/routing/search/score.js +0 -344
  57. package/dist/cjs/routing/swap-transactions.js +0 -74
  58. package/dist/cjs/routing/usd-value.js +0 -12
  59. package/dist/cjs/settings.js +1 -456
  60. package/dist/cjs/swap-venues.js +0 -17
  61. package/dist/cjs/ton-connect.js +0 -82
  62. package/dist/cjs/ton-execution.js +0 -6
  63. package/dist/cjs/ton.js +0 -42
  64. package/dist/cjs/tron-execution.js +0 -145
  65. package/dist/cjs/types.d.ts +8 -0
  66. package/dist/claims.js +0 -60
  67. package/dist/config.js +1 -211
  68. package/dist/consolidated-quote.js +2 -464
  69. package/dist/destination-calldata.js +0 -71
  70. package/dist/ecosystems.js +0 -183
  71. package/dist/execution.js +0 -92
  72. package/dist/fee-type.js +0 -2
  73. package/dist/hyperliquid-execution.js +0 -98
  74. package/dist/image-links.js +0 -108
  75. package/dist/lifi-execution-guard.js +65 -172
  76. package/dist/near-intents-conformance.js +0 -110
  77. package/dist/near-intents-route.d.ts +13 -0
  78. package/dist/near-intents-route.js +5 -139
  79. package/dist/near-intents.js +0 -562
  80. package/dist/origin-deposit.js +0 -56
  81. package/dist/pre-quote.js +0 -80
  82. package/dist/prices.js +0 -113
  83. package/dist/providers.js +0 -83
  84. package/dist/quote-fees.js +0 -80
  85. package/dist/referral.js +0 -75
  86. package/dist/relay-currencies.js +0 -31
  87. package/dist/relay-depository.js +52 -77
  88. package/dist/relay-quote.js +0 -394
  89. package/dist/route-steps.js +0 -100
  90. package/dist/routing/amounts.js +0 -83
  91. package/dist/routing/candidate-route.d.ts +46 -1
  92. package/dist/routing/candidate-route.js +10 -39
  93. package/dist/routing/candidate.js +0 -46
  94. package/dist/routing/carrier-provider-key.js +0 -27
  95. package/dist/routing/carriers/omnibridge.js +0 -120
  96. package/dist/routing/carriers/pulsex-paths.js +0 -57
  97. package/dist/routing/carriers/pulsex-split.js +0 -92
  98. package/dist/routing/carriers/pulsex.js +0 -279
  99. package/dist/routing/carriers/wrap.js +0 -57
  100. package/dist/routing/composed-route-quality.js +0 -95
  101. package/dist/routing/entry-chain-anchor.js +0 -27
  102. package/dist/routing/format.js +0 -50
  103. package/dist/routing/index.d.ts +1 -1
  104. package/dist/routing/index.js +1 -29
  105. package/dist/routing/producers.js +0 -854
  106. package/dist/routing/providers.js +0 -27
  107. package/dist/routing/search/compose.js +0 -56
  108. package/dist/routing/search/graph.js +0 -364
  109. package/dist/routing/search/plan-route-data.js +6 -511
  110. package/dist/routing/search/score.js +0 -344
  111. package/dist/routing/swap-transactions.js +0 -74
  112. package/dist/routing/usd-value.js +0 -12
  113. package/dist/settings.js +1 -456
  114. package/dist/swap-venues.js +0 -17
  115. package/dist/ton-connect.js +0 -82
  116. package/dist/ton-execution.js +0 -6
  117. package/dist/ton.js +0 -42
  118. package/dist/tron-execution.js +0 -145
  119. package/dist/types.d.ts +8 -0
  120. package/package.json +3 -3
@@ -1,61 +1,16 @@
1
1
  import { buildUrl } from '@gibs/common/url';
2
2
  import { parseSignature } from 'viem';
3
3
  import { relayApiBaseUrl } from './relay-quote.js';
4
- /**
5
- * Executing a Hyperliquid deposit, as pure data.
6
- *
7
- * Hyperliquid is the one origin whose deposit is never broadcast to a chain.
8
- * The user signs a typed-data ACTION and that signed action is posted to
9
- * Hyperliquid's own exchange API; Relay then observes the transfer and fills the
10
- * route. Two details make this impossible to derive from the quote alone, and
11
- * both are encoded here rather than rediscovered at a call site:
12
- *
13
- * 1. Relay's quote supplies `eip712Types`, `eip712PrimaryType` and the action,
14
- * but NOT the signing domain. The domain is fixed by Hyperliquid and is
15
- * reconstructed by {@link buildHyperliquidTypedData}.
16
- * 2. Hyperliquid wants the signature split into `r`/`s`/`v` components, not the
17
- * concatenated hex string a wallet returns.
18
- *
19
- * Kept free of transport so it is fully testable: nothing here signs, fetches,
20
- * or reads a clock. The caller supplies the signature and performs the request.
21
- *
22
- * The shape mirrors Relay's own client, which is the only reference
23
- * implementation of this exchange — their public documentation covers the
24
- * generic `signature` step but not this action-bearing `transaction` step.
25
- */
26
- /** Where a signed Hyperliquid action is submitted. Hyperliquid's API, not Relay's. */
27
4
  export const hyperliquidExchangeUrl = 'https://api.hyperliquid.xyz/exchange';
28
- /** The signing domain Hyperliquid requires. Fixed; never supplied by the quote. */
29
5
  export const hyperliquidDomainName = 'HyperliquidSignTransaction';
30
- /** The signing domain's version. Fixed alongside {@link hyperliquidDomainName}. */
31
6
  export const hyperliquidDomainVersion = '1';
32
- /**
33
- * The domain's `verifyingContract`. Hyperliquid actions are verified off-chain,
34
- * so no contract is involved and the field is the all-zero address.
35
- */
36
7
  export const hyperliquidVerifyingContract = '0x0000000000000000000000000000000000000000';
37
- /** The standard typed-data domain type, which the action's type table must include. */
38
8
  const eip712DomainType = [
39
9
  { name: 'name', type: 'string' },
40
10
  { name: 'version', type: 'string' },
41
11
  { name: 'chainId', type: 'uint256' },
42
12
  { name: 'verifyingContract', type: 'address' },
43
13
  ];
44
- /**
45
- * Builds the typed-data payload for a Hyperliquid deposit.
46
- *
47
- * The message is the action's parameters plus the action `type` and a
48
- * `signatureChainId`; the latter is the signing chain in hex and MUST agree
49
- * with `domain.chainId`, because Hyperliquid recovers the signer using both.
50
- * They are derived from the single `signatureChainId` argument so they cannot
51
- * disagree.
52
- *
53
- * @param deposit - the parsed Hyperliquid origin deposit
54
- * @param options.signatureChainId - the chain id the connected wallet signs
55
- * under. Not the Relay origin chain id: it identifies the signing domain, and
56
- * Relay's own client uses the wallet's active chain here.
57
- * @returns the payload to sign, whose `message` doubles as the submitted action
58
- */
59
14
  export const buildHyperliquidTypedData = (deposit, { signatureChainId }) => ({
60
15
  domain: {
61
16
  name: hyperliquidDomainName,
@@ -74,67 +29,24 @@ export const buildHyperliquidTypedData = (deposit, { signatureChainId }) => ({
74
29
  signatureChainId: `0x${signatureChainId.toString(16)}`,
75
30
  },
76
31
  });
77
- /**
78
- * Builds the exchange request for an action the user has signed.
79
- *
80
- * The nonce is read back out of the signed message rather than passed in: it is
81
- * covered by the signature, so any independently supplied value could disagree
82
- * with what was signed and be rejected.
83
- *
84
- * @param options.typedData - the payload that was signed
85
- * @param options.signature - the wallet's signature over it
86
- * @returns the request body, or null when the signed action carries no usable nonce
87
- */
88
32
  export const buildHyperliquidExchangeRequest = ({ typedData, signature, }) => {
89
- // Hyperliquid names it `nonce`; the older action shapes name it `time`.
90
33
  const rawNonce = typedData.message.nonce ?? typedData.message.time;
91
34
  if (typeof rawNonce !== 'number' && typeof rawNonce !== 'bigint') {
92
35
  return null;
93
36
  }
94
37
  const { r, s, v, yParity } = parseSignature(signature);
95
38
  return {
96
- // The exchange wants the 27/28 form. A signature whose final byte is the
97
- // PARITY form (0 or 1) — which some hardware wallets and smart-account flows
98
- // produce — parses with `v` absent and the parity carried separately, so
99
- // reading `v` alone and defaulting would send recovery value 0: not a value
100
- // the exchange accepts, and the deposit dies for those wallets only. The
101
- // parity is the same fact in the other encoding, so shift it rather than
102
- // guess.
103
39
  signature: { r, s, v: v === undefined ? yParity + 27 : Number(v) },
104
40
  nonce: Number(rawNonce),
105
41
  action: typedData.message,
106
42
  };
107
43
  };
108
- /**
109
- * Whether an exchange response reports success. Hyperliquid answers with HTTP
110
- * 200 even for a rejected action, so the body's own status is the only reliable
111
- * signal — treating the status code as the outcome would report a failed
112
- * transfer as a completed one.
113
- *
114
- * @param payload - the parsed response body
115
- * @returns true only when the body explicitly reports success
116
- */
117
44
  export const isHyperliquidExchangeSuccess = (payload) => {
118
45
  if (typeof payload !== 'object' || payload === null) {
119
46
  return false;
120
47
  }
121
48
  return payload.status === 'ok';
122
49
  };
123
- /**
124
- * The typed-data payload for the authorization that must be completed BEFORE
125
- * the action is submitted.
126
- *
127
- * Relay builds the authorization against a chain it picks when quoting, but the
128
- * signature is produced by whichever chain the wallet is actually on. Both the
129
- * domain here and `signatureChainId` in {@link buildHyperliquidAuthorizationRequest}
130
- * are therefore overridden with the active wallet chain; leaving Relay's value in
131
- * place makes the recovered signer disagree with the submitted one and the
132
- * authorization is rejected.
133
- *
134
- * @param authorization - the authorization carried by the deposit
135
- * @param options.signatureChainId - the chain id the connected wallet signs under
136
- * @returns the payload to sign
137
- */
138
50
  export const buildHyperliquidAuthorizationTypedData = (authorization, { signatureChainId }) => ({
139
51
  domain: {
140
52
  ...authorization.sign.domain,
@@ -144,16 +56,6 @@ export const buildHyperliquidAuthorizationTypedData = (authorization, { signatur
144
56
  primaryType: authorization.sign.primaryType,
145
57
  message: authorization.sign.value,
146
58
  });
147
- /**
148
- * Builds the authorization submission for a signed authorization.
149
- *
150
- * @param options.authorization - the authorization that was signed
151
- * @param options.signature - the wallet's signature over its typed data
152
- * @param options.signatureChainId - the chain id the wallet signed under, which
153
- * replaces the value Relay quoted so the body agrees with the signature
154
- * @param options.baseUrl - Relay's API root; the step's endpoint is relative
155
- * @returns the request to perform, or null when the endpoint is not a usable path
156
- */
157
59
  export const buildHyperliquidAuthorizationRequest = ({ authorization, signature, signatureChainId, baseUrl = relayApiBaseUrl, }) => {
158
60
  const { endpoint, method, body } = authorization.post;
159
61
  if (!endpoint.startsWith('/')) {
@@ -2,96 +2,25 @@ import { getAddress, zeroAddress } from 'viem';
2
2
  import { depositAddressChainIds } from './chain-names.js';
3
3
  import { isNativeAsset } from './ecosystems.js';
4
4
  let imageRoot = 'https://gib.show';
5
- /**
6
- * Sets the image root for the bridge
7
- * @param root - the root
8
- */
9
5
  export const setImageRoot = (root) => {
10
6
  imageRoot = root;
11
7
  };
12
- /**
13
- * Returns the image root for the bridge
14
- * @returns the image root
15
- */
16
8
  export const getImageRoot = () => imageRoot;
17
- /**
18
- * Returns the list image for the given path
19
- * @param path - the path
20
- * @returns the list image
21
- */
22
9
  export const list = (path) => {
23
10
  return `${imageRoot}/list${path}`;
24
11
  };
25
- /**
26
- * Returns the network image for the given chain id
27
- * @param chainId - the chain id
28
- * @returns the network image
29
- */
30
12
  export const network = (chainId) => `${imageRoot}/image/${Number(chainId)}`;
31
- /**
32
- * gib.show's own key for a chain this package can only name by a LOCAL,
33
- * INVENTED identifier — a pay-by-hand origin (see `depositAddressChainIds`)
34
- * rather than a real chain id gib.show's numeric endpoint recognizes.
35
- * `network(chainId)` 404s for one of these, and the browser draws that 404 as
36
- * a broken image on every chain badge and route mark drawn through it.
37
- *
38
- * Every route producer that draws a chain badge for a token needs this, not
39
- * only the deposit-address ones: a route can START on a deposit-address chain
40
- * and cross through ordinary Ethereum-Virtual-Machine chains after, so the
41
- * predicate has to run on every chain id a route touches, not only the one
42
- * the reader picked. Kept beside `network` rather than in the client that also
43
- * resolves Relay's pseudo chains (`@gibs/bridge-client/image`'s
44
- * `chainLogoUrl`) because that client sits ABOVE this package — it imports
45
- * FROM `bridge-sdk` — so this package importing back from it would be a
46
- * cycle. `chainLogoUrl` still adds a Relay-icon fallback for chains gib.show
47
- * does not carry at ALL (Eclipse, Hyperliquid); this table is only the
48
- * chains gib.show DOES carry, under a key other than their numeric id.
49
- *
50
- * EXPORTED, and this is the ONLY place a pay-by-hand chain's gib.show key is
51
- * declared. `@gibs/bridge-client`'s `image.ts` used to hard-code its own copy
52
- * of the same `zcash → 'bip122-133'` entry; it now spreads this map into its
53
- * own icon table instead, because the dependency runs one way — the client
54
- * already imports from this package — so there was never a cycle stopping it.
55
- */
56
13
  export const pseudoChainGibShowIdentifierByChain = {
57
14
  zcash: 'bip122-133',
58
15
  };
59
- /** {@link pseudoChainGibShowIdentifierByChain}, keyed by chain id for lookup. */
60
16
  export const pseudoChainGibShowIdentifier = Object.fromEntries(Object.keys(depositAddressChainIds).map((chain) => [
61
17
  depositAddressChainIds[chain],
62
18
  pseudoChainGibShowIdentifierByChain[chain],
63
19
  ]));
64
- /**
65
- * The network image for a chain id, honouring a pseudo chain's own gib.show
66
- * key when its numeric id is not one gib.show's `/image/<id>` endpoint knows.
67
- *
68
- * @param chainId - the chain id, a deposit-address chain's local identifier included
69
- * @returns a working network/chain-badge image url
70
- */
71
20
  export const networkOrPseudo = (chainId) => {
72
21
  const identifier = pseudoChainGibShowIdentifier[chainId];
73
22
  return identifier !== undefined ? `${imageRoot}/image/${identifier}` : network(chainId);
74
23
  };
75
- /**
76
- * Returns the image url for the given token info.
77
- *
78
- * The gas token is asked for by BOTH of its keys, because the service keys it
79
- * two ways and each chain carries only one of them. `<chain>/<zero address>` is
80
- * a dedicated picture — Ethereum's ether diamond, PulseChain's mark — and
81
- * Binance Smart Chain has none, so asking for it there returns a 404 the browser
82
- * draws as a broken image. The empty-address form `<chain>/` is the chain's own
83
- * mark, which every chain has.
84
- *
85
- * The order is NOT interchangeable. The service serves the first source that
86
- * resolves, so a chain with a dedicated picture keeps it; reversed, Ethereum
87
- * would show the network logo where the ether logo belongs (the two are
88
- * genuinely different files). The pair is for the gas token alone: pairing an
89
- * ordinary contract address with the chain mark would hide a missing token logo
90
- * behind the network's, showing the wrong token rather than an honest fallback.
91
- *
92
- * @param t - the token info
93
- * @returns the image url
94
- */
95
24
  export const image = (t) => {
96
25
  if (t.logoURI)
97
26
  return t.logoURI;
@@ -100,43 +29,6 @@ export const image = (t) => {
100
29
  }
101
30
  return `${network(t.chainId)}/${getAddress(t.address)}`;
102
31
  };
103
- /**
104
- * Whether `address` is a real Ethereum-Virtual-Machine address {@link image}
105
- * can ask the service about — the zero address included, since that is
106
- * {@link isNativeAsset}'s own case and {@link image} handles it without
107
- * `getAddress` ever running.
108
- *
109
- * @param address - the address to check
110
- * @returns true when `getAddress` can checksum it without throwing
111
- */
112
32
  const isResolvableEvmAddress = (address) => /^0x[0-9a-fA-F]{40}$/.test(address);
113
- /**
114
- * {@link image}, but falling back to the token's own CHAIN mark rather than
115
- * throwing or asking the service for a picture that was never going to exist,
116
- * when the token carries no address a picture can be resolved from yet.
117
- *
118
- * WHY THIS EXISTS SEPARATELY FROM `image`. A route producer can reach the
119
- * moment it draws a DELIVERED token's picture before that token's exact
120
- * on-chain address is known — a not-yet-bridged token's `assetOutAddress` is
121
- * documented to arrive `null` (see the repository's own "Not-Yet-Bridged
122
- * Tokens" gotcha), and a deferred crossing's landing token is exactly this
123
- * case: the reader has not yet signed the leg that would settle it. `image`
124
- * either throws (`getAddress` refuses a malformed or empty string) or, for a
125
- * caller that swallows the throw, silently draws nothing — the same "blank
126
- * disc" defect the carrier marks were fixed for, one token lower. The chain's
127
- * own mark is a real, recognisable picture that is honest about what is
128
- * known: THIS chain, a token not yet resolved on it — the same trade
129
- * `trackerView.ts`'s `depositAddressChainLogoFallback` already makes for a
130
- * pay-by-hand ORIGIN with no address of its own.
131
- *
132
- * @param t - the token to draw
133
- * @returns the token's own picture, or its chain's mark when the token's
134
- * address cannot be resolved into one
135
- */
136
33
  export const tokenImageOrChainFallback = (t) => isResolvableEvmAddress(t.address) ? image(t) : networkOrPseudo(t.chainId);
137
- /**
138
- * Returns a url that will lookup all sources for the given array
139
- * @param sources - the sources
140
- * @returns the images
141
- */
142
34
  export const images = (sources) => `${imageRoot}/image/?${sources.map((s) => `i=${s}`).join('&')}`;
@@ -1,14 +1,4 @@
1
1
  import { decodeAbiParameters, zeroAddress } from 'viem';
2
- /**
3
- * Thrown by {@link verifyLifiEvmExecution} instead of returning a deposit a
4
- * wallet could sign.
5
- *
6
- * NAMED AND TYPED SO A REFUSAL IS NEVER A SILENT DROP. Every caller that
7
- * catches this can read `refusal.reason` and show, or log, exactly which
8
- * check failed — the same discipline `@gibs/quotes`'s `ProviderQuoteError`
9
- * applies to a provider declining a quote, applied here to a provider's
10
- * ANSWER disagreeing with itself.
11
- */
12
2
  export class LifiExecutionRefusedError extends Error {
13
3
  refusal;
14
4
  constructor(refusal) {
@@ -20,102 +10,72 @@ export class LifiExecutionRefusedError extends Error {
20
10
  const refuse = (reason, detail) => {
21
11
  throw new LifiExecutionRefusedError({ reason, detail });
22
12
  };
23
- /**
24
- * LI.FI's Diamond entryway contract address, by chain id.
25
- *
26
- * SOURCE. `lifinance/contracts` (https://github.com/lifinance/contracts),
27
- * commit `025989955bb373739737ee78ddff01620638ae3b` (2026-09-23): the
28
- * `LiFiDiamond` address in `deployments/<network>.json`, matched to its
29
- * chain id in `config/networks.json`, for every network whose `status` is
30
- * `"active"` and `"type"` is `"mainnet"`. LI.FI's own documentation
31
- * (https://docs.li.fi/introduction/lifi-architecture/smart-contract-addresses)
32
- * states the address is `0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE` "on most
33
- * supported networks" but differs on some — confirmed here directly against
34
- * the deployment records rather than assumed: 39 of the 65 active mainnet
35
- * networks use a DIFFERENT address, almost all of them newer or lower-volume
36
- * chains (0G, Abstract, ApeChain, Arbitrum Nova, Berachain, Flare, zkSync
37
- * Era, and more).
38
- *
39
- * DELIBERATELY A FIXED, BAKED-IN TABLE, NEVER A LIVE LOOKUP. LI.FI's own
40
- * `/v1/chains` endpoint carries a `diamondAddress` per chain, and this
41
- * codebase already fetches it for other purposes — but that endpoint is
42
- * reached through the SAME configurable, potentially-compromised host this
43
- * module exists to distrust. Trusting it here would make the whole guard
44
- * circular: a compromised proxy could simply report its own malicious
45
- * address as the "correct" one. This table is real code, reviewed and
46
- * shipped with the application, and can only change through a new release.
47
- *
48
- * UNKNOWN CHAIN, UNKNOWN ADDRESS. A chain id absent from this table refuses
49
- * rather than falling back to the common address — LI.FI adds networks
50
- * continuously, and assuming a newly-added chain shares the common address
51
- * would be exactly the kind of guess this module exists to avoid making.
52
- */
53
13
  export const lifiDiamondAddressByChainId = new Map([
54
- [1, '0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE'], // mainnet
55
- [10, '0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE'], // optimism
56
- [14, '0x198FC70Dfe05E755C81e54bd67Bff3F729344B9b'], // flare
57
- [25, '0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE'], // cronos
58
- [30, '0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE'], // rootstock
59
- [40, '0xa7cd44521903C65915648385E3FE881E49171582'], // telos
60
- [50, '0x055d4612Ec74aD799C6cB4dF72C0Ab8dbDBCBAfa'], // xdc
61
- [56, '0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE'], // bsc
62
- [88, '0x198FC70Dfe05E755C81e54bd67Bff3F729344B9b'], // viction
63
- [100, '0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE'], // gnosis
64
- [122, '0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE'], // fuse
65
- [130, '0x864b314D4C5a0399368609581d3E8933a63b9232'], // unichain
66
- [137, '0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE'], // polygon
67
- [143, '0x026F252016A7C47CDEf1F05a3Fc9E20C92a49C37'], // monad
68
- [146, '0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE'], // sonic
69
- [196, '0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE'], // xlayer
70
- [204, '0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE'], // opbnb
71
- [232, '0xF3B20515d9B193531c48E47c18aF16d1e5d28f9a'], // lens
72
- [252, '0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE'], // fraxtal
73
- [288, '0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE'], // boba
74
- [324, '0x341e94069f53234fE6DabeF707aD424830525715'], // zksync
75
- [480, '0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE'], // worldchain
76
- [747, '0x026F252016A7C47CDEf1F05a3Fc9E20C92a49C37'], // flow
77
- [988, '0x026F252016A7C47CDEf1F05a3Fc9E20C92a49C37'], // stable
78
- [1088, '0x24ca98fB6972F5eE05f0dB00595c7f68D9FaFd68'], // metis
79
- [1135, '0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE'], // lisk
80
- [1329, '0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE'], // sei
81
- [1480, '0x198FC70Dfe05E755C81e54bd67Bff3F729344B9b'], // vana
82
- [1625, '0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE'], // gravity
83
- [1672, '0xFf70F4A1d11995621854F3692acF286d8aCd04b2'], // pharos
84
- [1776, '0xeCeC3970Ca674278DA8D9B1c484ACaF6B20181F5'], // injective
85
- [1868, '0x864b314D4C5a0399368609581d3E8933a63b9232'], // soneium
86
- [2020, '0x452Cf1B8597E6319Cd21abd847312bF17E26d8d1'], // ronin
87
- [2741, '0x4f8C9056bb8A3616693a76922FA35d53C056E5b3'], // abstract
88
- [2818, '0xF7aB42D00D2399f8A4Fba2F15466Be40709fe307'], // morph
89
- [4217, '0x2cAcAE8e22418E65dcf7651c67aEbe6288EB8243'], // tempo
90
- [4326, '0x026F252016A7C47CDEf1F05a3Fc9E20C92a49C37'], // megaeth
91
- [4663, '0xB477751B76CF82d00a686A1232f5fCD772414Af3'], // robinhood
92
- [5000, '0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE'], // mantle
93
- [5031, '0x0bc413CAe89C5b3Ba3AA87FB98dCA23425E1828f'], // somnia
94
- [5042, '0xA4072583658Fae592A3506A42431cb6316a8d40b'], // arc
95
- [5734951, '0x026F252016A7C47CDEf1F05a3Fc9E20C92a49C37'], // jovay
96
- [6900, '0x926c22Dc753E543Cf9CaB75CeEB46ecf865d006a'], // nibiru
97
- [8217, '0x1255d17c1BC2f764d087536410879F2d0D8772fD'], // kaia
98
- [8453, '0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE'], // base
99
- [9745, '0x026F252016A7C47CDEf1F05a3Fc9E20C92a49C37'], // plasma
100
- [13371, '0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE'], // immutablezkevm
101
- [16661, '0x213A83c67E1Fc0334eF684571ABCB820708A6536'], // 0g
102
- [33139, '0x2dea447e7dc6cd2f10b31bF10dCB30F87E838417'], // apechain
103
- [34443, '0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE'], // mode
104
- [42161, '0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE'], // arbitrum
105
- [42170, '0xFf70F4A1d11995621854F3692acF286d8aCd04b2'], // arbitrumnova
106
- [42220, '0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE'], // celo
107
- [42793, '0x977474593c982cFa8b197cAE302e6d01f789435b'], // etherlink
108
- [43111, '0x026F252016A7C47CDEf1F05a3Fc9E20C92a49C37'], // hemi
109
- [43114, '0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE'], // avalanche
110
- [57073, '0x864b314D4C5a0399368609581d3E8933a63b9232'], // ink
111
- [59144, '0xDE1E598b81620773454588B85D6b5D4eEC32573e'], // linea
112
- [60808, '0x452Cf1B8597E6319Cd21abd847312bF17E26d8d1'], // bob
113
- [80094, '0xf909c4Ae16622898b885B89d7F839E0244851c66'], // berachain
114
- [81457, '0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE'], // blast
115
- [98866, '0x6f5C8Bb0C5Fe4ECeAC40EE1C238EaB6bbb29761c'], // plume
116
- [534352, '0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE'], // scroll
117
- [747474, '0xC59fe32C9549e3E8B5dCcdAbC45BD287Bd5bA2bc'], // katana
118
- [999, '0x0a0758d937d1059c356D4714e57F5df0239bce1A'], // hyperevm
14
+ [1, '0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE'],
15
+ [10, '0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE'],
16
+ [14, '0x198FC70Dfe05E755C81e54bd67Bff3F729344B9b'],
17
+ [25, '0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE'],
18
+ [30, '0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE'],
19
+ [40, '0xa7cd44521903C65915648385E3FE881E49171582'],
20
+ [50, '0x055d4612Ec74aD799C6cB4dF72C0Ab8dbDBCBAfa'],
21
+ [56, '0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE'],
22
+ [88, '0x198FC70Dfe05E755C81e54bd67Bff3F729344B9b'],
23
+ [100, '0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE'],
24
+ [122, '0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE'],
25
+ [130, '0x864b314D4C5a0399368609581d3E8933a63b9232'],
26
+ [137, '0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE'],
27
+ [143, '0x026F252016A7C47CDEf1F05a3Fc9E20C92a49C37'],
28
+ [146, '0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE'],
29
+ [196, '0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE'],
30
+ [204, '0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE'],
31
+ [232, '0xF3B20515d9B193531c48E47c18aF16d1e5d28f9a'],
32
+ [252, '0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE'],
33
+ [288, '0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE'],
34
+ [324, '0x341e94069f53234fE6DabeF707aD424830525715'],
35
+ [480, '0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE'],
36
+ [747, '0x026F252016A7C47CDEf1F05a3Fc9E20C92a49C37'],
37
+ [988, '0x026F252016A7C47CDEf1F05a3Fc9E20C92a49C37'],
38
+ [1088, '0x24ca98fB6972F5eE05f0dB00595c7f68D9FaFd68'],
39
+ [1135, '0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE'],
40
+ [1329, '0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE'],
41
+ [1480, '0x198FC70Dfe05E755C81e54bd67Bff3F729344B9b'],
42
+ [1625, '0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE'],
43
+ [1672, '0xFf70F4A1d11995621854F3692acF286d8aCd04b2'],
44
+ [1776, '0xeCeC3970Ca674278DA8D9B1c484ACaF6B20181F5'],
45
+ [1868, '0x864b314D4C5a0399368609581d3E8933a63b9232'],
46
+ [2020, '0x452Cf1B8597E6319Cd21abd847312bF17E26d8d1'],
47
+ [2741, '0x4f8C9056bb8A3616693a76922FA35d53C056E5b3'],
48
+ [2818, '0xF7aB42D00D2399f8A4Fba2F15466Be40709fe307'],
49
+ [4217, '0x2cAcAE8e22418E65dcf7651c67aEbe6288EB8243'],
50
+ [4326, '0x026F252016A7C47CDEf1F05a3Fc9E20C92a49C37'],
51
+ [4663, '0xB477751B76CF82d00a686A1232f5fCD772414Af3'],
52
+ [5000, '0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE'],
53
+ [5031, '0x0bc413CAe89C5b3Ba3AA87FB98dCA23425E1828f'],
54
+ [5042, '0xA4072583658Fae592A3506A42431cb6316a8d40b'],
55
+ [5734951, '0x026F252016A7C47CDEf1F05a3Fc9E20C92a49C37'],
56
+ [6900, '0x926c22Dc753E543Cf9CaB75CeEB46ecf865d006a'],
57
+ [8217, '0x1255d17c1BC2f764d087536410879F2d0D8772fD'],
58
+ [8453, '0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE'],
59
+ [9745, '0x026F252016A7C47CDEf1F05a3Fc9E20C92a49C37'],
60
+ [13371, '0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE'],
61
+ [16661, '0x213A83c67E1Fc0334eF684571ABCB820708A6536'],
62
+ [33139, '0x2dea447e7dc6cd2f10b31bF10dCB30F87E838417'],
63
+ [34443, '0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE'],
64
+ [42161, '0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE'],
65
+ [42170, '0xFf70F4A1d11995621854F3692acF286d8aCd04b2'],
66
+ [42220, '0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE'],
67
+ [42793, '0x977474593c982cFa8b197cAE302e6d01f789435b'],
68
+ [43111, '0x026F252016A7C47CDEf1F05a3Fc9E20C92a49C37'],
69
+ [43114, '0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE'],
70
+ [57073, '0x864b314D4C5a0399368609581d3E8933a63b9232'],
71
+ [59144, '0xDE1E598b81620773454588B85D6b5D4eEC32573e'],
72
+ [60808, '0x452Cf1B8597E6319Cd21abd847312bF17E26d8d1'],
73
+ [80094, '0xf909c4Ae16622898b885B89d7F839E0244851c66'],
74
+ [81457, '0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE'],
75
+ [98866, '0x6f5C8Bb0C5Fe4ECeAC40EE1C238EaB6bbb29761c'],
76
+ [534352, '0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE'],
77
+ [747474, '0xC59fe32C9549e3E8B5dCcdAbC45BD287Bd5bA2bc'],
78
+ [999, '0x0a0758d937d1059c356D4714e57F5df0239bce1A'],
119
79
  ]);
120
80
  const bridgeDataAbiType = {
121
81
  type: 'tuple',
@@ -144,32 +104,14 @@ const swapDataArrayAbiType = {
144
104
  { name: 'requiresDeposit', type: 'bool' },
145
105
  ],
146
106
  };
147
- /** Decodes `BridgeData` and the leading `SwapData` entry, shared by every verified decoder. */
148
107
  const decodeBridgeDataAndLeadingSwap = (encodedTail) => {
149
108
  const [bridgeData, swapData] = decodeAbiParameters([bridgeDataAbiType, swapDataArrayAbiType], encodedTail);
150
- // EVERY VERIFIED SELECTOR IS A `swapAndStartBridgeTokensViaX` FUNCTION,
151
- // whose `containsSourceSwaps` modifier requires a non-empty `SwapData[]`
152
- // on a genuine call. An empty array here — whether from `hasSourceSwaps`
153
- // being forged false or the array itself being emptied — means this
154
- // module cannot identify what was actually pulled from the depositor, so
155
- // it refuses rather than reading past the end of the array.
156
109
  const leadingSwap = swapData[0];
157
110
  if (!bridgeData.hasSourceSwaps || leadingSwap === undefined) {
158
111
  return null;
159
112
  }
160
113
  return { bridgeData, leadingSwap };
161
114
  };
162
- /**
163
- * `swapAndStartBridgeTokensViaAcrossV4((BridgeData),(SwapData[]),(AcrossV4Data))`.
164
- *
165
- * Selector `0x1794958f`, verified against
166
- * `packages/bridge-sdk/src/__fixtures__/lifi/contract-quote-success-eth-to-base-usdc.json`
167
- * (a real `GET /v1/quote` response) — signature and struct layout read from
168
- * `lifinance/contracts/src/Facets/AcrossFacetV4.sol`. `AcrossV4Data` carries
169
- * no native-fee field, so {@link DecodedLifiFacetCall.extraNativeFee} is
170
- * always `0n`. `outputAmount` is Across's own destination-side guarantee —
171
- * confirmed equal to the SAME response's `estimate.toAmountMin`.
172
- */
173
115
  const decodeAcrossV4SwapAndStart = (data) => {
174
116
  const acrossV4DataAbiType = {
175
117
  type: 'tuple',
@@ -202,19 +144,6 @@ const decodeAcrossV4SwapAndStart = (data) => {
202
144
  destinationMinimum: acrossData.outputAmount,
203
145
  };
204
146
  };
205
- /**
206
- * `swapAndStartBridgeTokensViaLayerSwap((BridgeData),(SwapData[]),(LayerSwapData))`.
207
- *
208
- * Selector `0x4c279d6b`, verified against
209
- * `packages/bridge-sdk/src/__fixtures__/lifi/quote-plain-base-to-polygon.json`
210
- * (a real `GET /v1/quote` response) — signature and struct layout read from
211
- * `lifinance/contracts/src/Facets/LayerSwapFacet.sol`. `LayerSwapData`
212
- * carries no native-fee field ({@link DecodedLifiFacetCall.extraNativeFee}
213
- * is always `0n`) and, unlike Across or Stargate, NO destination-amount
214
- * field at all — LayerSwap's delivered amount is attested off-chain by an
215
- * EIP-712 signature over `requestId`, not provable from this calldata, so
216
- * {@link DecodedLifiFacetCall.destinationMinimum} is always `null`.
217
- */
218
147
  const decodeLayerSwapSwapAndStart = (data) => {
219
148
  const layerSwapDataAbiType = {
220
149
  type: 'tuple',
@@ -241,22 +170,6 @@ const decodeLayerSwapSwapAndStart = (data) => {
241
170
  destinationMinimum: null,
242
171
  };
243
172
  };
244
- /**
245
- * `swapAndStartBridgeTokensViaStargate((BridgeData),(SwapData[]),(StargateData))`.
246
- *
247
- * Selector `0xa6010a66`, verified against two live captures of
248
- * `POST /v1/quote/contractCalls`
249
- * (`packages/bridge-sdk/src/__fixtures__/lifi/contract-calls-native-base-to-eth-mediator.json`
250
- * and its `-erc20-` sibling) — signature and struct layout read from
251
- * `lifinance/contracts/src/Facets/StargateFacetV2.sol` and
252
- * `src/Interfaces/IStargate.sol`. `StargateData.fee.nativeFee` is a
253
- * LayerZero messaging fee that rides in `msg.value` ON TOP of any deposited
254
- * native amount — confirmed by both fixtures: `transactionRequest.value`
255
- * equalled `originAmount + fee.nativeFee` exactly (origin ETH) and
256
- * `fee.nativeFee` alone when the origin amount was an ERC20 (USD Coin, no
257
- * native component). `sendParams.minAmountLD` is Stargate's own
258
- * destination-side guarantee.
259
- */
260
173
  const decodeStargateSwapAndStart = (data) => {
261
174
  const stargateDataAbiType = {
262
175
  type: 'tuple',
@@ -301,32 +214,12 @@ const decodeStargateSwapAndStart = (data) => {
301
214
  destinationMinimum: stargateData.sendParams.minAmountLD,
302
215
  };
303
216
  };
304
- /**
305
- * Every LI.FI facet function this module can decode, keyed by its four-byte
306
- * selector. AN UNKNOWN SELECTOR IS NEVER DECODED — {@link verifyLifiEvmExecution}
307
- * refuses it outright. Extending this table means capturing a real fixture
308
- * for the new tool first; see this module's top-of-file doc comment.
309
- */
310
217
  const lifiFacetDecoders = {
311
218
  '0x1794958f': decodeAcrossV4SwapAndStart,
312
219
  '0x4c279d6b': decodeLayerSwapSwapAndStart,
313
220
  '0xa6010a66': decodeStargateSwapAndStart,
314
221
  };
315
222
  const sameAddress = (a, b) => a.toLowerCase() === b.toLowerCase();
316
- /**
317
- * Verifies a LI.FI EVM execution transaction against what this application
318
- * asked for, throwing {@link LifiExecutionRefusedError} on any disagreement.
319
- * Returns normally — carrying nothing, since the caller already holds the
320
- * transaction it validated — when every check passes.
321
- *
322
- * See this module's top-of-file doc comment for what is checked and why.
323
- *
324
- * @param transactionRequest - the parsed `to`/`data`/`value`/`chainId` this
325
- * application is about to hand to a wallet
326
- * @param approvalAddress - `estimate.approvalAddress` from the same
327
- * response, or `null` when the route needs no token approval
328
- * @param expectation - what this application actually asked for
329
- */
330
223
  export const verifyLifiEvmExecution = (transactionRequest, approvalAddress, expectation) => {
331
224
  const router = lifiDiamondAddressByChainId.get(transactionRequest.chainId);
332
225
  if (router === undefined) {