@gibs/bridge-sdk 1.12.0 → 1.13.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 (117) hide show
  1. package/LICENSE +15 -0
  2. package/README.md +234 -432
  3. package/dist/abis.d.ts +1 -0
  4. package/dist/bridge-limits.d.ts +103 -0
  5. package/dist/bridge-limits.js +84 -0
  6. package/dist/chain-info.d.ts +169 -0
  7. package/dist/chain-info.js +410 -0
  8. package/dist/chain-names.d.ts +160 -0
  9. package/dist/chain-names.js +200 -0
  10. package/dist/chains.d.ts +65 -0
  11. package/dist/chains.js +284 -0
  12. package/dist/config.d.ts +216 -0
  13. package/dist/config.js +493 -0
  14. package/dist/consolidated-quote.d.ts +554 -0
  15. package/dist/consolidated-quote.js +773 -0
  16. package/dist/destination-calldata.d.ts +118 -0
  17. package/dist/destination-calldata.js +152 -0
  18. package/dist/ecosystems.d.ts +217 -0
  19. package/dist/ecosystems.js +288 -0
  20. package/dist/fee-type.d.ts +10 -0
  21. package/dist/fee-type.js +9 -0
  22. package/dist/hyperliquid-execution.d.ts +152 -0
  23. package/dist/hyperliquid-execution.js +168 -0
  24. package/dist/image-links.d.ts +117 -0
  25. package/dist/image-links.js +142 -0
  26. package/dist/index.d.ts +20 -0
  27. package/dist/index.js +20 -0
  28. package/dist/lifi-execution-guard.d.ts +199 -0
  29. package/dist/lifi-execution-guard.js +400 -0
  30. package/dist/near-intents-conformance.d.ts +85 -0
  31. package/dist/near-intents-conformance.js +329 -0
  32. package/dist/near-intents-route.d.ts +47 -0
  33. package/dist/near-intents-route.js +265 -0
  34. package/dist/near-intents.d.ts +524 -0
  35. package/dist/near-intents.js +1055 -0
  36. package/dist/origin-deposit.d.ts +326 -0
  37. package/dist/origin-deposit.js +68 -0
  38. package/dist/pre-quote.d.ts +198 -0
  39. package/dist/pre-quote.js +175 -0
  40. package/dist/prices.d.ts +107 -0
  41. package/dist/prices.js +162 -0
  42. package/dist/providers.d.ts +221 -0
  43. package/dist/providers.js +157 -0
  44. package/dist/quote-fees.d.ts +102 -0
  45. package/dist/quote-fees.js +195 -0
  46. package/dist/referral.d.ts +77 -0
  47. package/dist/referral.js +72 -0
  48. package/dist/relay-currencies.d.ts +47 -0
  49. package/dist/relay-currencies.js +89 -0
  50. package/dist/relay-quote.d.ts +301 -0
  51. package/dist/relay-quote.js +983 -0
  52. package/dist/route-steps.d.ts +138 -0
  53. package/dist/route-steps.js +305 -0
  54. package/dist/routing/amounts.d.ts +80 -0
  55. package/dist/routing/amounts.js +120 -0
  56. package/dist/routing/candidate-route.d.ts +43 -0
  57. package/dist/routing/candidate-route.js +45 -0
  58. package/dist/routing/candidate.d.ts +237 -0
  59. package/dist/routing/candidate.js +96 -0
  60. package/dist/routing/carriers/ask-answer.d.ts +58 -0
  61. package/dist/routing/carriers/ask-answer.js +1 -0
  62. package/dist/routing/carriers/omnibridge.d.ts +137 -0
  63. package/dist/routing/carriers/omnibridge.js +419 -0
  64. package/dist/routing/carriers/pulsex.d.ts +111 -0
  65. package/dist/routing/carriers/pulsex.js +404 -0
  66. package/dist/routing/carriers/wrap.d.ts +25 -0
  67. package/dist/routing/carriers/wrap.js +115 -0
  68. package/dist/routing/composed-route-quality.d.ts +103 -0
  69. package/dist/routing/composed-route-quality.js +108 -0
  70. package/dist/routing/entry-chain-anchor.d.ts +88 -0
  71. package/dist/routing/entry-chain-anchor.js +55 -0
  72. package/dist/routing/format.d.ts +31 -0
  73. package/dist/routing/format.js +58 -0
  74. package/dist/routing/index.d.ts +34 -0
  75. package/dist/routing/index.js +42 -0
  76. package/dist/routing/producers.d.ts +770 -0
  77. package/dist/routing/producers.js +1564 -0
  78. package/dist/routing/providers.d.ts +26 -0
  79. package/dist/routing/providers.js +38 -0
  80. package/dist/routing/route-data.d.ts +355 -0
  81. package/dist/routing/route-data.js +1 -0
  82. package/dist/routing/search/compose.d.ts +168 -0
  83. package/dist/routing/search/compose.js +98 -0
  84. package/dist/routing/search/graph.d.ts +639 -0
  85. package/dist/routing/search/graph.js +445 -0
  86. package/dist/routing/search/plan-route-data.d.ts +244 -0
  87. package/dist/routing/search/plan-route-data.js +767 -0
  88. package/dist/routing/search/score.d.ts +324 -0
  89. package/dist/routing/search/score.js +400 -0
  90. package/dist/routing/usd-value.d.ts +17 -0
  91. package/dist/routing/usd-value.js +25 -0
  92. package/dist/settings.d.ts +692 -0
  93. package/dist/settings.js +909 -0
  94. package/dist/ton-execution.d.ts +117 -0
  95. package/dist/ton-execution.js +247 -0
  96. package/dist/tron-execution.d.ts +146 -0
  97. package/dist/tron-execution.js +239 -0
  98. package/dist/types.d.ts +51 -0
  99. package/dist/types.js +1 -0
  100. package/package.json +203 -23
  101. package/src/chain-info.test.ts +0 -968
  102. package/src/chain-info.ts +0 -498
  103. package/src/chains.test.ts +0 -123
  104. package/src/chains.ts +0 -88
  105. package/src/config.test.ts +0 -679
  106. package/src/config.ts +0 -500
  107. package/src/fee-type.test.ts +0 -45
  108. package/src/fee-type.ts +0 -14
  109. package/src/image-links.test.ts +0 -160
  110. package/src/image-links.ts +0 -65
  111. package/src/index.ts +0 -8
  112. package/src/settings.test.ts +0 -2754
  113. package/src/settings.ts +0 -875
  114. package/src/types.ts +0 -48
  115. package/tsconfig.json +0 -17
  116. package/vitest.config.ts +0 -13
  117. /package/{src/abis.ts → dist/abis.js} +0 -0
@@ -0,0 +1,118 @@
1
+ import { type Hex } from 'viem';
2
+ import type { TokenBridgeInfo } from './chain-info.js';
3
+ import type { Pathway } from './config.js';
4
+ import type { Token } from './types.js';
5
+ /**
6
+ * The shape of a call an external executor (an aggregator's destination-chain
7
+ * contract, e.g. LI.FI's executor or Relay's solver) must perform to push
8
+ * bridged funds into the omnibridge toward the home chain.
9
+ */
10
+ export type DestinationCall = {
11
+ /** Contract the executor calls (mediator, native router, or the token itself) */
12
+ to: Hex;
13
+ /** Native value to attach to the call (non-zero only for native-asset entry) */
14
+ value: bigint;
15
+ /** Encoded calldata for the call */
16
+ data: Hex;
17
+ /**
18
+ * Contract that must hold an ERC20 approval from the executor before the
19
+ * call, or null when no approval is needed (native value transfers and
20
+ * ERC677 transferAndCall, which moves tokens itself)
21
+ */
22
+ approvalTarget: Hex | null;
23
+ /**
24
+ * The mediator that validates the amount and emits the bridge message.
25
+ *
26
+ * NOT THE SAME AS `to`, and that is the point. `to` is whatever the executor
27
+ * calls — the mediator for an ordinary token, the router for a native asset,
28
+ * the token itself for an ERC677 transfer — but all three funnel into this
29
+ * one contract, and this is the contract whose limits decide whether the
30
+ * transfer happens at all. Proved by experiment on a fork: raising its
31
+ * `minPerTx` alone, with the far side untouched, reverts the entry call.
32
+ */
33
+ entryMediator: Hex;
34
+ /**
35
+ * The address the mediator keys its per-token limits by.
36
+ *
37
+ * For a native asset this is the WRAPPED address, because the router wraps
38
+ * before the mediator sees anything. Reading limits under the zero address
39
+ * instead returns the mediator's fallback default, which is a real number
40
+ * for a different question.
41
+ */
42
+ entryTokenAddress: Hex;
43
+ /** Conservative gas budget for executing the call on the destination chain */
44
+ gasLimit: bigint;
45
+ };
46
+ /**
47
+ * Conservative per-shape gas budgets for omnibridge entry calls executed by an
48
+ * aggregator on the destination chain. An undershoot reverts the executor's
49
+ * call and strands funds at the aggregator's fallback address, so these err
50
+ * high; the aggregator prices unused gas into the quote rather than burning it.
51
+ *
52
+ * MEASURED against the deployed mediators on a fork of Ethereum mainnet,
53
+ * 2026-08-31, by `destination-calldata.fork.test.ts`:
54
+ *
55
+ * relayTokens 195,967 USD Coin, an ordinary registered token
56
+ * wrapAndRelayTokens 200,347 native ether through the router
57
+ * transferAndCall 187,000 wrapped Pulse, a bridged representation home
58
+ * to 204,000, depending on the fork block
59
+ *
60
+ * The figures move with block state — whether a storage slot the call touches
61
+ * is already warm — so treat them as a band, not a constant. The spread
62
+ * measured across two blocks minutes apart was about nine percent.
63
+ *
64
+ * THE BUDGET STAYS AT 400,000, and the headroom is deliberate. Every figure
65
+ * above is a token the bridge has carried before. The first crossing of a
66
+ * token the mediator has not seen writes its limits as well, and a token with
67
+ * a transfer hook costs more again — neither is measured here, and both fail
68
+ * by stranding the user's funds rather than by costing us a little gas. The
69
+ * fork test asserts each shape stays under the budget, so a regression that
70
+ * eats the headroom fails a test rather than a transfer.
71
+ */
72
+ export declare const destinationGasLimits: {
73
+ readonly relayTokens: 400000n;
74
+ readonly transferAndCall: 400000n;
75
+ readonly wrapAndRelayTokens: 400000n;
76
+ };
77
+ /**
78
+ * Builds the call an aggregator's executor must perform on the bridge's
79
+ * foreign chain (e.g. Ethereum) to relay just-bridged funds onward through the
80
+ * omnibridge to the recipient on the home chain (e.g. PulseChain).
81
+ *
82
+ * This is the second leg of a consolidated route: the aggregator bridges the
83
+ * user's funds to the foreign chain with a guaranteed minimum amount, then its
84
+ * executor performs this call. Because the executor — not the user — is the
85
+ * caller, the result always encodes the fixed `amount` and names the user as
86
+ * `recipient`; delivery-fee encoding never applies (home-chain gas handout is
87
+ * a separate automatic system).
88
+ *
89
+ * @param pathway - the bridge pathway whose foreign side the executor enters
90
+ * @param assetIn - the foreign-chain token the aggregator delivers (zero address for native)
91
+ * @param recipient - the user's address on the home chain
92
+ * @param sender - the user's address, threaded through pathways that take an extra sender param
93
+ * @param assetLink - the asset link for the token, used to detect bridged representations
94
+ * @param amount - the exact token amount the executor will relay
95
+ * @returns the destination call, or null when the inputs cannot form a valid call
96
+ */
97
+ export declare const buildDestinationCalldata: ({ pathway, assetIn, recipient, sender, assetLink, amount, unwrap, }: {
98
+ pathway: Pathway | null;
99
+ assetIn: Token | null;
100
+ recipient: Hex | null;
101
+ sender: Hex | null;
102
+ assetLink: TokenBridgeInfo | null;
103
+ amount: bigint;
104
+ /**
105
+ * Deliver the chain's own coin rather than its wrapped token.
106
+ *
107
+ * ONLY ONE INPUT PER PATHWAY CAN DO THIS: the pathway's own
108
+ * `bridgedNativeAssetOut`, which is the wrapped native asset of the chain the
109
+ * funds are heading TO, held on the chain they leave from. Wrapped Pulse on
110
+ * Ethereum is the case that matters here — it arrives as wrapped Pulse on
111
+ * PulseChain, and the destination router turns that into native Pulse.
112
+ *
113
+ * Asked for on any other token it is IGNORED rather than obeyed, because the
114
+ * bridge would ignore it too and a call built as though it would not is a
115
+ * call that does something different from what the caller believes.
116
+ */
117
+ unwrap?: boolean;
118
+ }) => DestinationCall | null;
@@ -0,0 +1,152 @@
1
+ import { getAddress } from 'viem';
2
+ import { destinationDataParam, interactingWithBridgeToken, transactionInputs, } from './settings.js';
3
+ /**
4
+ * Conservative per-shape gas budgets for omnibridge entry calls executed by an
5
+ * aggregator on the destination chain. An undershoot reverts the executor's
6
+ * call and strands funds at the aggregator's fallback address, so these err
7
+ * high; the aggregator prices unused gas into the quote rather than burning it.
8
+ *
9
+ * MEASURED against the deployed mediators on a fork of Ethereum mainnet,
10
+ * 2026-08-31, by `destination-calldata.fork.test.ts`:
11
+ *
12
+ * relayTokens 195,967 USD Coin, an ordinary registered token
13
+ * wrapAndRelayTokens 200,347 native ether through the router
14
+ * transferAndCall 187,000 wrapped Pulse, a bridged representation home
15
+ * to 204,000, depending on the fork block
16
+ *
17
+ * The figures move with block state — whether a storage slot the call touches
18
+ * is already warm — so treat them as a band, not a constant. The spread
19
+ * measured across two blocks minutes apart was about nine percent.
20
+ *
21
+ * THE BUDGET STAYS AT 400,000, and the headroom is deliberate. Every figure
22
+ * above is a token the bridge has carried before. The first crossing of a
23
+ * token the mediator has not seen writes its limits as well, and a token with
24
+ * a transfer hook costs more again — neither is measured here, and both fail
25
+ * by stranding the user's funds rather than by costing us a little gas. The
26
+ * fork test asserts each shape stays under the budget, so a regression that
27
+ * eats the headroom fails a test rather than a transfer.
28
+ */
29
+ export const destinationGasLimits = {
30
+ relayTokens: 400000n,
31
+ transferAndCall: 400000n,
32
+ wrapAndRelayTokens: 400000n,
33
+ };
34
+ /**
35
+ * Builds the call an aggregator's executor must perform on the bridge's
36
+ * foreign chain (e.g. Ethereum) to relay just-bridged funds onward through the
37
+ * omnibridge to the recipient on the home chain (e.g. PulseChain).
38
+ *
39
+ * This is the second leg of a consolidated route: the aggregator bridges the
40
+ * user's funds to the foreign chain with a guaranteed minimum amount, then its
41
+ * executor performs this call. Because the executor — not the user — is the
42
+ * caller, the result always encodes the fixed `amount` and names the user as
43
+ * `recipient`; delivery-fee encoding never applies (home-chain gas handout is
44
+ * a separate automatic system).
45
+ *
46
+ * @param pathway - the bridge pathway whose foreign side the executor enters
47
+ * @param assetIn - the foreign-chain token the aggregator delivers (zero address for native)
48
+ * @param recipient - the user's address on the home chain
49
+ * @param sender - the user's address, threaded through pathways that take an extra sender param
50
+ * @param assetLink - the asset link for the token, used to detect bridged representations
51
+ * @param amount - the exact token amount the executor will relay
52
+ * @returns the destination call, or null when the inputs cannot form a valid call
53
+ */
54
+ export const buildDestinationCalldata = ({ pathway, assetIn, recipient, sender, assetLink, amount, unwrap = false, }) => {
55
+ if (amount <= 0n) {
56
+ return null;
57
+ }
58
+ // `transactionInputs` rejects both of these too, but it cannot say so to the
59
+ // type checker, and the entry fields below are read straight off them. Asking
60
+ // first keeps the answer honest rather than asserted.
61
+ if (!pathway || !assetLink) {
62
+ return null;
63
+ }
64
+ // THE UNWRAP RIDES THE DATA PARAMETER, which is the same slot the recipient
65
+ // travels in. Naming the destination router there and the recipient after it
66
+ // tells the home mediator to hand the arriving tokens to the router, which
67
+ // unwraps them and forwards the coin on. `destinationDataParam` owns that
68
+ // encoding for the direct path already, so it owns it here too rather than
69
+ // being restated.
70
+ //
71
+ // The gate is the pathway's own bridged native asset. Anything else arrives
72
+ // wrapped whatever the caller asked for, so obeying the request would build a
73
+ // call that does something other than what the caller believes it does.
74
+ const unwrapOnArrival = unwrap &&
75
+ assetIn !== null &&
76
+ pathway.destinationRouter !== null &&
77
+ getAddress(assetIn.address) === getAddress(pathway.bridgedNativeAssetOut);
78
+ const destinationData = unwrapOnArrival
79
+ ? destinationDataParam({
80
+ recipient,
81
+ bridgePathway: pathway,
82
+ assetIn,
83
+ destinationRouter: pathway.destinationRouter,
84
+ feeDirectorStructEncoded: null,
85
+ assetLink,
86
+ shouldDeliver: false,
87
+ unwrap: true,
88
+ })
89
+ : recipient;
90
+ // Only reachable when the unwrap was asked for and could not be encoded.
91
+ // Falling back to a plain recipient would quietly deliver the wrapped token.
92
+ if (destinationData === null) {
93
+ return null;
94
+ }
95
+ const inputs = transactionInputs({
96
+ // NO READER COMPOSED THIS CALL, so there is no pair on screen for it to
97
+ // disagree with. An aggregator's executor performs it on the entry chain
98
+ // after the reader has already signed their own transaction, and the chain
99
+ // pair IS this pathway. See `crossingRefusal` for why the field is nullable
100
+ // rather than optional: every caller has to say which of the two it is.
101
+ bridgeKey: null,
102
+ signedCrossing: null,
103
+ bridgePathway: pathway,
104
+ assetIn,
105
+ recipient,
106
+ account: sender,
107
+ assetLink,
108
+ // for bridged tokens the data param rides transferAndCall and the
109
+ // mediator decodes it as the home-chain recipient
110
+ destinationDataParam: destinationData,
111
+ amountToBridge: amount,
112
+ feeDirectorStructEncoded: null,
113
+ shouldDeliver: false,
114
+ });
115
+ if (!inputs) {
116
+ return null;
117
+ }
118
+ const isNativeEntry = inputs.value > 0n;
119
+ const isBridgeTokenEntry = interactingWithBridgeToken({
120
+ assetLink,
121
+ assetInAddress: assetIn?.address ?? null,
122
+ });
123
+ // Both are the same for every shape: the pathway's own mediator, and the
124
+ // on-chain address the link resolved (already the wrapped one for a native
125
+ // asset, because `tokenBridgeInfo` substitutes it before looking anything up).
126
+ const entry = {
127
+ entryMediator: pathway.from,
128
+ entryTokenAddress: assetLink.assetInAddress,
129
+ };
130
+ if (isNativeEntry) {
131
+ return {
132
+ ...inputs,
133
+ ...entry,
134
+ approvalTarget: null,
135
+ gasLimit: destinationGasLimits.wrapAndRelayTokens,
136
+ };
137
+ }
138
+ if (isBridgeTokenEntry) {
139
+ return {
140
+ ...inputs,
141
+ ...entry,
142
+ approvalTarget: null,
143
+ gasLimit: destinationGasLimits.transferAndCall,
144
+ };
145
+ }
146
+ return {
147
+ ...inputs,
148
+ ...entry,
149
+ approvalTarget: inputs.to,
150
+ gasLimit: destinationGasLimits.relayTokens,
151
+ };
152
+ };
@@ -0,0 +1,217 @@
1
+ /**
2
+ * A source-chain virtual-machine family the bridge can originate a route from.
3
+ * This is deliberately the `id` of a descriptor in {@link ecosystemRegistry},
4
+ * not a hand-maintained parallel union: code that needs ecosystem behavior looks
5
+ * the record up instead of branching on the literal, so adding an ecosystem is
6
+ * one new descriptor and every reader keeps working.
7
+ *
8
+ * The identifiers match the `vmType` strings Relay reports at
9
+ * https://api.relay.link/chains, so a Relay chain record maps onto an ecosystem
10
+ * without a translation table.
11
+ *
12
+ * Quoting an origin is not the same as being able to SIGN one: the ecosystem
13
+ * registry is the library-side model, while the wallet adapter that produces a
14
+ * signature lives in the interface package. Every ecosystem listed here now has
15
+ * an adapter in this repository's interface, so the two are in step — but the
16
+ * distinction stands for whatever is added next, and an interface that lacks an
17
+ * adapter must still reject that origin rather than route it to a signer meant
18
+ * for another ecosystem.
19
+ *
20
+ * ONE IDENTIFIER HERE IS NOT A RELAY NAME, and that is deliberate rather than
21
+ * an oversight: `zcash`. Relay does not carry Zcash in any form, so there is no
22
+ * `vmType` string to match and inventing one shaped like the others would imply
23
+ * a mapping that does not exist. It is also the one family this interface can
24
+ * never SIGN for — see the note above, and `isDepositAddressChain` in
25
+ * `chain-names.ts`, which is the predicate a surface actually asks.
26
+ */
27
+ export type Ecosystem = 'evm' | 'svm' | 'bvm' | 'tvm' | 'tonvm' | 'hypevm' | 'zcash';
28
+ /**
29
+ * Whether anyone has carried a transfer through this ecosystem from end to
30
+ * end — connected a wallet, signed the deposit, watched the funds arrive — on
31
+ * a build a reader can reach.
32
+ *
33
+ * THIS IS A RECORD OF PROOF, NOT A SWITCH. Read the name literally: `pending`
34
+ * says the proof has not been obtained yet, and says nothing at all about
35
+ * whether the code works. Every ecosystem here is modelled, quoted and wired
36
+ * to a signer; several have unit tests over real fixtures. None of that is the
37
+ * same as one funded transfer completing, and this field records only the
38
+ * latter. So a `pending` ecosystem is a TEMPORARY HOLD on a public claim, and
39
+ * the way to clear it is to make the transfer and change the word — not to
40
+ * delete the descriptor, and not to write code around it.
41
+ *
42
+ * It exists because the landing page advertises where a transfer can start
43
+ * from, and an advertised origin that has never been proven is a promise the
44
+ * product has not earned.
45
+ *
46
+ * WHAT A `pending` ANSWER MAKES THE INTERFACE DO, and this is the part that was
47
+ * got wrong once and corrected by the owner: it QUALIFIES an entry, it does not
48
+ * remove one. A chain drawn quietly — a dashed edge, a desaturated mark, no
49
+ * caption — tells a reader the truth without a promise attached to it. A
50
+ * chain deleted from the list tells them it is not part of this product,
51
+ * which is a stronger claim than this field carries and a false one. The
52
+ * treatment used to spell the hold out in words ("not proven yet"), and the
53
+ * owner corrected that too: the state is now carried visually, plus
54
+ * `aria-disabled` for a reader who cannot see the desaturation, with no
55
+ * caption of its own. See `reelTokenProof` and `chainProof` in the interface
56
+ * — the reel and the chain chips — which turn this answer into a treatment
57
+ * rather than a filter.
58
+ *
59
+ * IT IS NOT THE ONLY REASON AN ORIGIN CAN BE ABSENT. Hyperliquid is `pending`
60
+ * here and still appears nowhere, because nothing can quote it: the interface's
61
+ * source picker never offers it, so there is no route to draw quietly. A gate on
62
+ * proof and a gate on reachability are different questions, and only this one
63
+ * belongs in this field.
64
+ */
65
+ export type EndToEndProof = 'verified' | 'pending';
66
+ /**
67
+ * Everything intrinsic to one ecosystem, in one record. Carries only
68
+ * framework-agnostic knowledge — nothing about the user interface, wallet
69
+ * adapters, or providers — so it can live in the library.
70
+ */
71
+ export type EcosystemDescriptor = {
72
+ /** The stable key; equals the literal used everywhere else. */
73
+ id: Ecosystem;
74
+ /** Fully spelled-out display name. */
75
+ label: string;
76
+ /**
77
+ * The chain-agnostic identifier namespace (the leading segment of a
78
+ * "namespace:reference:address" identifier). Used to map a connected wallet
79
+ * identifier back to its ecosystem.
80
+ */
81
+ caipNamespace: string;
82
+ /**
83
+ * How this ecosystem expresses its native asset as an address string. Kept
84
+ * byte-equal to the values the Relay request builder currently sends.
85
+ */
86
+ nativeAssetSentinel: string;
87
+ /**
88
+ * Whether a transfer has been carried through this ecosystem end to end. See
89
+ * {@link EndToEndProof} — `pending` is a hold on a public claim, never a
90
+ * statement that the path is broken.
91
+ *
92
+ * Held HERE, beside the ecosystem it describes, so re-enabling one is a
93
+ * single word next to that ecosystem rather than a hunt for an exclusion
94
+ * list in a component.
95
+ */
96
+ endToEndProof: EndToEndProof;
97
+ /** Pure format check: does this look like a valid address in this ecosystem? */
98
+ isValidAddress: (value: string) => boolean;
99
+ /**
100
+ * Pure normalization to the ecosystem's canonical form. Ethereum applies the
101
+ * checksum; the already-case-significant encodings are identity.
102
+ */
103
+ normalizeAddress: (value: string) => string;
104
+ /**
105
+ * Whether two addresses in this ecosystem may differ in case and still be the
106
+ * same address.
107
+ *
108
+ * A FIELD RATHER THAN A BRANCH SOMEWHERE ELSE, and that is the whole point of
109
+ * it. This rule lived as `ecosystem === 'evm' ? lowercase both : compare
110
+ * exactly` inside the interface, which is a second place that has to learn
111
+ * about every family added here — and the least likely place anyone would
112
+ * think to look. Adding a family is now one entry in this registry.
113
+ *
114
+ * `insensitive` is Ethereum's: the checksum is carried in the case, so two
115
+ * spellings of one address are the same address. `significant` is everyone
116
+ * else's: base58 and base64url alphabets use case to carry information, so
117
+ * two addresses can differ by case alone and comparing them loosely would
118
+ * merge two different accounts.
119
+ */
120
+ addressCasing: 'insensitive' | 'significant';
121
+ };
122
+ /**
123
+ * Every ecosystem the bridge can originate from. LI.FI-compatible one first.
124
+ *
125
+ * Registration means the library can MODEL and QUOTE the ecosystem, not that an
126
+ * interface can sign it — see the note on {@link Ecosystem}.
127
+ *
128
+ * It means less than that again where a public claim is concerned: read
129
+ * {@link EndToEndProof} before listing this registry anywhere a reader will
130
+ * take it as an offer.
131
+ */
132
+ export declare const ecosystemRegistry: readonly EcosystemDescriptor[];
133
+ /**
134
+ * Looks up the descriptor for an ecosystem id. Total over the `Ecosystem` union;
135
+ * throws only if the registry is ever left incomplete (a programming error the
136
+ * round-trip test would catch).
137
+ *
138
+ * @param id - the ecosystem key
139
+ * @returns the descriptor whose `id` equals `id`
140
+ */
141
+ export declare const ecosystemById: (id: Ecosystem) => EcosystemDescriptor;
142
+ /**
143
+ * Whether a transfer has been carried through this ecosystem end to end.
144
+ *
145
+ * The predicate a surface calls before ADVERTISING an origin. It is separate
146
+ * from anything the router asks, and deliberately so: the router must keep
147
+ * quoting and naming every registered ecosystem, because a reader who reaches
148
+ * an unproven chain through a link still needs the page to work. This governs
149
+ * only what the product offers unprompted.
150
+ *
151
+ * @param id - the ecosystem key
152
+ * @returns true when a real transfer has completed through it
153
+ */
154
+ export declare const isEcosystemProvenEndToEnd: (id: Ecosystem) => boolean;
155
+ /**
156
+ * Resolves an ecosystem from a chain-agnostic identifier namespace.
157
+ *
158
+ * @param namespace - the leading segment of a "namespace:reference:address" id
159
+ * @returns the matching descriptor, or undefined when the namespace is unknown
160
+ */
161
+ export declare const ecosystemByCaipNamespace: (namespace: string) => EcosystemDescriptor | undefined;
162
+ /**
163
+ * Whether two addresses in the same ecosystem name the same thing.
164
+ *
165
+ * THE ONE PLACE THIS QUESTION IS ANSWERED. It was answered in two: this
166
+ * registry, which knows each family's address rules, and a ternary in the
167
+ * interface's routing module that hard-coded "Ethereum is case-insensitive,
168
+ * everything else is not". Two homes means a family added here is still
169
+ * compared wrongly there, silently, because a loose comparison does not fail —
170
+ * it merges two different accounts into one.
171
+ *
172
+ * @param a - an address
173
+ * @param b - an address, in the same ecosystem
174
+ * @param ecosystem - the ecosystem both belong to
175
+ * @returns whether they are the same address
176
+ */
177
+ export declare const sameAddress: (a: string, b: string, ecosystem: Ecosystem) => boolean;
178
+ /**
179
+ * Whether an address is the ecosystem's own native asset rather than a token.
180
+ *
181
+ * Every ecosystem already declares its `nativeAssetSentinel`, and this is the
182
+ * predicate that reads it. The comparison goes through {@link sameAddress}
183
+ * rather than `toLowerCase()`, which matters for exactly the families where the
184
+ * hand-written checks were wrong to begin with: Solana's, Bitcoin's and The
185
+ * Open Network's sentinels are case-significant, so lower-casing them before
186
+ * comparing can match an address that is not the sentinel.
187
+ *
188
+ * @param value - the address to test
189
+ * @param ecosystem - the ecosystem it belongs to
190
+ * @returns whether it names the native asset
191
+ */
192
+ export declare const isNativeAsset: (value: string, ecosystem: Ecosystem) => boolean;
193
+ /**
194
+ * Whether a string is a well-formed address in this ecosystem.
195
+ *
196
+ * A free function over the registry, so a caller needs the ecosystem key and
197
+ * nothing else. Reaching for viem's `isAddress` directly is the thing this
198
+ * replaces: it answers only for Ethereum and answers FALSE — confidently — for
199
+ * every valid Solana, Bitcoin, Tron and Open Network address.
200
+ *
201
+ * @param value - the string to test
202
+ * @param ecosystem - the ecosystem to test it against
203
+ * @returns whether the string is a valid address there
204
+ */
205
+ export declare const isValidAddressIn: (value: string, ecosystem: Ecosystem) => boolean;
206
+ /**
207
+ * The ecosystem's canonical spelling of an address.
208
+ *
209
+ * Total and side-effect-free: an input this ecosystem cannot parse comes back
210
+ * unchanged rather than throwing, because normalizing is something callers do
211
+ * on the way to a comparison and a throw there would be a crash on a typo.
212
+ *
213
+ * @param value - the address to normalize
214
+ * @param ecosystem - the ecosystem it belongs to
215
+ * @returns the canonical form, or the input when it cannot be parsed
216
+ */
217
+ export declare const normalizeAddressIn: (value: string, ecosystem: Ecosystem) => string;