@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,38 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.nearIntentsRefusalShapeFindings = exports.nearIntentsStatusShapeFindings = exports.nearIntentsMappedChainNames = exports.nearIntentsTokenListShapeFindings = exports.nearIntentsQuoteShapeFindings = void 0;
4
- /**
5
- * Does the live service still answer in the shape this repository parses?
6
- *
7
- * THIS EXISTS BECAUSE NEAR INTENTS HAS NO TEST NETWORK. The vendor states it
8
- * four times in its own current material, most plainly in its list of common
9
- * questions: "There is no testnet deployment and no plans for one. We
10
- * recommend testing on NEAR mainnet using separate dev/test NEAR accounts."
11
- * So there is no safe copy of the service to check an integration against, and
12
- * the only honest substitute is a priced request against production that
13
- * reserves nothing — a dry quote. See `docs/near-intents-capability-survey.md`.
14
- *
15
- * WHAT THIS CLOSES THAT THE FIXTURES CANNOT. `near-intents.test.ts` runs
16
- * against real captures taken on 2026-09-17. A capture is a photograph: it
17
- * proves the parser reads what the service sent that day, and it goes on
18
- * proving that forever, including after the service stops sending it. Every
19
- * parser here is tolerant by design — it returns null rather than throwing —
20
- * so a field that changes type does not break a test, it removes a provider
21
- * from the interface with no message anywhere. `amountOut` arriving as a
22
- * number instead of a string is the whole failure: 37 green tests, and NEAR
23
- * Intents silently never bids again.
24
- *
25
- * So these functions name every field the parsers actually depend on and
26
- * report what is missing, rather than returning a normalized value. Handed a
27
- * live response they answer "has production drifted away from the captures".
28
- * Handed a capture they answer "is this capture still a fair stand-in".
29
- *
30
- * They are deliberately NOT parsers. A parser answers "can I use this"; these
31
- * answer "is this what I was written against", which is a different question
32
- * and needs the failures enumerated rather than collapsed into a null.
33
- */
34
4
  const near_intents_js_1 = require("./near-intents.js");
35
- /** Which parser depends on a field, so a finding says what will break. */
36
5
  const describe = (value) => {
37
6
  if (value === undefined) {
38
7
  return 'absent';
@@ -48,13 +17,6 @@ const describe = (value) => {
48
17
  const asRecord = (value) => typeof value === 'object' && value !== null && !Array.isArray(value)
49
18
  ? value
50
19
  : null;
51
- /**
52
- * Checks one field and returns a finding when it is not the required type.
53
- *
54
- * A base-unit amount must be a NON-EMPTY string, because that is what
55
- * `parseAmount` in `near-intents.ts` requires: it refuses an empty string and
56
- * refuses a number, so either one silently collapses the whole quote to null.
57
- */
58
20
  const requireField = ({ container, key, path, kind, }) => {
59
21
  const value = container[key];
60
22
  if (kind === 'amount') {
@@ -76,21 +38,6 @@ const requireField = ({ container, key, path, kind, }) => {
76
38
  : { path, expected: 'a non-empty string', found: describe(value) };
77
39
  };
78
40
  const compact = (findings) => findings.filter((finding) => finding !== null);
79
- /**
80
- * Checks a `POST /v0/quote` answer against everything the quote parsers read.
81
- *
82
- * THE DOLLAR FIGURES ARE CHECKED THOUGH THE PARSER TOLERATES THEIR ABSENCE.
83
- * `parseNearIntentsQuote` turns a missing `amountInUsd` into null and carries
84
- * on, which is right for a quote and wrong for a conformance check: losing the
85
- * dollar figure leaves the reader a route with no price beside it, and nothing
86
- * else in the system would report that the service stopped sending one.
87
- *
88
- * @param payload - the raw JSON body the service answered with
89
- * @param options.expectDepositAddress - true for an executable (`dry: false`)
90
- * answer, false for a dry one. A dry answer omits the deposit address by
91
- * design, so requiring it there would report a finding on a healthy service
92
- * @returns every departure from the expected shape; empty means conformant
93
- */
94
41
  const nearIntentsQuoteShapeFindings = (payload, { expectDepositAddress }) => {
95
42
  const body = asRecord(payload);
96
43
  if (!body) {
@@ -145,17 +92,6 @@ const nearIntentsQuoteShapeFindings = (payload, { expectDepositAddress }) => {
145
92
  return [...findings, ...nearIntentsAppFeeFindings(body.quoteRequest)];
146
93
  };
147
94
  exports.nearIntentsQuoteShapeFindings = nearIntentsQuoteShapeFindings;
148
- /**
149
- * Checks the echoed request for the surcharge a key-less caller is charged.
150
- *
151
- * THE SERVICE INSERTS THIS, NOT US. Nothing in this repository asks for an
152
- * `appFees` entry, and the fee parser only finds the twenty-five-basis-point
153
- * charge because the service writes it into the request it echoes back. If it
154
- * ever stops echoing it, the charge does not stop — it disappears from the
155
- * fee rows and the reader is shown a route that costs a quarter of a percent
156
- * more than the interface says. That is a silent understatement of cost, so it
157
- * is a finding rather than a tolerated absence.
158
- */
159
95
  const nearIntentsAppFeeFindings = (quoteRequest) => {
160
96
  const request = asRecord(quoteRequest);
161
97
  if (!request) {
@@ -193,23 +129,6 @@ const nearIntentsAppFeeFindings = (quoteRequest) => {
193
129
  });
194
130
  }));
195
131
  };
196
- /**
197
- * Checks a `GET /v0/tokens` answer, including the chain names we map by hand.
198
- *
199
- * AN UNMAPPED CHAIN NAME IS THE DRIFT MOST LIKELY TO HAPPEN AND LEAST LIKELY
200
- * TO BE NOTICED. `chainIdByNearIntentsChain` is a hand-written table, and
201
- * `findNearIntentsAsset` matches through it — so if the service renames a
202
- * chain or adds one, every asset on that chain becomes invisible to this
203
- * repository while the asset list parses perfectly and every test stays green.
204
- * The names are reported rather than the assets, because a new chain we do not
205
- * carry is ordinary and a renamed chain we DO carry is the emergency.
206
- *
207
- * @param payload - the raw JSON body from the asset endpoint
208
- * @param options.requiredChains - the service's own names for the chains this
209
- * repository must keep reaching. A name missing from the answer means the
210
- * service renamed or dropped it
211
- * @returns every departure from the expected shape; empty means conformant
212
- */
213
132
  const nearIntentsTokenListShapeFindings = (payload, { requiredChains }) => {
214
133
  if (!Array.isArray(payload)) {
215
134
  return [{ path: '', expected: 'an array of assets', found: describe(payload) }];
@@ -264,27 +183,10 @@ const nearIntentsTokenListShapeFindings = (payload, { requiredChains }) => {
264
183
  return findings;
265
184
  };
266
185
  exports.nearIntentsTokenListShapeFindings = nearIntentsTokenListShapeFindings;
267
- /**
268
- * The service's own names for every chain this repository maps to a chain
269
- * identifier, which is exactly the set whose renaming would be invisible.
270
- */
271
186
  const nearIntentsMappedChainNames = () => [
272
187
  ...near_intents_js_1.chainIdByNearIntentsChain.keys(),
273
188
  ];
274
189
  exports.nearIntentsMappedChainNames = nearIntentsMappedChainNames;
275
- /**
276
- * Checks a `GET /v0/status` answer against what the status parser reads.
277
- *
278
- * THE DELIVERY HASH IS NOT REQUIRED, and that is not laxity. A route awaiting
279
- * its deposit has genuinely not produced one, and the captured
280
- * `status-pending-deposit.json` is exactly that case — so requiring it would
281
- * report a finding on a perfectly healthy in-flight transfer. What is required
282
- * is that the ARRAY exists, because its absence is the difference between "no
283
- * hash yet" and "the service stopped telling us where the funds landed".
284
- *
285
- * @param payload - the raw JSON body from the status endpoint
286
- * @returns every departure from the expected shape; empty means conformant
287
- */
288
190
  const nearIntentsStatusShapeFindings = (payload) => {
289
191
  const body = asRecord(payload);
290
192
  if (!body) {
@@ -313,18 +215,6 @@ const nearIntentsStatusShapeFindings = (payload) => {
313
215
  ];
314
216
  };
315
217
  exports.nearIntentsStatusShapeFindings = nearIntentsStatusShapeFindings;
316
- /**
317
- * Checks a refusal body carries the message the refusal parser reads.
318
- *
319
- * BOTH SIZE FLOORS ARRIVE ONLY AS PROSE IN THIS FIELD. There is no code, no
320
- * limits endpoint and no structured figure — `parseNearIntentsQuoteRefusal`
321
- * runs a regular expression over the sentence. So if the wording changes, a
322
- * refusal that should withdraw the route from the competition instead reads as
323
- * `other`, and the reader waits for a bid that will never come.
324
- *
325
- * @param payload - the raw JSON body of a refused quote
326
- * @returns every departure from the expected shape; empty means conformant
327
- */
328
218
  const nearIntentsRefusalShapeFindings = (payload) => {
329
219
  const body = asRecord(payload);
330
220
  if (!body) {
@@ -1,5 +1,18 @@
1
1
  import type { DeferredCrossing, RouteCandidate } from './routing/candidate.js';
2
2
  import type { RouteData } from './routing/route-data.js';
3
+ /**
4
+ * The name of a step that starts on one chain and ends on another (or the same).
5
+ *
6
+ * A step whose two chains differ is "Send to {end chain}". A step that never
7
+ * leaves its chain is a swap, so it is "Swap on {chain}". "Send to Ethereum"
8
+ * on a swap that starts and ends on Ethereum names a crossing that never
9
+ * happens.
10
+ *
11
+ * @param startChainId - the chain the step starts on
12
+ * @param endChainId - the chain the step ends on
13
+ * @returns the step's English label
14
+ */
15
+ export declare const sendOrSwapLabel: (startChainId: number, endChainId: number) => string;
3
16
  /**
4
17
  * Builds the two-signature route for a candidate whose aggregator cannot
5
18
  * execute the omnibridge entry call.
@@ -33,69 +33,24 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.describeDeferredCrossing = exports.buildNearIntentsTwoStepRouteData = void 0;
36
+ exports.describeDeferredCrossing = exports.buildNearIntentsTwoStepRouteData = exports.sendOrSwapLabel = void 0;
37
37
  const imageLinks = __importStar(require("./image-links.js"));
38
38
  const producers_js_1 = require("./routing/producers.js");
39
39
  const providers_js_1 = require("./providers.js");
40
40
  const usd_value_js_1 = require("./routing/usd-value.js");
41
41
  const chain_names_js_1 = require("./chain-names.js");
42
- /**
43
- * The route shape for an aggregator that cannot execute on the chain it
44
- * delivers to.
45
- *
46
- * WHY THIS EXISTS AT ALL. Every other consolidated route in this repository is
47
- * ONE signature: the aggregator carries the reader's funds to an omnibridge
48
- * entry chain and its executor performs the entry call on arrival, so the
49
- * crossing into PulseChain happens inside the same transaction the reader
50
- * already signed. NEAR Intents cannot do that — it delivers tokens to an
51
- * address and runs nothing — and no arrangement of recipients works around it,
52
- * because every omnibridge entry point learns who the reader is from a data
53
- * field and a plain token transfer has none. See the head of `near-intents.ts`.
54
- *
55
- * So the crossing becomes TWO signatures, and the honest thing is to draw it
56
- * that way. The aggregator lands the anchor token in the reader's OWN wallet on
57
- * the entry chain; the reader then signs the ordinary omnibridge call
58
- * themselves. The interface already renders exactly this shape — a section
59
- * marked `deferred` draws "You sign this later" on the route itself rather than
60
- * hiding the fact in a tooltip — so nothing new had to be invented to show it.
61
- *
62
- * WHAT THIS MUST NEVER DO is present the second signature as optional, or let
63
- * the route claim a delivered amount as though it were settled. The reader is
64
- * mid-journey until they sign again, and a route that implies otherwise is
65
- * selling a single-signature experience it does not deliver.
66
- */
67
- /**
68
- * Turns a token into the display node the route strip draws, resolving its logo
69
- * here rather than in the view.
70
- *
71
- * Pre-resolved deliberately: a view-layer image fallback reaches only the nodes
72
- * a builder left unset, so a builder that sets the field and a builder that
73
- * does not produce different pictures for the same token.
74
- *
75
- * The chain badge goes through `networkOrPseudo`, not `network` — a deposit-
76
- * address origin (Zcash) carries a local, invented chain id the numeric
77
- * endpoint 404s on. See that helper's own note for why this lives in
78
- * `image-links.ts` rather than the richer client-side resolver.
79
- */
80
42
  const tokenNode = (token, chainId) => ({
81
43
  symbol: token.symbol,
82
44
  address: token.address,
83
45
  chainId,
84
46
  decimals: token.decimals,
85
- // `tokenImageOrChainFallback`, NOT `image` — the ANCHOR node this call also
86
- // draws can reach here before its exact address is known (the deferred
87
- // crossing has not settled yet), and `image` either throws on an address it
88
- // cannot checksum or draws nothing at all. See that helper's own note.
89
47
  logoUri: imageLinks.tokenImageOrChainFallback(token),
90
48
  chainLogoUri: imageLinks.networkOrPseudo(chainId),
91
49
  });
92
- /**
93
- * Parses one of the aggregator's own dollar figures.
94
- *
95
- * They arrive as decimal strings. A figure that will not parse becomes null
96
- * rather than zero, because zero is a real value that reads as "this leg is
97
- * free" — which is the one thing a cost figure must never say by accident.
98
- */
50
+ const sendOrSwapLabel = (startChainId, endChainId) => startChainId === endChainId
51
+ ? `Swap on ${(0, chain_names_js_1.chainDisplayName)(endChainId)}`
52
+ : `Send to ${(0, chain_names_js_1.chainDisplayName)(endChainId)}`;
53
+ exports.sendOrSwapLabel = sendOrSwapLabel;
99
54
  const usdNumber = (value) => {
100
55
  if (typeof value !== 'string' || value === '') {
101
56
  return null;
@@ -103,41 +58,11 @@ const usdNumber = (value) => {
103
58
  const parsed = Number(value);
104
59
  return Number.isFinite(parsed) ? parsed : null;
105
60
  };
106
- /**
107
- * Builds the two-signature route for a candidate whose aggregator cannot
108
- * execute the omnibridge entry call.
109
- *
110
- * The result has exactly two sections, and the order carries the meaning:
111
- *
112
- * 1. The aggregator's leg, signed NOW. It ends with the anchor token sitting
113
- * in the reader's own wallet on the entry chain.
114
- * 2. The omnibridge crossing, marked `deferred`, signed LATER by the reader.
115
- *
116
- * COSTS ARE SPLIT BETWEEN THE SECTIONS RATHER THAN POOLED, because a reader
117
- * deciding whether to accept a second signature needs to know what each half
118
- * costs. The first section's spread is the difference between the aggregator's
119
- * own paid and delivered figures — both from the one answer that priced them,
120
- * never from two feeds. The second section's cost is the omnibridge crossing
121
- * fee, computed from the known on-chain rate.
122
- *
123
- * THE DELIVERED FIGURE IS AN ESTIMATE AND THE INTERFACE KNOWS IT. A route whose
124
- * last section is deferred has not been quoted end to end, so
125
- * `outputAmountIsUnsettled` blanks the received-amount field on the reader's
126
- * behalf. The figure is still carried — the conversion route sets its estimate
127
- * the same way — so the route can be ranked and compared.
128
- *
129
- * @param candidate - the route candidate, which must carry a `deferredCrossing`
130
- * @returns the two-section route, or null when the candidate names no deferred
131
- * crossing or no omnibridge provider to perform it
132
- */
133
61
  const buildNearIntentsTwoStepRouteData = (candidate) => {
134
62
  const deferredCrossing = candidate.deferredCrossing;
135
63
  if (!deferredCrossing) {
136
64
  return null;
137
65
  }
138
- // No omnibridge leg means there is no second signature, which means this is
139
- // not the shape being built. A route the aggregator carries end to end is an
140
- // ordinary one-signature route and belongs to `buildCandidateRouteData`.
141
66
  const omnibridgeProviderKey = candidate.omnibridgeProvider;
142
67
  if (omnibridgeProviderKey === null) {
143
68
  return null;
@@ -149,9 +74,6 @@ const buildNearIntentsTwoStepRouteData = (candidate) => {
149
74
  const destinationNode = tokenNode(destinationToken, producers_js_1.pulsechainChainId);
150
75
  const paidUsd = usdNumber(candidate.quote.fromAmountUsd);
151
76
  const landedUsd = usdNumber(anchorUsdValue);
152
- // The aggregator's spread on its own leg: what the reader paid, less what the
153
- // aggregator says arrives. Both figures come from the same answer, so the
154
- // difference is the route and nothing else.
155
77
  const aggregatorFeeUsd = (0, producers_js_1.subtractUsdValues)(paidUsd, landedUsd);
156
78
  const crossingFeeUsd = (0, usd_value_js_1.usdValueOfAmount)({
157
79
  balance: candidate.omnibridgeFeeAmount,
@@ -163,35 +85,20 @@ const buildNearIntentsTwoStepRouteData = (candidate) => {
163
85
  ? Math.ceil(candidate.quote.executionDurationSeconds / 60)
164
86
  : null;
165
87
  const aggregatorHop = {
166
- // THIS HOP IS THE AGGREGATOR, NOT THE OMNIBRIDGE — `providerDisplayName`
167
- // (used for the crossing hop below) is keyed only on `Providers.PULSECHAIN`
168
- // / `Providers.TOKENSEX` and falls back to the generic "Omnibridge" for
169
- // anything else. Run through it here, `candidate.quote.provider` (a
170
- // `ProviderId` — 'lifi' | 'relay' | 'near-intents') had no entry, so a
171
- // NEAR Intents two-step route named its first leg "Omnibridge" — the
172
- // bridge, not the aggregator that actually carried it. `providerById` is
173
- // total over `ProviderId` and throws on an unregistered one rather than
174
- // silently naming a different provider.
175
88
  providerName: (0, providers_js_1.providerById)(candidate.quote.provider).label,
176
89
  providerKey: candidate.quote.provider,
177
- title: `Send to ${(0, chain_names_js_1.chainDisplayName)(candidate.entryChainId)}`,
90
+ title: (0, exports.sendOrSwapLabel)(originToken.chainId, candidate.entryChainId),
178
91
  conversion: `→ ${anchorToken.symbol}`,
179
92
  fromToken: originNode,
180
93
  toToken: anchorNode,
181
94
  feeUsdValue: aggregatorFeeUsd,
182
- // The reader's own signature starts this leg; nothing runs inside it.
183
95
  automatic: false,
184
96
  };
185
97
  const aggregatorSection = {
186
98
  id: `${candidate.id}-signature-1`,
187
- // Named for where the funds END UP, and pointedly NOT "Bridge to
188
- // PulseChain": this signature does not reach PulseChain and a label that
189
- // said so would be the single-signature claim this route exists to avoid.
190
- label: `Send to ${(0, chain_names_js_1.chainDisplayName)(candidate.entryChainId)}`,
99
+ label: (0, exports.sendOrSwapLabel)(originToken.chainId, candidate.entryChainId),
191
100
  providerKey: candidate.quote.provider,
192
101
  tokenFlow: [originNode, anchorNode],
193
- // WHAT THE READER IS LEFT HOLDING between the two signatures, in their own
194
- // wallet on the entry chain. This is the step's whole point.
195
102
  landing: {
196
103
  amount: anchorAmount,
197
104
  decimals: anchorToken.decimals,
@@ -212,9 +119,6 @@ const buildNearIntentsTwoStepRouteData = (candidate) => {
212
119
  fromToken: anchorNode,
213
120
  toToken: destinationNode,
214
121
  feeUsdValue: crossingFeeUsd,
215
- // NOT automatic, and this is the difference the whole route turns on. On a
216
- // one-signature route the aggregator's executor makes this call; here the
217
- // reader does, by hand, after the anchor lands.
218
122
  automatic: false,
219
123
  };
220
124
  const crossingSection = {
@@ -229,23 +133,8 @@ const buildNearIntentsTwoStepRouteData = (candidate) => {
229
133
  usdValue: (0, producers_js_1.subtractUsdValues)(landedUsd, crossingFeeUsd),
230
134
  },
231
135
  feeUsdValue: crossingFeeUsd,
232
- // THE FLAG THAT MAKES THE ROUTE HONEST. It is what draws "You sign this
233
- // later" on the step, what makes the primary button name the step it
234
- // actually signs, and what stops any surface stating the delivered amount
235
- // as settled. Removing it would turn this into a route that silently
236
- // promises one signature and asks for two.
237
136
  deferred: true,
238
- // `sectionDescription` in the route strip reads `section.deferredNote ??
239
- // defaultDeferredNote()`, so a note supplied HERE replaces the default
240
- // sentence outright rather than adding to it. The default sentence is
241
- // "Fee is approximate — quoted when you return." — the one fact that
242
- // tells the reader the output figure they are looking at is not settled.
243
- // A note that names only the second signature and drops that fact leaves
244
- // a settled-looking figure on screen with nothing anywhere saying
245
- // otherwise, so this note must carry BOTH facts itself.
246
137
  deferredNote: `The bridge crossing is a second signature you make once the funds arrive on ${(0, chain_names_js_1.chainDisplayName)(candidate.entryChainId)}. The amount shown is approximate and is quoted again when you return.`,
247
- // The crossing's own settlement wait, which is the long part of the journey
248
- // and has nothing to do with the aggregator's estimate above.
249
138
  etaMinutes: producers_js_1.BRIDGE_SETTLEMENT_ETA_MINUTES,
250
139
  hops: [crossingHop],
251
140
  };
@@ -255,42 +144,20 @@ const buildNearIntentsTwoStepRouteData = (candidate) => {
255
144
  return {
256
145
  kind: 'aggregated',
257
146
  entryChainId: candidate.entryChainId,
258
- // Named after the omnibridge, matching the one-signature route: a route is
259
- // named for the thing that performs its defining leg.
260
147
  headlineProviderKey: omnibridgeProviderKey,
261
148
  sections: [aggregatorSection, crossingSection],
262
149
  output: {
263
150
  amount: candidate.deliveredAmount,
264
151
  decimals: destinationToken.decimals,
265
152
  symbol: destinationToken.symbol,
266
- // The source basis, carried the whole way: what was paid, less what each
267
- // leg costs. Re-pricing the delivered token against its own feed would
268
- // state this route's cost twice and the two would not agree.
269
153
  usdValue: (0, producers_js_1.subtractUsdValues)(paidUsd, totalCostUsdValue),
270
154
  },
271
155
  totalCostUsdValue,
272
- // Ranked on the same net figure as every other route: delivered value less
273
- // everything the journey costs.
274
156
  netValueUsd: (0, producers_js_1.subtractUsdValues)(paidUsd, totalCostUsdValue),
275
- // The reader's wait is BOTH legs, not the aggregator's leg alone. A route
276
- // that reported only the first would claim to finish before its second
277
- // signature had even been asked for.
278
157
  etaMinutes: (etaMinutes ?? 0) + producers_js_1.BRIDGE_SETTLEMENT_ETA_MINUTES,
279
158
  };
280
159
  };
281
160
  exports.buildNearIntentsTwoStepRouteData = buildNearIntentsTwoStepRouteData;
282
- /**
283
- * Describes the anchor a two-signature route leaves the reader holding.
284
- *
285
- * A small constructor rather than an inline object literal at the call site,
286
- * so the three fields are named and documented in one place and a caller
287
- * cannot quietly pair one aggregator's amount with another's valuation.
288
- *
289
- * @param options.anchorToken - the entry-chain token the aggregator delivers
290
- * @param options.anchorAmount - how much of it lands, in its base units
291
- * @param options.anchorUsdValue - the AGGREGATOR'S own valuation of that landing
292
- * @returns the deferred-crossing record, or null when no amount is known
293
- */
294
161
  const describeDeferredCrossing = ({ anchorToken, anchorAmount, anchorUsdValue, }) => {
295
162
  if (anchorToken === null) {
296
163
  return null;