@gibs/bridge-sdk 1.19.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 (111) hide show
  1. package/dist/abis.js +0 -2
  2. package/dist/bridge-limits.js +0 -38
  3. package/dist/chain-info.js +0 -116
  4. package/dist/chain-names.js +0 -151
  5. package/dist/chains.js +0 -198
  6. package/dist/cjs/abis.js +0 -2
  7. package/dist/cjs/bridge-limits.js +0 -38
  8. package/dist/cjs/chain-info.js +0 -116
  9. package/dist/cjs/chain-names.js +0 -151
  10. package/dist/cjs/chains.js +0 -198
  11. package/dist/cjs/claims.js +0 -60
  12. package/dist/cjs/config.js +1 -208
  13. package/dist/cjs/consolidated-quote.js +0 -465
  14. package/dist/cjs/destination-calldata.js +0 -71
  15. package/dist/cjs/ecosystems.js +0 -183
  16. package/dist/cjs/execution.js +0 -92
  17. package/dist/cjs/fee-type.js +0 -1
  18. package/dist/cjs/hyperliquid-execution.js +0 -98
  19. package/dist/cjs/image-links.js +0 -108
  20. package/dist/cjs/lifi-execution-guard.js +65 -172
  21. package/dist/cjs/near-intents-conformance.js +0 -110
  22. package/dist/cjs/near-intents-route.js +0 -149
  23. package/dist/cjs/near-intents.js +0 -562
  24. package/dist/cjs/origin-deposit.js +0 -56
  25. package/dist/cjs/pre-quote.js +0 -80
  26. package/dist/cjs/prices.js +0 -113
  27. package/dist/cjs/providers.js +0 -83
  28. package/dist/cjs/quote-fees.js +0 -80
  29. package/dist/cjs/referral.js +0 -75
  30. package/dist/cjs/relay-currencies.js +0 -31
  31. package/dist/cjs/relay-depository.js +52 -77
  32. package/dist/cjs/relay-quote.js +0 -394
  33. package/dist/cjs/route-steps.js +0 -100
  34. package/dist/cjs/routing/amounts.js +0 -83
  35. package/dist/cjs/routing/candidate-route.js +0 -73
  36. package/dist/cjs/routing/candidate.js +0 -46
  37. package/dist/cjs/routing/carrier-provider-key.js +0 -27
  38. package/dist/cjs/routing/carriers/omnibridge.js +0 -120
  39. package/dist/cjs/routing/carriers/pulsex-paths.js +0 -57
  40. package/dist/cjs/routing/carriers/pulsex-split.js +0 -92
  41. package/dist/cjs/routing/carriers/pulsex.js +0 -279
  42. package/dist/cjs/routing/carriers/wrap.js +0 -57
  43. package/dist/cjs/routing/composed-route-quality.js +0 -95
  44. package/dist/cjs/routing/entry-chain-anchor.js +0 -27
  45. package/dist/cjs/routing/format.js +0 -50
  46. package/dist/cjs/routing/index.js +0 -28
  47. package/dist/cjs/routing/producers.js +0 -854
  48. package/dist/cjs/routing/providers.js +0 -27
  49. package/dist/cjs/routing/search/compose.js +0 -56
  50. package/dist/cjs/routing/search/graph.js +0 -364
  51. package/dist/cjs/routing/search/plan-route-data.js +0 -508
  52. package/dist/cjs/routing/search/score.js +0 -344
  53. package/dist/cjs/routing/swap-transactions.js +0 -74
  54. package/dist/cjs/routing/usd-value.js +0 -12
  55. package/dist/cjs/settings.js +1 -456
  56. package/dist/cjs/swap-venues.js +0 -17
  57. package/dist/cjs/ton-connect.js +0 -82
  58. package/dist/cjs/ton-execution.js +0 -6
  59. package/dist/cjs/ton.js +0 -42
  60. package/dist/cjs/tron-execution.js +0 -145
  61. package/dist/claims.js +0 -60
  62. package/dist/config.js +1 -211
  63. package/dist/consolidated-quote.js +0 -465
  64. package/dist/destination-calldata.js +0 -71
  65. package/dist/ecosystems.js +0 -183
  66. package/dist/execution.js +0 -92
  67. package/dist/fee-type.js +0 -2
  68. package/dist/hyperliquid-execution.js +0 -98
  69. package/dist/image-links.js +0 -108
  70. package/dist/lifi-execution-guard.js +65 -172
  71. package/dist/near-intents-conformance.js +0 -110
  72. package/dist/near-intents-route.js +0 -149
  73. package/dist/near-intents.js +0 -562
  74. package/dist/origin-deposit.js +0 -56
  75. package/dist/pre-quote.js +0 -80
  76. package/dist/prices.js +0 -113
  77. package/dist/providers.js +0 -83
  78. package/dist/quote-fees.js +0 -80
  79. package/dist/referral.js +0 -75
  80. package/dist/relay-currencies.js +0 -31
  81. package/dist/relay-depository.js +52 -77
  82. package/dist/relay-quote.js +0 -394
  83. package/dist/route-steps.js +0 -100
  84. package/dist/routing/amounts.js +0 -83
  85. package/dist/routing/candidate-route.js +0 -73
  86. package/dist/routing/candidate.js +0 -46
  87. package/dist/routing/carrier-provider-key.js +0 -27
  88. package/dist/routing/carriers/omnibridge.js +0 -120
  89. package/dist/routing/carriers/pulsex-paths.js +0 -57
  90. package/dist/routing/carriers/pulsex-split.js +0 -92
  91. package/dist/routing/carriers/pulsex.js +0 -279
  92. package/dist/routing/carriers/wrap.js +0 -57
  93. package/dist/routing/composed-route-quality.js +0 -95
  94. package/dist/routing/entry-chain-anchor.js +0 -27
  95. package/dist/routing/format.js +0 -50
  96. package/dist/routing/index.js +0 -28
  97. package/dist/routing/producers.js +0 -854
  98. package/dist/routing/providers.js +0 -27
  99. package/dist/routing/search/compose.js +0 -56
  100. package/dist/routing/search/graph.js +0 -364
  101. package/dist/routing/search/plan-route-data.js +0 -508
  102. package/dist/routing/search/score.js +0 -344
  103. package/dist/routing/swap-transactions.js +0 -74
  104. package/dist/routing/usd-value.js +0 -12
  105. package/dist/settings.js +1 -456
  106. package/dist/swap-venues.js +0 -17
  107. package/dist/ton-connect.js +0 -82
  108. package/dist/ton-execution.js +0 -6
  109. package/dist/ton.js +0 -42
  110. package/dist/tron-execution.js +0 -145
  111. package/package.json +3 -3
@@ -1,69 +1,7 @@
1
1
  import { isNativeAsset } from '../../ecosystems.js';
2
2
  import { compareRoutePlansByDeliveredAmount, planIsRankable, isRankableBasis, } from './graph.js';
3
- /**
4
- * PHASE 0 — FOUNDATION ONLY. Today this module holds exactly one function,
5
- * {@link waitPenaltyPpm}, moved here unchanged from
6
- * `packages/ui/src/lib/stores/consolidated-quote.ts` (that file now imports
7
- * and re-exports it, so every existing caller keeps working). Phase 1's
8
- * `score.ts` work (design section 4) generalizes `candidateNetValueUsd` and
9
- * `netValueAfterWaitPenalty` from `../producers.js` and
10
- * `packages/ui/src/lib/state/useRouteOptions.ts` into one `scoreRoutePlan`
11
- * function that lives here beside it.
12
- *
13
- * WHY THIS MOVES TO `bridge-sdk` AT ALL. `waitPenaltyPpm` is a pure function
14
- * of a number — it has no dependency on React, a store, or any
15
- * user-interface concern — and `scoreRoutePlan` will need it to score a
16
- * `RoutePlan` (`../graph.js`), which is a `bridge-sdk` type. Leaving the
17
- * function in the user-interface package would make `bridge-sdk`'s own
18
- * scoring logic import FROM the application that is supposed to consume it.
19
- */
20
- /**
21
- * The share of the transfer a full minute of extra waiting is charged, in
22
- * parts per million — 5,000 ppm is half of one percent.
23
- *
24
- * WHERE THE NUMBER COMES FROM. The owner's own crossing: LI.FI (through
25
- * squid) claimed twenty seconds and Relay claimed two, and the strip
26
- * preferred LI.FI because it delivered 0.075% more — nine cents on a
27
- * hundred and twenty-six dollars. The transfer was still unsettled
28
- * twenty-five minutes later. A second live measurement on Base to Polygon:
29
- * twenty-nine seconds against three, for 0.0545%. Both are the same shape —
30
- * a few cents of advantage bought with a ten-fold increase in the wait —
31
- * and under this rate both go the other way: at eighteen seconds of extra
32
- * claimed wait a route must deliver 0.15% more to win, and at twenty-six
33
- * seconds it must deliver 0.217% more. Neither does.
34
- *
35
- * The rate is also calibrated NOT to override a real price advantage. A
36
- * route that is a full minute slower still wins on 0.6% more delivered,
37
- * which on a hundred-and-twenty-six-dollar transfer is seventy-six cents —
38
- * a figure worth waiting a minute for, where nine cents is not.
39
- */
40
3
  const WAIT_PENALTY_PPM_PER_MINUTE = 5_000;
41
- /** The wait beyond which extra claimed seconds stop adding to the penalty. */
42
4
  const WAIT_PENALTY_CEILING_SECONDS = 60;
43
- /**
44
- * What a quote's CLAIMED duration costs it in the ranking, as a share of the
45
- * transfer in parts per million. It ramps linearly to
46
- * {@link WAIT_PENALTY_PPM_PER_MINUTE} at {@link WAIT_PENALTY_CEILING_SECONDS}
47
- * and stops there.
48
- *
49
- * THE DURATION IS A CLAIM AND IS TREATED AS ONE. The route that prompted
50
- * this ran about seventy-five times its provider's own estimate, so the
51
- * figure cannot be trusted as a measurement of anything. It is still the
52
- * only signal there is, and it is informative in one direction: a provider
53
- * that says it will take longer is not going to turn out faster, and a
54
- * claimed wait understates the real one far more often than it overstates
55
- * it. So the penalty is used to demand a real price advantage before ANY
56
- * extra claimed wait is accepted — never to predict a settlement time, and
57
- * never to produce a number shown to the reader. Nothing on screen is
58
- * adjusted by this; only the order is.
59
- *
60
- * The ceiling is what keeps the rule from becoming a speed preference. Past
61
- * a minute the penalty stops growing, so a route that is genuinely worth
62
- * waiting for still wins on the strength of its price.
63
- *
64
- * @param durationSeconds - the provider's own claimed execution duration
65
- * @returns the penalty as parts per million of the transfer, 0 for a missing claim
66
- */
67
5
  export const waitPenaltyPpm = (durationSeconds) => {
68
6
  if (typeof durationSeconds !== 'number' || !Number.isFinite(durationSeconds))
69
7
  return 0;
@@ -72,185 +10,13 @@ export const waitPenaltyPpm = (durationSeconds) => {
72
10
  const rampedSeconds = Math.min(durationSeconds, WAIT_PENALTY_CEILING_SECONDS);
73
11
  return Math.round((WAIT_PENALTY_PPM_PER_MINUTE * rampedSeconds) / WAIT_PENALTY_CEILING_SECONDS);
74
12
  };
75
- // ---------------------------------------------------------------------------
76
- // scoreRoutePlan — the one maximization function
77
- // ---------------------------------------------------------------------------
78
- /**
79
- * The share of the transfer charged for EACH reader action beyond the first,
80
- * in parts per million — see {@link signaturePenaltyUsd}.
81
- *
82
- * THIS IS A PROPOSAL, NOT A MEASUREMENT. Unlike {@link WAIT_PENALTY_PPM_PER_MINUTE},
83
- * which is calibrated against two logged, live crossings, no comparable
84
- * signature-count measurement exists yet. 2,500 ppm (0.25% of the delivered
85
- * amount) is a starting point sized to sit BELOW the wait penalty's own
86
- * ceiling (5,000 ppm) — a second signature should cost less than the worst
87
- * wait penalty already accepted, since a signature is a moment of the
88
- * reader's attention, not twenty-five minutes of theirs. The owner is meant
89
- * to calibrate this against real reader behavior once it ships.
90
- */
91
13
  export const SIGNATURE_PENALTY_PPM = 2_500;
92
- /**
93
- * SUPERSEDED FOR THE SEARCH ENGINE'S OWN RANKING — see
94
- * {@link compareRoutePlansByGasAdjustedDeliveredAmount}, below, which
95
- * `waves.ts` now uses in place of {@link compareRoutePlansByScoreAdjustedDeliveredAmount}
96
- * once real gas data exists. A flat parts-per-million guess cannot tell a
97
- * cheap chain from an expensive one, and it charges nothing for gas at all —
98
- * the owner's own instruction: "it's custom for each provider ... gather the
99
- * logic around how much a user is about to be charged." This constant, and
100
- * {@link GAS_TOPUP_PENALTY_PPM} below, are KEPT UNCHANGED because
101
- * {@link scoreRoutePlan} and every existing United States dollar-based
102
- * caller of it (`plan-route-data.ts`, `producers.ts`, the user interface's
103
- * own single-candidate scoring) still read them — migrating those callers to
104
- * a real gas-cost model is FLAGGED HERE as follow-up work outside this
105
- * module's own owned scope, not done silently in this change.
106
- */
107
- /**
108
- * The minimum a signature is ever charged, in United States dollars — see
109
- * {@link signaturePenaltyUsd}.
110
- *
111
- * THIS IS A PROPOSAL, NOT A MEASUREMENT. Without a floor, {@link SIGNATURE_PENALTY_PPM}
112
- * charges almost nothing on a small transfer (0.25% of ten dollars is two and
113
- * a half cents), which would let a route add a whole extra signature for a
114
- * fraction of a cent. One dollar is a guess at what a reader's own time and
115
- * attention for one extra wallet prompt is worth, floored so it cannot be
116
- * bought away by a large delivered amount either — the floor and the rate are
117
- * a `max`, so whichever is larger applies. The owner is meant to calibrate
118
- * this once real reader behavior is observed.
119
- */
120
14
  export const SIGNATURE_PENALTY_FLOOR_USD = 1;
121
- /**
122
- * The share of the transfer charged for EACH intermediate chain where the
123
- * reader holds no gas, in parts per million — see {@link gasTopUpPenaltyUsd}.
124
- *
125
- * THIS IS A PROPOSAL, NOT A MEASUREMENT. Sized larger than
126
- * {@link SIGNATURE_PENALTY_PPM} because a gas top-up is not a moment of
127
- * attention like a signature — it is a SEPARATE errand: acquire the
128
- * intermediate chain's native coin, by another bridge or a purchase, before
129
- * the planned hop can even be signed. That errand risks stranding the
130
- * transfer mid-route if the reader does not complete it, which the
131
- * "stranded funds" risk in the route-search design's section 10 names
132
- * directly. The owner is meant to calibrate this once real reader behavior
133
- * is observed.
134
- */
135
15
  export const GAS_TOPUP_PENALTY_PPM = 10_000;
136
- /**
137
- * The minimum a gas top-up is ever charged, in United States dollars — see
138
- * {@link gasTopUpPenaltyUsd}.
139
- *
140
- * THIS IS A PROPOSAL, NOT A MEASUREMENT. Set higher than
141
- * {@link SIGNATURE_PENALTY_FLOOR_USD} for the same reason
142
- * {@link GAS_TOPUP_PENALTY_PPM} is: this penalty stands in for a separate
143
- * errand with its own real cost (buying gas on a chain the reader was not
144
- * already using), not a moment of attention. The owner is meant to calibrate
145
- * this once real reader behavior is observed.
146
- */
147
16
  export const GAS_TOPUP_PENALTY_FLOOR_USD = 3;
148
- /**
149
- * What one extra reader action (a signature or a pay-by-hand deposit) costs
150
- * in the ranking, in United States dollars: the larger of
151
- * {@link SIGNATURE_PENALTY_FLOOR_USD} and {@link SIGNATURE_PENALTY_PPM} of
152
- * the delivered amount. See both constants' docs for where the numbers come
153
- * from and that they are proposals, not measurements.
154
- *
155
- * @param deliveredUsd - the route's delivered value in United States dollars
156
- * @returns the penalty for one extra action, always positive
157
- */
158
17
  const signaturePenaltyUsd = (deliveredUsd) => Math.max(SIGNATURE_PENALTY_FLOOR_USD, (deliveredUsd * SIGNATURE_PENALTY_PPM) / 1_000_000);
159
- /**
160
- * What one intermediate chain with no reader gas costs in the ranking, in
161
- * United States dollars: the larger of {@link GAS_TOPUP_PENALTY_FLOOR_USD}
162
- * and {@link GAS_TOPUP_PENALTY_PPM} of the delivered amount. See both
163
- * constants' docs for where the numbers come from and that they are
164
- * proposals, not measurements.
165
- *
166
- * @param deliveredUsd - the route's delivered value in United States dollars
167
- * @returns the penalty for one gasless intermediate chain, always positive
168
- */
169
18
  const gasTopUpPenaltyUsd = (deliveredUsd) => Math.max(GAS_TOPUP_PENALTY_FLOOR_USD, (deliveredUsd * GAS_TOPUP_PENALTY_PPM) / 1_000_000);
170
- /**
171
- * The one maximization function a route search ranks every plan by —
172
- * generalizing today's `candidateNetValueUsd` and `netValueAfterWaitPenalty`
173
- * (`../producers.js` and `packages/ui/src/lib/state/useRouteOptions.ts`)
174
- * from a single quoted candidate to a whole {@link RouteScoreInputs} plan, per
175
- * the route-search design's section 4:
176
- *
177
- * ```
178
- * score = D − P − F
179
- * − Σ_legs D·waitPenaltyPpm(claimedSeconds_leg)/1e6
180
- * − (A − 1)·max($1, D·SIGNATURE_PENALTY_PPM/1e6)
181
- * − G·max($3, D·GAS_TOPUP_PENALTY_PPM/1e6)
182
- * ```
183
- *
184
- * A HIGHER SCORE IS BETTER. A route search picks the plan with the largest
185
- * `scoreRoutePlan` result, exactly as today's ranking picks the candidate
186
- * with the largest `netValueAfterWaitPenalty`.
187
- *
188
- * THE WAIT PENALTY IS UNCHANGED, JUST SUMMED ACROSS LEGS. Today's single-quote
189
- * penalty is `deliveredUsd * waitPenaltyPpm(oneClaimedDuration) / 1e6`, one
190
- * term. A plan can carry several hops, each with its own claimed duration, so
191
- * this sums that same per-unit charge over every hop in
192
- * {@link RouteScoreInputs.legClaimedDurationsSeconds} — still against the
193
- * PLAN'S total delivered value, not each leg's own, because the reader is
194
- * charged for the whole route's wait, not a fraction of it per leg.
195
- *
196
- * WHAT IS NEW: THE ACTION AND GAS-TOP-UP TERMS. Today's ranking only ever
197
- * compared plans that cost one signature, so it had nothing to charge for a
198
- * second one. A general search can find a plan needing two or three actions,
199
- * or one that strands the reader without gas on an intermediate chain — see
200
- * `signaturePenaltyUsd` and `gasTopUpPenaltyUsd` for what each extra action
201
- * or gasless chain costs, and {@link SIGNATURE_PENALTY_PPM} /
202
- * {@link GAS_TOPUP_PENALTY_PPM} for where the rates come from.
203
- *
204
- * WHY `(A − 1)` AND NOT `A`. Every plan needs at least one action to execute
205
- * at all — signing or depositing is not itself a mark against a route, it is
206
- * what EXECUTES it. Only actions beyond the first are extra friction the
207
- * reader would not have paid on a one-action alternative, so only those are
208
- * charged.
209
- *
210
- * REFUSES AN UNPRICED PLAN BY SCORING IT NEGATIVE INFINITY — PHASE 3. When
211
- * {@link RouteScoreInputs.basis} is `'unpriced'`, `deliveredUsd` is a bare
212
- * decimal rescale with no value behind it (see `EstimateBasis`'s own doc,
213
- * `graph.ts`), and no arithmetic performed on it below would make it
214
- * trustworthy. Returning `Number.NEGATIVE_INFINITY` rather than, say, `-1` or
215
- * `0` is what makes this impossible to sidestep BY ACCIDENT: an ordinary `>`
216
- * comparison, a plain numeric `.sort()`, or a `Math.max` over several plans'
217
- * scores all already put an unpriced plan last WITHOUT the caller having to
218
- * remember to check {@link RouteScoreInputs.basis} first — the same defence
219
- * `compareRoutePlansByDeliveredAmount` (`graph.ts`) applies explicitly to a
220
- * plan-to-plan comparison, applied here so a caller who reaches for
221
- * `scoreRoutePlan` directly, for a single plan's score, gets the same
222
- * protection for free.
223
- *
224
- * @param inputs - the plan's already-priced figures; see {@link RouteScoreInputs}
225
- * @returns the plan's score — higher is better, and the units are United
226
- * States dollars throughout; `Number.NEGATIVE_INFINITY` for an unpriced plan
227
- */
228
- // ---------------------------------------------------------------------------
229
- // compareRoutePlansByScoreAdjustedDeliveredAmount — ranking that charges for
230
- // an extra signature, without needing a United States dollar price
231
- // ---------------------------------------------------------------------------
232
- /** `SIGNATURE_PENALTY_PPM`'s denominator: parts per million, as a bigint. */
233
19
  const PPM_DENOMINATOR = 1000000n;
234
- /**
235
- * `plan`'s last-hop `deliveredAmount`, discounted by {@link SIGNATURE_PENALTY_PPM}
236
- * for every signature beyond the first — proportionally, in the delivered
237
- * token's own base units, entirely in bigint arithmetic.
238
- *
239
- * WHY ONLY THE PROPORTIONAL SHARE, NEVER {@link SIGNATURE_PENALTY_FLOOR_USD}.
240
- * The floor is denominated in United States dollars; converting a base-unit
241
- * `deliveredAmount` into dollars needs a live price, which a `RoutePlan`
242
- * (`graph.ts`) does not carry — it is a bigint amount in one token's own
243
- * units, nothing more. `scoreRoutePlan` still applies the full formula,
244
- * floor included, once a caller (`plan-route-data.ts`) has priced a plan into
245
- * `RouteScoreInputs`. This function is the version usable at the STRUCTURAL
246
- * ranking sites — `enumerate.ts`'s cut and `waves.ts`'s between-wave
247
- * re-ranking — which only ever see the plan's own hops, not a price. See
248
- * {@link compareRoutePlansByScoreAdjustedDeliveredAmount}'s own doc for why a
249
- * proportional-only penalty is still enough to settle the case it exists for.
250
- *
251
- * @param plan - the plan to discount
252
- * @returns the discounted delivered amount, floored at zero
253
- */
254
20
  const signaturePenaltyAdjustedDeliveredAmount = (plan) => {
255
21
  const deliveredAmount = plan.hops[plan.hops.length - 1]?.outcome.deliveredAmount ?? 0n;
256
22
  const extraActionCount = Math.max(0, plan.signatures.length - 1);
@@ -258,45 +24,6 @@ const signaturePenaltyAdjustedDeliveredAmount = (plan) => {
258
24
  const retainedPpm = penaltyPpm >= PPM_DENOMINATOR ? 0n : PPM_DENOMINATOR - penaltyPpm;
259
25
  return (deliveredAmount * retainedPpm) / PPM_DENOMINATOR;
260
26
  };
261
- /**
262
- * Orders two RANKABLE plans (both pass `graph.ts`'s `planIsRankable`) by
263
- * their {@link signaturePenaltyAdjustedDeliveredAmount} rather than their raw
264
- * `deliveredAmount` — the STRUCTURAL counterpart to `graph.ts`'s
265
- * {@link @gibs/bridge-sdk/routing/search/graph!compareRoutePlansByDeliveredAmount},
266
- * reusing every one of that function's rules (rankable beats unrankable,
267
- * `compareUnrankablePlans`'s tiebreak among two unrankable plans) and adding
268
- * exactly one more: within two RANKABLE plans, a plan needing more
269
- * signatures than another must clear {@link SIGNATURE_PENALTY_PPM} of
270
- * "extra" delivered value per extra signature before it is allowed to win,
271
- * not merely `> 0`.
272
- *
273
- * THE DEFECT THIS CLOSES. `SIGNATURE_PENALTY_PPM` and `GAS_TOPUP_PENALTY_PPM`
274
- * existed in this module as constants `scoreRoutePlan` charges — but nothing
275
- * in the actual ranking path called `scoreRoutePlan` at all:
276
- * `enumerate.ts`'s cut, `waves.ts`'s between-wave re-ranking, and
277
- * `useRouteSearch.ts`'s final sort all imported `graph.ts`'s plain
278
- * delivered-amount comparator directly, so a route needing a second
279
- * signature for a fractional gain (measured: 0.006% more, needing one more
280
- * wallet prompt) always won outright. Sorting on
281
- * {@link signaturePenaltyAdjustedDeliveredAmount} instead is what makes that
282
- * lose to the one-signature alternative: the extra signature's proportional
283
- * cost (0.25% per {@link SIGNATURE_PENALTY_PPM}) outweighs a 0.006% edge by
284
- * roughly forty times.
285
- *
286
- * WHY NOT `GAS_TOPUP_PENALTY_PPM` HERE TOO. A gasless-intermediate-chain
287
- * charge needs to know whether the connected account holds gas on a chain in
288
- * the middle of the plan — a live wallet balance read `RoutePlan` has no way
289
- * to name. Applying it here would require guessing, which this comparator
290
- * refuses to do; `GAS_TOPUP_PENALTY_PPM` is still applied wherever a caller
291
- * has that balance and reaches for `scoreRoutePlan` directly (`plan-route-data.ts`
292
- * onward). Left as an OWNER DECISION whether a structural ranking site should
293
- * ever get gas-balance context of its own.
294
- *
295
- * @param a - one plan being compared
296
- * @param b - the other
297
- * @returns negative when `a` ranks ahead of `b`, positive when `b` ranks
298
- * ahead of `a`, zero when they tie
299
- */
300
27
  export const compareRoutePlansByScoreAdjustedDeliveredAmount = (a, b) => {
301
28
  const rankableA = planIsRankable(a.hops);
302
29
  const rankableB = planIsRankable(b.hops);
@@ -325,33 +52,7 @@ export const scoreRoutePlan = (inputs) => {
325
52
  totalSignaturePenaltyUsd -
326
53
  totalGasTopUpPenaltyUsd);
327
54
  };
328
- /**
329
- * A PLACEHOLDER {@link GasCostFor} that charges nothing — preserves the
330
- * behaviour of ranking on raw delivered amount for a caller that has not yet
331
- * wired a real gas-price and native-price source. NOT A PRODUCTION DEFAULT:
332
- * unlike {@link WAIT_PENALTY_PPM_PER_MINUTE}'s two logged, live crossings, no
333
- * per-chain gas figure here would be a measurement — it would be a guess
334
- * dressed up as one, exactly what Rule 13 of this codebase's own working
335
- * principles warns against. A host should always supply its own
336
- * {@link GasCostFor} once it has gas-price and native-price feeds to build
337
- * one from; this export exists only so `waves.ts`'s own default comparator
338
- * has something total to call when nobody has.
339
- */
340
55
  export const zeroGasCostFor = () => ({ gasAmount: 0n, refuelAmount: 0n });
341
- /**
342
- * Whether the section at `sectionIndex` starts with native coin already in
343
- * the reader's hand: the hop that ends the PREVIOUS section delivers the
344
- * chain's native coin, so the reader arrives holding gas for this section's
345
- * own signature and needs no top-up there, whatever their balance was.
346
- *
347
- * Always false for the first section — nothing lands before it, so its gas
348
- * can only come from the reader's own balance.
349
- *
350
- * @param plan - the plan the section belongs to
351
- * @param sectionIndex - 0-based index into `plan.signatures`
352
- * @returns true when the previous section lands native coin on this
353
- * section's chain
354
- */
355
56
  export const sectionIsFundedByLanding = (plan, sectionIndex) => {
356
57
  if (sectionIndex < 1)
357
58
  return false;
@@ -361,20 +62,6 @@ export const sectionIsFundedByLanding = (plan, sectionIndex) => {
361
62
  return false;
362
63
  return isNativeAsset(landingHop.edge.to.address, landingHop.edge.to.ecosystem);
363
64
  };
364
- /**
365
- * `plan`'s last-hop `deliveredAmount`, minus the REAL cost of every
366
- * signature it needs — `gasCostFor` charged ONCE per signature group
367
- * (`plan.signatures`, built by `groupHopsBySignature`), on the chain and
368
- * carrier of that group's FIRST hop, which is the hop the reader actually
369
- * signs (or deposits by hand) for that group. A group's refuel cost is
370
- * dropped when the previous group lands native coin
371
- * ({@link sectionIsFundedByLanding}). Floored at zero: a plan whose
372
- * gas costs exceed its own delivered amount is worth nothing, never negative.
373
- *
374
- * @param plan - the plan to charge
375
- * @param gasCostFor - supplies each signature's real cost; see {@link GasCostFor}
376
- * @returns the gas-adjusted delivered amount, in the plan's destination token's base units
377
- */
378
65
  export const gasAdjustedDeliveredAmount = (plan, gasCostFor) => {
379
66
  const deliveredAmount = plan.hops[plan.hops.length - 1]?.outcome.deliveredAmount ?? 0n;
380
67
  const totalGasCost = plan.signatures.reduce((total, group, sectionIndex) => {
@@ -389,32 +76,6 @@ export const gasAdjustedDeliveredAmount = (plan, gasCostFor) => {
389
76
  const netAmount = deliveredAmount - totalGasCost;
390
77
  return netAmount < 0n ? 0n : netAmount;
391
78
  };
392
- /**
393
- * Orders two plans by {@link gasAdjustedDeliveredAmount} rather than raw
394
- * `deliveredAmount` or {@link signaturePenaltyAdjustedDeliveredAmount}'s flat
395
- * ppm guess — the structural ranking `waves.ts` uses once Round A/B have real
396
- * gas data to charge, replacing {@link SIGNATURE_PENALTY_PPM}/
397
- * {@link GAS_TOPUP_PENALTY_PPM} at that one site per the owner's own
398
- * instruction (see both constants' updated docs). A CURRIED FACTORY, not a
399
- * plain comparator, because the real cost this needs — {@link GasCostFor} —
400
- * is caller-supplied and cannot be a module-level default the way
401
- * {@link compareRoutePlansByScoreAdjustedDeliveredAmount} is; call it once
402
- * per search with the caller's own `gasCostFor`, then pass the returned
403
- * comparator wherever a plan-to-plan comparison is needed.
404
- *
405
- * KEEPS THE SAME RANKABLE-BEFORE-UNRANKABLE RULE `compareRoutePlansByScoreAdjustedDeliveredAmount`
406
- * ALREADY APPLIES, unchanged, including its `compareRoutePlansByDeliveredAmount`
407
- * tiebreak among two unrankable plans — only the tiebreak among two RANKABLE
408
- * plans changes, from a proportional signature-count discount to the route's
409
- * own real charges.
410
- *
411
- * @param gasCostFor - supplies each signature's real cost; see {@link GasCostFor}
412
- * TIE-BREAK: when the gas-adjusted amounts are equal, the plan with fewer
413
- * signatures ranks first.
414
- *
415
- * @returns a comparator: negative when `a` ranks ahead of `b`, positive when
416
- * `b` ranks ahead of `a`, zero when they tie
417
- */
418
79
  export const compareRoutePlansByGasAdjustedDeliveredAmount = (gasCostFor) => (a, b) => {
419
80
  const rankableA = planIsRankable(a.hops);
420
81
  const rankableB = planIsRankable(b.hops);
@@ -426,10 +87,5 @@ export const compareRoutePlansByGasAdjustedDeliveredAmount = (gasCostFor) => (a,
426
87
  const adjustedB = gasAdjustedDeliveredAmount(b, gasCostFor);
427
88
  if (adjustedA !== adjustedB)
428
89
  return adjustedA > adjustedB ? -1 : 1;
429
- // EQUAL FIGURES: FEWER SIGNATURES RANKS FIRST. Two plans that deliver the
430
- // same amount cost the reader different effort — each signature is one more
431
- // wallet prompt. Without this the stable sort kept the depth-first walk
432
- // order, so a three-signature plan could be selected over a two-signature
433
- // plan showing the same figure.
434
90
  return a.signatures.length - b.signatures.length;
435
91
  };
@@ -2,50 +2,7 @@ import { encodeFunctionData, isAddressEqual, parseAbi, zeroAddress } from 'viem'
2
2
  import { pulseXSwapTransactionInputs } from '../settings.js';
3
3
  import { defaultSwapVenues } from '../config.js';
4
4
  import { pulseXSwapPathForHop, venueForEdge } from './carriers/pulsex.js';
5
- /**
6
- * The minimal WETH9-style wrap/unwrap interface: `deposit()` mints the
7
- * wrapped token for the native coin sent with the call, `withdraw(uint256)`
8
- * burns wrapped balance and returns native coin. Every wrapped-native
9
- * contract this application bridges to exposes exactly this pair — see
10
- * `carriers/wrap.ts`, whose own doc records the selectors as confirmed
11
- * present on WPLS by bytecode inspection (2026-09-24). Kept local rather than
12
- * added to `@gibs/abis`: the interface is two standard, unchanging selectors
13
- * rather than a contract-specific ABI.
14
- */
15
5
  const wrapAbi = parseAbi(['function deposit() payable', 'function withdraw(uint256 amount)']);
16
- /**
17
- * Builds a same-chain PulseX swap transaction for one planned route-search
18
- * hop. The interface's section signing (`packages/ui` `state/sectionSigning.ts`)
19
- * and the SDK's execution planner (`execution.ts`) both call it, so there is
20
- * exactly one place that turns "swap this hop" into calldata.
21
- *
22
- * SIGNS THE PATH THE HOP WAS PRICED ON. The PulseX carrier picks the best of
23
- * many paths through its hub tokens and records the winner on the hop's
24
- * outcome; `pulseXSwapPathForHop` (`carriers/pulsex.ts`) reads it back
25
- * and checks it fits the hop's edge. This never rebuilds a path: a rebuilt
26
- * path is a quote on one route and a signature on another. A hop that
27
- * records no path is refused. REUSES `pulseXSwapTransactionInputs` (`settings.ts`)
28
- * for the encoding, never re-implements it: that function already carries the
29
- * `swapRefusal` guard (refuses to build a call for a leg the screen is not
30
- * looking at) and the native-in/native-out/token-token branching.
31
- *
32
- * SIGNS ON THE EDGE'S OWN ROUTER. A PulseX edge names the deployment it was
33
- * quoted on (`venueForEdge`: V1 or V2, each with its own pools). The
34
- * caller's `routerAddress` must be that same router — it is also the router
35
- * the caller approved to spend the input token — or nothing is built. A V2
36
- * quote signed on V1 would trade against a different pool than the one the
37
- * reader was shown.
38
- *
39
- * @param options - the hop to swap, the amount and slippage-adjusted
40
- * minimum, who receives the output, the signing deadline, what the caller
41
- * believes this signature does (`signedLeg`), the chain it executes on, the
42
- * resolved router address, and the swap venues the router must belong to
43
- * (the defaults when omitted)
44
- * @returns the swap transaction inputs, or null when the hop records no
45
- * PulseX swap path, names no known router, `routerAddress` is not the
46
- * edge's own router, the leg on screen disagrees, or any of
47
- * `pulseXSwapTransactionInputs`'s own preconditions are unmet
48
- */
49
6
  export const buildPulseXSwapTransaction = (options) => {
50
7
  const { hop, amountIn, minAmountOut, recipient, deadline, signedLeg, chainId, routerAddress } = options;
51
8
  const { edge } = hop;
@@ -70,25 +27,6 @@ export const buildPulseXSwapTransaction = (options) => {
70
27
  deadline,
71
28
  });
72
29
  };
73
- /**
74
- * Builds a native-coin wrap/unwrap transaction for one route-search graph
75
- * edge — PLS<->WPLS on PulseChain, ETH<->WETH on Ethereum, or the same pair
76
- * on any other chain `config.ts`'s `nativeAssetOut` names one for.
77
- *
78
- * A WRAP IS NOT A SWAP CALL. There is no PulseX pool for native-versus-wrapped
79
- * — see `routing/carriers/wrap.ts`'s own doc — so this never touches the
80
- * PulseX router: wrapping sends `amountIn` native coin to the wrapped token's
81
- * own `deposit()`; unwrapping calls `withdraw(amountIn)` on it with zero
82
- * value. The `edge` names which direction: its `from`/`to` addresses are
83
- * checked against the zero-address sentinel, never assumed from a caller
84
- * flag, so a swapped/malformed edge is refused rather than guessed at.
85
- *
86
- * @param options - the edge to wrap or unwrap, and the amount in the SOURCE
87
- * token's base units (native units wrapping, wrapped units unwrapping —
88
- * native and wrapped share decimals on every chain this carrier covers)
89
- * @returns the wrap/unwrap transaction inputs, or null when `amountIn` is not
90
- * positive or the edge is not exactly one native/wrapped pair
91
- */
92
30
  export const buildWrapTransaction = (options) => {
93
31
  const { edge, amountIn } = options;
94
32
  if (amountIn <= 0n) {
@@ -96,8 +34,6 @@ export const buildWrapTransaction = (options) => {
96
34
  }
97
35
  const fromIsNative = edge.from.address.toLowerCase() === zeroAddress;
98
36
  const toIsNative = edge.to.address.toLowerCase() === zeroAddress;
99
- // Exactly one side must be the native sentinel — a token/token pair, or a
100
- // native/native no-op, is not a wrap edge at all.
101
37
  if (fromIsNative === toIsNative) {
102
38
  return null;
103
39
  }
@@ -114,14 +50,4 @@ export const buildWrapTransaction = (options) => {
114
50
  data: encodeFunctionData({ abi: wrapAbi, functionName: 'withdraw', args: [amountIn] }),
115
51
  };
116
52
  };
117
- /**
118
- * The slippage floor a swap signs: the quoted output less the slippage
119
- * allowance, rounded down. The interface's engine signing and the SDK's
120
- * execution planner both read it, so the two never sign different floors for
121
- * the same quote.
122
- *
123
- * @param options.quotedAmount - the hop's quoted output, in the output token's base units
124
- * @param options.slippageBasisPoints - the allowance, in basis points (100 is 1%)
125
- * @returns the minimum output the swap accepts
126
- */
127
53
  export const swapMinimumOut = ({ quotedAmount, slippageBasisPoints, }) => (quotedAmount * (10000n - slippageBasisPoints)) / 10000n;
@@ -1,16 +1,4 @@
1
1
  import { formatUnits } from 'viem';
2
- /**
3
- * The United States dollar value of a base-unit token amount at a given price, as
4
- * a NUMBER — the numeric core of the user interface's `formatFiatValue` without the
5
- * currency string. Returns null when the token is unpriced (`price` is null) or the
6
- * computed value is not finite, mirroring the "return null for invalid state"
7
- * convention so callers can fall back.
8
- *
9
- * @param params.balance - the amount in base units
10
- * @param params.decimals - the token's decimals
11
- * @param params.price - the token's United States dollar price, or null when unpriced
12
- * @returns the dollar value as a number, or null
13
- */
14
2
  export const usdValueOfAmount = (params) => {
15
3
  const { balance, decimals, price } = params;
16
4
  if (price === null)