@gibs/bridge-sdk 1.12.0 → 1.13.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +15 -0
- package/README.md +234 -432
- package/dist/abis.d.ts +1 -0
- package/dist/bridge-limits.d.ts +103 -0
- package/dist/bridge-limits.js +84 -0
- package/dist/chain-info.d.ts +169 -0
- package/dist/chain-info.js +410 -0
- package/dist/chain-names.d.ts +160 -0
- package/dist/chain-names.js +200 -0
- package/dist/chains.d.ts +65 -0
- package/dist/chains.js +284 -0
- package/dist/config.d.ts +216 -0
- package/dist/config.js +493 -0
- package/dist/consolidated-quote.d.ts +554 -0
- package/dist/consolidated-quote.js +773 -0
- package/dist/destination-calldata.d.ts +118 -0
- package/dist/destination-calldata.js +152 -0
- package/dist/ecosystems.d.ts +217 -0
- package/dist/ecosystems.js +288 -0
- package/dist/fee-type.d.ts +10 -0
- package/dist/fee-type.js +9 -0
- package/dist/hyperliquid-execution.d.ts +152 -0
- package/dist/hyperliquid-execution.js +168 -0
- package/dist/image-links.d.ts +117 -0
- package/dist/image-links.js +142 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.js +20 -0
- package/dist/lifi-execution-guard.d.ts +199 -0
- package/dist/lifi-execution-guard.js +400 -0
- package/dist/near-intents-conformance.d.ts +85 -0
- package/dist/near-intents-conformance.js +329 -0
- package/dist/near-intents-route.d.ts +47 -0
- package/dist/near-intents-route.js +265 -0
- package/dist/near-intents.d.ts +524 -0
- package/dist/near-intents.js +1055 -0
- package/dist/origin-deposit.d.ts +326 -0
- package/dist/origin-deposit.js +68 -0
- package/dist/pre-quote.d.ts +198 -0
- package/dist/pre-quote.js +175 -0
- package/dist/prices.d.ts +107 -0
- package/dist/prices.js +162 -0
- package/dist/providers.d.ts +221 -0
- package/dist/providers.js +157 -0
- package/dist/quote-fees.d.ts +102 -0
- package/dist/quote-fees.js +195 -0
- package/dist/referral.d.ts +77 -0
- package/dist/referral.js +72 -0
- package/dist/relay-currencies.d.ts +47 -0
- package/dist/relay-currencies.js +89 -0
- package/dist/relay-quote.d.ts +301 -0
- package/dist/relay-quote.js +983 -0
- package/dist/route-steps.d.ts +138 -0
- package/dist/route-steps.js +305 -0
- package/dist/routing/amounts.d.ts +80 -0
- package/dist/routing/amounts.js +120 -0
- package/dist/routing/candidate-route.d.ts +43 -0
- package/dist/routing/candidate-route.js +45 -0
- package/dist/routing/candidate.d.ts +237 -0
- package/dist/routing/candidate.js +96 -0
- package/dist/routing/carriers/ask-answer.d.ts +60 -0
- package/dist/routing/carriers/ask-answer.js +1 -0
- package/dist/routing/carriers/omnibridge.d.ts +137 -0
- package/dist/routing/carriers/omnibridge.js +419 -0
- package/dist/routing/carriers/pulsex.d.ts +149 -0
- package/dist/routing/carriers/pulsex.js +453 -0
- package/dist/routing/carriers/wrap.d.ts +25 -0
- package/dist/routing/carriers/wrap.js +115 -0
- package/dist/routing/composed-route-quality.d.ts +103 -0
- package/dist/routing/composed-route-quality.js +108 -0
- package/dist/routing/entry-chain-anchor.d.ts +88 -0
- package/dist/routing/entry-chain-anchor.js +55 -0
- package/dist/routing/format.d.ts +31 -0
- package/dist/routing/format.js +58 -0
- package/dist/routing/index.d.ts +34 -0
- package/dist/routing/index.js +42 -0
- package/dist/routing/producers.d.ts +770 -0
- package/dist/routing/producers.js +1564 -0
- package/dist/routing/providers.d.ts +26 -0
- package/dist/routing/providers.js +38 -0
- package/dist/routing/route-data.d.ts +355 -0
- package/dist/routing/route-data.js +1 -0
- package/dist/routing/search/compose.d.ts +168 -0
- package/dist/routing/search/compose.js +98 -0
- package/dist/routing/search/graph.d.ts +653 -0
- package/dist/routing/search/graph.js +445 -0
- package/dist/routing/search/plan-route-data.d.ts +244 -0
- package/dist/routing/search/plan-route-data.js +767 -0
- package/dist/routing/search/score.d.ts +353 -0
- package/dist/routing/search/score.js +427 -0
- package/dist/routing/usd-value.d.ts +17 -0
- package/dist/routing/usd-value.js +25 -0
- package/dist/settings.d.ts +692 -0
- package/dist/settings.js +909 -0
- package/dist/ton-execution.d.ts +117 -0
- package/dist/ton-execution.js +247 -0
- package/dist/tron-execution.d.ts +146 -0
- package/dist/tron-execution.js +239 -0
- package/dist/types.d.ts +51 -0
- package/dist/types.js +1 -0
- package/llms.txt +169 -0
- package/package.json +204 -23
- package/src/chain-info.test.ts +0 -968
- package/src/chain-info.ts +0 -498
- package/src/chains.test.ts +0 -123
- package/src/chains.ts +0 -88
- package/src/config.test.ts +0 -679
- package/src/config.ts +0 -500
- package/src/fee-type.test.ts +0 -45
- package/src/fee-type.ts +0 -14
- package/src/image-links.test.ts +0 -160
- package/src/image-links.ts +0 -65
- package/src/index.ts +0 -8
- package/src/settings.test.ts +0 -2754
- package/src/settings.ts +0 -875
- package/src/types.ts +0 -48
- package/tsconfig.json +0 -17
- package/vitest.config.ts +0 -13
- /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;
|