@gibs/bridge-sdk 1.13.0 → 1.17.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 (217) hide show
  1. package/README.md +244 -18
  2. package/abis/package.json +6 -0
  3. package/bridge-limits/package.json +6 -0
  4. package/chain-info/package.json +6 -0
  5. package/chain-names/package.json +6 -0
  6. package/chains/package.json +6 -0
  7. package/claims/package.json +6 -0
  8. package/config/package.json +6 -0
  9. package/consolidated-quote/package.json +6 -0
  10. package/destination-calldata/package.json +6 -0
  11. package/dist/chain-info.d.ts +1 -1
  12. package/dist/chain-info.js +11 -12
  13. package/dist/chains.d.ts +25 -0
  14. package/dist/chains.js +55 -20
  15. package/dist/cjs/abis.d.ts +1 -0
  16. package/dist/cjs/abis.js +19 -0
  17. package/dist/cjs/bridge-limits.d.ts +103 -0
  18. package/dist/cjs/bridge-limits.js +89 -0
  19. package/dist/cjs/chain-info.d.ts +169 -0
  20. package/dist/cjs/chain-info.js +452 -0
  21. package/dist/cjs/chain-names.d.ts +160 -0
  22. package/dist/cjs/chain-names.js +207 -0
  23. package/dist/cjs/chains.d.ts +90 -0
  24. package/dist/cjs/chains.js +357 -0
  25. package/dist/cjs/claims.d.ts +198 -0
  26. package/dist/cjs/claims.js +182 -0
  27. package/dist/cjs/config.d.ts +240 -0
  28. package/dist/cjs/config.js +537 -0
  29. package/dist/cjs/consolidated-quote.d.ts +648 -0
  30. package/dist/cjs/consolidated-quote.js +1048 -0
  31. package/dist/cjs/destination-calldata.d.ts +118 -0
  32. package/dist/cjs/destination-calldata.js +156 -0
  33. package/dist/cjs/ecosystems.d.ts +217 -0
  34. package/dist/cjs/ecosystems.js +298 -0
  35. package/dist/cjs/execution.d.ts +346 -0
  36. package/dist/cjs/execution.js +468 -0
  37. package/dist/cjs/fee-type.d.ts +10 -0
  38. package/dist/cjs/fee-type.js +10 -0
  39. package/dist/cjs/hyperliquid-execution.d.ts +152 -0
  40. package/dist/cjs/hyperliquid-execution.js +175 -0
  41. package/dist/cjs/image-links.d.ts +117 -0
  42. package/dist/cjs/image-links.js +153 -0
  43. package/dist/cjs/index.d.ts +23 -0
  44. package/dist/cjs/index.js +39 -0
  45. package/dist/cjs/lifi-execution-guard.d.ts +210 -0
  46. package/dist/cjs/lifi-execution-guard.js +409 -0
  47. package/dist/cjs/near-intents-conformance.d.ts +85 -0
  48. package/dist/cjs/near-intents-conformance.js +337 -0
  49. package/dist/cjs/near-intents-route.d.ts +47 -0
  50. package/dist/cjs/near-intents-route.js +303 -0
  51. package/dist/cjs/near-intents.d.ts +524 -0
  52. package/dist/cjs/near-intents.js +1071 -0
  53. package/dist/cjs/origin-deposit.d.ts +326 -0
  54. package/dist/cjs/origin-deposit.js +82 -0
  55. package/dist/cjs/package.json +3 -0
  56. package/dist/cjs/pre-quote.d.ts +198 -0
  57. package/dist/cjs/pre-quote.js +180 -0
  58. package/dist/cjs/prices.d.ts +107 -0
  59. package/dist/cjs/prices.js +172 -0
  60. package/dist/cjs/providers.d.ts +238 -0
  61. package/dist/cjs/providers.js +171 -0
  62. package/dist/cjs/quote-fees.d.ts +102 -0
  63. package/dist/cjs/quote-fees.js +201 -0
  64. package/dist/cjs/referral.d.ts +85 -0
  65. package/dist/cjs/referral.js +85 -0
  66. package/dist/cjs/relay-currencies.d.ts +47 -0
  67. package/dist/cjs/relay-currencies.js +95 -0
  68. package/dist/cjs/relay-depository.d.ts +2 -0
  69. package/dist/cjs/relay-depository.js +85 -0
  70. package/dist/cjs/relay-quote.d.ts +301 -0
  71. package/dist/cjs/relay-quote.js +996 -0
  72. package/dist/cjs/route-steps.d.ts +138 -0
  73. package/dist/cjs/route-steps.js +310 -0
  74. package/dist/cjs/routing/amounts.d.ts +80 -0
  75. package/dist/cjs/routing/amounts.js +126 -0
  76. package/dist/cjs/routing/candidate-route.d.ts +43 -0
  77. package/dist/cjs/routing/candidate-route.js +50 -0
  78. package/dist/cjs/routing/candidate.d.ts +237 -0
  79. package/dist/cjs/routing/candidate.js +100 -0
  80. package/dist/cjs/routing/carriers/ask-answer.d.ts +77 -0
  81. package/dist/cjs/routing/carriers/ask-answer.js +2 -0
  82. package/dist/cjs/routing/carriers/omnibridge.d.ts +137 -0
  83. package/dist/cjs/routing/carriers/omnibridge.js +459 -0
  84. package/dist/cjs/routing/carriers/pulsex-paths.d.ts +80 -0
  85. package/dist/cjs/routing/carriers/pulsex-paths.js +97 -0
  86. package/dist/cjs/routing/carriers/pulsex-split.d.ts +175 -0
  87. package/dist/cjs/routing/carriers/pulsex-split.js +193 -0
  88. package/dist/cjs/routing/carriers/pulsex.d.ts +159 -0
  89. package/dist/cjs/routing/carriers/pulsex.js +565 -0
  90. package/dist/cjs/routing/carriers/wrap.d.ts +25 -0
  91. package/dist/cjs/routing/carriers/wrap.js +119 -0
  92. package/dist/cjs/routing/composed-route-quality.d.ts +125 -0
  93. package/dist/cjs/routing/composed-route-quality.js +144 -0
  94. package/dist/cjs/routing/entry-chain-anchor.d.ts +88 -0
  95. package/dist/cjs/routing/entry-chain-anchor.js +59 -0
  96. package/dist/cjs/routing/format.d.ts +31 -0
  97. package/dist/cjs/routing/format.js +64 -0
  98. package/dist/cjs/routing/index.d.ts +38 -0
  99. package/dist/cjs/routing/index.js +134 -0
  100. package/dist/cjs/routing/producers.d.ts +770 -0
  101. package/dist/cjs/routing/producers.js +1617 -0
  102. package/dist/cjs/routing/providers.d.ts +31 -0
  103. package/dist/cjs/routing/providers.js +48 -0
  104. package/dist/cjs/routing/route-data.d.ts +355 -0
  105. package/dist/cjs/routing/route-data.js +2 -0
  106. package/dist/cjs/routing/search/compose.d.ts +168 -0
  107. package/dist/cjs/routing/search/compose.js +104 -0
  108. package/dist/cjs/routing/search/graph.d.ts +668 -0
  109. package/dist/cjs/routing/search/graph.js +461 -0
  110. package/dist/cjs/routing/search/plan-route-data.d.ts +269 -0
  111. package/dist/cjs/routing/search/plan-route-data.js +848 -0
  112. package/dist/cjs/routing/search/score.d.ts +356 -0
  113. package/dist/cjs/routing/search/score.js +445 -0
  114. package/dist/cjs/routing/swap-transactions.d.ts +91 -0
  115. package/dist/cjs/routing/swap-transactions.js +131 -0
  116. package/dist/cjs/routing/usd-value.d.ts +17 -0
  117. package/dist/cjs/routing/usd-value.js +29 -0
  118. package/dist/cjs/settings.d.ts +785 -0
  119. package/dist/cjs/settings.js +1074 -0
  120. package/dist/cjs/ton-connect.d.ts +98 -0
  121. package/dist/cjs/ton-connect.js +206 -0
  122. package/dist/cjs/ton-execution.d.ts +7 -0
  123. package/dist/cjs/ton-execution.js +23 -0
  124. package/dist/cjs/ton.d.ts +37 -0
  125. package/dist/cjs/ton.js +83 -0
  126. package/dist/cjs/tron-execution.d.ts +146 -0
  127. package/dist/cjs/tron-execution.js +248 -0
  128. package/dist/cjs/types.d.ts +51 -0
  129. package/dist/cjs/types.js +2 -0
  130. package/dist/claims.d.ts +198 -0
  131. package/dist/claims.js +140 -0
  132. package/dist/config.d.ts +24 -0
  133. package/dist/config.js +39 -5
  134. package/dist/consolidated-quote.d.ts +109 -15
  135. package/dist/consolidated-quote.js +310 -52
  136. package/dist/execution.d.ts +346 -0
  137. package/dist/execution.js +428 -0
  138. package/dist/hyperliquid-execution.js +2 -3
  139. package/dist/index.d.ts +3 -0
  140. package/dist/index.js +3 -0
  141. package/dist/lifi-execution-guard.d.ts +13 -2
  142. package/dist/lifi-execution-guard.js +4 -0
  143. package/dist/near-intents.js +2 -3
  144. package/dist/pre-quote.d.ts +6 -6
  145. package/dist/pre-quote.js +10 -14
  146. package/dist/providers.d.ts +17 -0
  147. package/dist/providers.js +6 -0
  148. package/dist/referral.d.ts +12 -4
  149. package/dist/referral.js +12 -4
  150. package/dist/relay-depository.d.ts +2 -0
  151. package/dist/relay-depository.js +82 -0
  152. package/dist/relay-quote.js +2 -3
  153. package/dist/routing/candidate.d.ts +3 -3
  154. package/dist/routing/candidate.js +3 -3
  155. package/dist/routing/carriers/ask-answer.d.ts +19 -0
  156. package/dist/routing/carriers/omnibridge.js +23 -21
  157. package/dist/routing/carriers/pulsex-paths.d.ts +80 -0
  158. package/dist/routing/carriers/pulsex-paths.js +92 -0
  159. package/dist/routing/carriers/pulsex-split.d.ts +175 -0
  160. package/dist/routing/carriers/pulsex-split.js +185 -0
  161. package/dist/routing/carriers/pulsex.d.ts +69 -21
  162. package/dist/routing/carriers/pulsex.js +184 -65
  163. package/dist/routing/composed-route-quality.d.ts +28 -6
  164. package/dist/routing/composed-route-quality.js +36 -5
  165. package/dist/routing/entry-chain-anchor.d.ts +1 -1
  166. package/dist/routing/entry-chain-anchor.js +1 -1
  167. package/dist/routing/index.d.ts +7 -3
  168. package/dist/routing/index.js +7 -3
  169. package/dist/routing/producers.js +1 -1
  170. package/dist/routing/providers.d.ts +5 -0
  171. package/dist/routing/providers.js +5 -0
  172. package/dist/routing/search/graph.d.ts +29 -0
  173. package/dist/routing/search/plan-route-data.d.ts +25 -0
  174. package/dist/routing/search/plan-route-data.js +43 -7
  175. package/dist/routing/search/score.d.ts +33 -1
  176. package/dist/routing/search/score.js +41 -6
  177. package/dist/routing/swap-transactions.d.ts +91 -0
  178. package/dist/routing/swap-transactions.js +125 -0
  179. package/dist/settings.d.ts +94 -1
  180. package/dist/settings.js +95 -3
  181. package/dist/ton-connect.d.ts +98 -0
  182. package/dist/ton-connect.js +200 -0
  183. package/dist/ton-execution.d.ts +4 -114
  184. package/dist/ton-execution.js +4 -244
  185. package/dist/ton.d.ts +37 -0
  186. package/dist/ton.js +65 -0
  187. package/docs/examples/example-a-ether-to-pulse.ts +300 -0
  188. package/docs/examples/example-b-token-pulsechain-to-ethereum.ts +270 -0
  189. package/docs/examples/shared.ts +261 -0
  190. package/docs/examples/tsconfig.json +18 -0
  191. package/docs/integration-guide.md +617 -0
  192. package/ecosystems/package.json +6 -0
  193. package/execution/package.json +6 -0
  194. package/fee-type/package.json +6 -0
  195. package/hyperliquid-execution/package.json +6 -0
  196. package/image-links/package.json +6 -0
  197. package/lifi-execution-guard/package.json +6 -0
  198. package/llms.txt +234 -0
  199. package/near-intents/package.json +6 -0
  200. package/near-intents-route/package.json +6 -0
  201. package/origin-deposit/package.json +6 -0
  202. package/package.json +818 -10
  203. package/pre-quote/package.json +6 -0
  204. package/prices/package.json +6 -0
  205. package/providers/package.json +6 -0
  206. package/quote-fees/package.json +6 -0
  207. package/referral/package.json +6 -0
  208. package/relay-currencies/package.json +6 -0
  209. package/relay-quote/package.json +6 -0
  210. package/route-steps/package.json +6 -0
  211. package/routing/package.json +6 -0
  212. package/settings/package.json +6 -0
  213. package/ton/package.json +6 -0
  214. package/ton-connect/package.json +6 -0
  215. package/ton-execution/package.json +6 -0
  216. package/tron-execution/package.json +6 -0
  217. package/types/package.json +6 -0
@@ -0,0 +1,298 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.normalizeAddressIn = exports.isValidAddressIn = exports.isNativeAsset = exports.sameAddress = exports.ecosystemByCaipNamespace = exports.isEcosystemProvenEndToEnd = exports.ecosystemById = exports.ecosystemRegistry = void 0;
4
+ const viem_1 = require("viem");
5
+ // Solana public keys are base58 (no 0, O, I, l) and 32–44 characters long.
6
+ const base58Solana = /^[1-9A-HJ-NP-Za-km-z]{32,44}$/;
7
+ // Bitcoin mainnet: bech32 (bc1…) or base58 pay-to-key/script (starts 1 or 3).
8
+ const bech32Bitcoin = /^bc1[0-9ac-hj-np-z]{6,87}$/;
9
+ const base58Bitcoin = /^[13][1-9A-HJ-NP-Za-km-z]{25,39}$/;
10
+ // Tron base58check addresses are always 34 characters and always begin with a
11
+ // capital T (the encoding of the 0x41 mainnet prefix byte).
12
+ const base58Tron = /^T[1-9A-HJ-NP-Za-km-z]{33}$/;
13
+ // The Open Network has two interchangeable address encodings, and Relay uses
14
+ // both: the 48-character "user-friendly" base64url form (EQ/UQ on mainnet,
15
+ // kQ/0Q on testnet), and the "raw" form of a workchain, a colon, and a
16
+ // 64-character hex account identifier.
17
+ const friendlyTon = /^[EUk0]Q[A-Za-z0-9_-]{46}$/;
18
+ const rawTon = /^-?\d+:[0-9a-fA-F]{64}$/;
19
+ // HyperCore token identifiers are hex of a length Ethereum never uses: sixteen
20
+ // bytes for most tokens, nineteen for a few. Twenty is allowed too so a token
21
+ // that is addressed by a full Ethereum address still resolves.
22
+ const hyperliquidTokenId = /^0x[0-9a-fA-F]{32,40}$/;
23
+ // Zcash TRANSPARENT addresses only, and the restriction is the service's, not
24
+ // ours: a shielded (`zs1…`) or unified (`u1…`) address is refused at the door
25
+ // with `refundTo is not valid`, before a solver is ever reached. Both
26
+ // transparent forms are base58check over a two-byte prefix, which always
27
+ // encodes to exactly 35 characters: `t1` pays to a public key hash, `t3` to a
28
+ // script hash. The pattern rejects the shielded forms by construction, because
29
+ // neither begins with `t`.
30
+ const transparentZcash = /^t[13][1-9A-HJ-NP-Za-km-z]{33}$/;
31
+ const evmDescriptor = {
32
+ id: 'evm',
33
+ label: 'Ethereum Virtual Machine',
34
+ caipNamespace: 'eip155',
35
+ // The all-zero address, exactly as the Relay builder uses across every
36
+ // Ethereum Virtual Machine chain for the native gas token.
37
+ nativeAssetSentinel: '0x0000000000000000000000000000000000000000',
38
+ // The only proof the product holds. The bridge's own contracts run on
39
+ // PulseChain, Ethereum and Binance Smart Chain, and every aggregator origin
40
+ // LI.FI carries is an Ethereum Virtual Machine chain, so this is the family
41
+ // real transfers have crossed.
42
+ endToEndProof: 'verified',
43
+ isValidAddress: (value) => (0, viem_1.isAddress)(value),
44
+ // getAddress applies the mixed-case checksum; it throws on a non-address, so
45
+ // fall back to the raw input to keep normalize total and side-effect-free.
46
+ normalizeAddress: (value) => ((0, viem_1.isAddress)(value) ? (0, viem_1.getAddress)(value) : value),
47
+ addressCasing: 'insensitive',
48
+ };
49
+ const svmDescriptor = {
50
+ id: 'svm',
51
+ label: 'Solana',
52
+ caipNamespace: 'solana',
53
+ // Solana native currency (the System Program address), as Relay expects it.
54
+ nativeAssetSentinel: '11111111111111111111111111111111',
55
+ // Connects through the Reown AppKit Solana adapter and signs for real
56
+ // (`useSolanaDepositSigner` builds a versioned transaction and calls the
57
+ // wallet's sign-and-send). Every test around it drives a mocked wallet, and
58
+ // Relay — the only provider that quotes this origin — has never had its
59
+ // on-chain execution confirmed by a funded transfer.
60
+ endToEndProof: 'pending',
61
+ isValidAddress: (value) => base58Solana.test(value),
62
+ // base58 is case-significant; canonical form is the input unchanged.
63
+ normalizeAddress: (value) => value,
64
+ addressCasing: 'significant',
65
+ };
66
+ const bvmDescriptor = {
67
+ id: 'bvm',
68
+ label: 'Bitcoin',
69
+ caipNamespace: 'bip122',
70
+ // Bitcoin native currency string, as Relay expects it.
71
+ nativeAssetSentinel: 'bc1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqmql8k8',
72
+ // The best-evidenced of the four, and still short of proof. A partially
73
+ // signed transaction the pipeline builds is accepted by a real node, but
74
+ // that test runs against a local regtest node behind `BITCOIN_REGTEST=1`
75
+ // and never in the normal suite. The browser wallet that signs in
76
+ // production is driven by nothing but a mock, and no funded mainnet
77
+ // transfer has completed.
78
+ endToEndProof: 'pending',
79
+ isValidAddress: (value) => bech32Bitcoin.test(value) || base58Bitcoin.test(value),
80
+ // bech32 and base58 are case-significant; canonical form is the input unchanged.
81
+ normalizeAddress: (value) => value,
82
+ addressCasing: 'significant',
83
+ };
84
+ const tvmDescriptor = {
85
+ id: 'tvm',
86
+ label: 'Tron',
87
+ caipNamespace: 'tron',
88
+ // Tron native currency (TRX), as Relay expects it. Not a real contract: it is
89
+ // the placeholder address Relay publishes for the chain's native asset.
90
+ nativeAssetSentinel: 'T9yD14Nj9j7xAB4dbGeiX9h8unkKHxuWwb',
91
+ // The first wallet the interface reaches outside Reown AppKit: it reads an
92
+ // injected provider directly. That is more of the connection path owned
93
+ // here, and therefore more of it unexercised outside a mock. No funded
94
+ // transfer has completed.
95
+ endToEndProof: 'pending',
96
+ isValidAddress: (value) => base58Tron.test(value),
97
+ // base58check is case-significant; canonical form is the input unchanged.
98
+ normalizeAddress: (value) => value,
99
+ addressCasing: 'significant',
100
+ };
101
+ const tonvmDescriptor = {
102
+ id: 'tonvm',
103
+ label: 'The Open Network',
104
+ caipNamespace: 'ton',
105
+ // Relay publishes Gram — NOT the Toncoin gas asset — as this chain's native
106
+ // currency, so a native-asset route on The Open Network is denominated in
107
+ // Gram. Kept byte-equal to Relay's own value rather than "corrected".
108
+ nativeAssetSentinel: 'EQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM9c',
109
+ // The second wallet outside Reown AppKit, on a separate connection library,
110
+ // and the one origin whose deposit identifier is derived from the returned
111
+ // cell rather than handed back by the wallet. Only a mock has ever returned
112
+ // that cell. No funded transfer has completed.
113
+ endToEndProof: 'pending',
114
+ isValidAddress: (value) => friendlyTon.test(value) || rawTon.test(value),
115
+ // both encodings are case-significant; canonical form is the input unchanged.
116
+ normalizeAddress: (value) => value,
117
+ addressCasing: 'significant',
118
+ };
119
+ const hypevmDescriptor = {
120
+ id: 'hypevm',
121
+ label: 'Hyperliquid',
122
+ caipNamespace: 'hyperliquid',
123
+ // Relay publishes USD Coin — NOT the Hype gas asset — as this chain's native
124
+ // currency, and addresses it by a sixteen-byte HyperCore token identifier
125
+ // rather than the twenty-byte all-zero address every Ethereum Virtual Machine
126
+ // chain uses. The two sentinels are therefore different strings.
127
+ nativeAssetSentinel: '0x00000000000000000000000000000000',
128
+ // THE WORST OF THE SIX, and the one that was actively misleading. The
129
+ // interface's source picker never offers Hyperliquid — nothing can quote it
130
+ // — yet the landing page drew a pill for it that set the source chain to
131
+ // Hyperliquid on click. A reader who pressed it arrived at a chain the form
132
+ // does not list and no provider answers. Removing the pill removes that dead
133
+ // end; the descriptor stays because the route layer still has to be able to
134
+ // NAME the chain.
135
+ endToEndProof: 'pending',
136
+ // This predicate checks TOKEN addresses, and HyperCore identifies a token by a
137
+ // hex string SHORTER than an Ethereum address — sixteen bytes for most,
138
+ // nineteen for a few — so the twenty-byte `isAddress` check would reject the
139
+ // very identifiers it exists to accept. Its only consumer silently falls back
140
+ // to the native sentinel when this returns false, so an over-strict pattern
141
+ // would quietly swallow valid token links instead of surfacing an error.
142
+ // Accounts are a different namespace (ordinary twenty-byte Ethereum
143
+ // addresses) and are validated by the wallet layer, not here.
144
+ isValidAddress: (value) => hyperliquidTokenId.test(value),
145
+ // Hex is case-insensitive and Relay emits lower case, so lower case is the
146
+ // canonical form. It matters: the token-equality check compares non-Ethereum
147
+ // addresses exactly, and only a single canonical case makes that correct.
148
+ normalizeAddress: (value) => hyperliquidTokenId.test(value) ? value.toLowerCase() : value,
149
+ addressCasing: 'significant',
150
+ };
151
+ const zcashDescriptor = {
152
+ id: 'zcash',
153
+ label: 'Zcash',
154
+ // Zcash is not a Relay chain and has no widely-registered chain-agnostic
155
+ // namespace. `zcash` is this repository's own key, and nothing maps a
156
+ // connected wallet through it, because no wallet connects to this family.
157
+ caipNamespace: 'zcash',
158
+ // DERIVED, NOT INVENTED: the transparent pay-to-public-key-hash address of
159
+ // an all-zero key hash, base58check over the mainnet prefix `1cb8` followed
160
+ // by twenty zero bytes. Nobody holds a key for it. It follows the pattern of
161
+ // Relay's Bitcoin sentinel, an all-zero witness program, and for the same
162
+ // reason: the sentinel stands where a token address is expected, so it must
163
+ // pass this family's own address check. Zcash carries no tokens on this
164
+ // route, so the native asset is the only asset.
165
+ nativeAssetSentinel: 't1Hsc1LR8yKnbbe3twRp88p6vFfC5t7DLbs',
166
+ // THE FIRST ECOSYSTEM WITH NO WALLET AT ALL, and therefore the first whose
167
+ // hold cannot be cleared by connecting one. The reader pays an address by
168
+ // hand from wherever they hold the coin, so every part of the journey that
169
+ // this repository owns — the quote, the address, the amount, the deadline,
170
+ // the status poll — is exercised only by a fixture. Nothing funded has
171
+ // crossed. Clearing this is one word, after one transfer.
172
+ endToEndProof: 'pending',
173
+ isValidAddress: (value) => transparentZcash.test(value),
174
+ // base58check is case-significant; canonical form is the input unchanged.
175
+ normalizeAddress: (value) => value,
176
+ addressCasing: 'significant',
177
+ };
178
+ /**
179
+ * Every ecosystem the bridge can originate from. LI.FI-compatible one first.
180
+ *
181
+ * Registration means the library can MODEL and QUOTE the ecosystem, not that an
182
+ * interface can sign it — see the note on {@link Ecosystem}.
183
+ *
184
+ * It means less than that again where a public claim is concerned: read
185
+ * {@link EndToEndProof} before listing this registry anywhere a reader will
186
+ * take it as an offer.
187
+ */
188
+ exports.ecosystemRegistry = [
189
+ evmDescriptor,
190
+ svmDescriptor,
191
+ bvmDescriptor,
192
+ tvmDescriptor,
193
+ tonvmDescriptor,
194
+ hypevmDescriptor,
195
+ zcashDescriptor,
196
+ ];
197
+ const byId = new Map(exports.ecosystemRegistry.map((descriptor) => [descriptor.id, descriptor]));
198
+ /**
199
+ * Looks up the descriptor for an ecosystem id. Total over the `Ecosystem` union;
200
+ * throws only if the registry is ever left incomplete (a programming error the
201
+ * round-trip test would catch).
202
+ *
203
+ * @param id - the ecosystem key
204
+ * @returns the descriptor whose `id` equals `id`
205
+ */
206
+ const ecosystemById = (id) => {
207
+ const descriptor = byId.get(id);
208
+ if (descriptor === undefined) {
209
+ throw new Error(`no ecosystem descriptor registered for id "${id}"`);
210
+ }
211
+ return descriptor;
212
+ };
213
+ exports.ecosystemById = ecosystemById;
214
+ /**
215
+ * Whether a transfer has been carried through this ecosystem end to end.
216
+ *
217
+ * The predicate a surface calls before ADVERTISING an origin. It is separate
218
+ * from anything the router asks, and deliberately so: the router must keep
219
+ * quoting and naming every registered ecosystem, because a reader who reaches
220
+ * an unproven chain through a link still needs the page to work. This governs
221
+ * only what the product offers unprompted.
222
+ *
223
+ * @param id - the ecosystem key
224
+ * @returns true when a real transfer has completed through it
225
+ */
226
+ const isEcosystemProvenEndToEnd = (id) => (0, exports.ecosystemById)(id).endToEndProof === 'verified';
227
+ exports.isEcosystemProvenEndToEnd = isEcosystemProvenEndToEnd;
228
+ const byNamespace = new Map(exports.ecosystemRegistry.map((descriptor) => [descriptor.caipNamespace, descriptor]));
229
+ /**
230
+ * Resolves an ecosystem from a chain-agnostic identifier namespace.
231
+ *
232
+ * @param namespace - the leading segment of a "namespace:reference:address" id
233
+ * @returns the matching descriptor, or undefined when the namespace is unknown
234
+ */
235
+ const ecosystemByCaipNamespace = (namespace) => byNamespace.get(namespace);
236
+ exports.ecosystemByCaipNamespace = ecosystemByCaipNamespace;
237
+ /**
238
+ * Whether two addresses in the same ecosystem name the same thing.
239
+ *
240
+ * THE ONE PLACE THIS QUESTION IS ANSWERED. It was answered in two: this
241
+ * registry, which knows each family's address rules, and a ternary in the
242
+ * interface's routing module that hard-coded "Ethereum is case-insensitive,
243
+ * everything else is not". Two homes means a family added here is still
244
+ * compared wrongly there, silently, because a loose comparison does not fail —
245
+ * it merges two different accounts into one.
246
+ *
247
+ * @param a - an address
248
+ * @param b - an address, in the same ecosystem
249
+ * @param ecosystem - the ecosystem both belong to
250
+ * @returns whether they are the same address
251
+ */
252
+ const sameAddress = (a, b, ecosystem) => (0, exports.ecosystemById)(ecosystem).addressCasing === 'insensitive'
253
+ ? a.toLowerCase() === b.toLowerCase()
254
+ : a === b;
255
+ exports.sameAddress = sameAddress;
256
+ /**
257
+ * Whether an address is the ecosystem's own native asset rather than a token.
258
+ *
259
+ * Every ecosystem already declares its `nativeAssetSentinel`, and this is the
260
+ * predicate that reads it. The comparison goes through {@link sameAddress}
261
+ * rather than `toLowerCase()`, which matters for exactly the families where the
262
+ * hand-written checks were wrong to begin with: Solana's, Bitcoin's and The
263
+ * Open Network's sentinels are case-significant, so lower-casing them before
264
+ * comparing can match an address that is not the sentinel.
265
+ *
266
+ * @param value - the address to test
267
+ * @param ecosystem - the ecosystem it belongs to
268
+ * @returns whether it names the native asset
269
+ */
270
+ const isNativeAsset = (value, ecosystem) => (0, exports.sameAddress)(value, (0, exports.ecosystemById)(ecosystem).nativeAssetSentinel, ecosystem);
271
+ exports.isNativeAsset = isNativeAsset;
272
+ /**
273
+ * Whether a string is a well-formed address in this ecosystem.
274
+ *
275
+ * A free function over the registry, so a caller needs the ecosystem key and
276
+ * nothing else. Reaching for viem's `isAddress` directly is the thing this
277
+ * replaces: it answers only for Ethereum and answers FALSE — confidently — for
278
+ * every valid Solana, Bitcoin, Tron and Open Network address.
279
+ *
280
+ * @param value - the string to test
281
+ * @param ecosystem - the ecosystem to test it against
282
+ * @returns whether the string is a valid address there
283
+ */
284
+ const isValidAddressIn = (value, ecosystem) => (0, exports.ecosystemById)(ecosystem).isValidAddress(value);
285
+ exports.isValidAddressIn = isValidAddressIn;
286
+ /**
287
+ * The ecosystem's canonical spelling of an address.
288
+ *
289
+ * Total and side-effect-free: an input this ecosystem cannot parse comes back
290
+ * unchanged rather than throwing, because normalizing is something callers do
291
+ * on the way to a comparison and a throw there would be a crash on a typo.
292
+ *
293
+ * @param value - the address to normalize
294
+ * @param ecosystem - the ecosystem it belongs to
295
+ * @returns the canonical form, or the input when it cannot be parsed
296
+ */
297
+ const normalizeAddressIn = (value, ecosystem) => (0, exports.ecosystemById)(ecosystem).normalizeAddress(value);
298
+ exports.normalizeAddressIn = normalizeAddressIn;
@@ -0,0 +1,346 @@
1
+ import { type Hex, type PublicClient } from 'viem';
2
+ import type { TokenBridgeInfo } from './chain-info.js';
3
+ import { type AggregatorOriginRefusal, type ConsolidatedQuote, type ConsolidatedQuoteRequest } from './consolidated-quote.js';
4
+ import type { FeeType } from './fee-type.js';
5
+ import type { RouteCandidate } from './routing/candidate.js';
6
+ import type { HopEdge, PlannedHop } from './routing/search/graph.js';
7
+ import type { ResolveNodeToken } from './routing/search/plan-route-data.js';
8
+ import type { BridgeKey, Token } from './types.js';
9
+ /**
10
+ * EXECUTION PLANS. Turns a chosen route into the ordered list of transactions
11
+ * a wallet sends, one {@link PlannedTx} at a time.
12
+ *
13
+ * Every builder here is the one the interface already signs with: the
14
+ * omnibridge call is `settings.ts`'s `transactionInputs`, the PulseX swap and
15
+ * the wrap are `routing/swap-transactions.ts`, the aggregator deposit is
16
+ * `consolidated-quote.ts`'s `aggregatorOriginCalls`, and the approval is
17
+ * `settings.ts`'s `approveCall` sized by `approvalAmounts`. This module only
18
+ * orders them and decides which approvals to skip.
19
+ *
20
+ * EVERY SPENDER IS ONE THIS CODE ALREADY KNOWS. Approvals are for the exact
21
+ * amount spent, never unlimited, and go only to:
22
+ * - the omnibridge pathway's `from` mediator, read from `config.ts`;
23
+ * - the PulseX router the edge was quoted on, read from `config.ts`;
24
+ * - an aggregator spender that `aggregatorOriginCalls` checked against a
25
+ * fixed table for its provider and chain (LI.FI's Diamond, Relay's
26
+ * depository). A quote cannot name its own spender.
27
+ *
28
+ * A PLAN IS ORDERED, AND EACH STEP WAITS FOR THE ONE BEFORE IT. An approval
29
+ * must land before the call that spends it, and a later section spends what
30
+ * the earlier one delivered. So every transaction except the last carries
31
+ * `waitForReceipt: true`.
32
+ *
33
+ * A RECEIPT IS NOT ARRIVAL. When a later section starts on a different chain
34
+ * than the one before it ends on, the earlier receipt only says the crossing
35
+ * started. The wallet must also wait for the funds to arrive on the next
36
+ * chain (the bridge indexer's delivery status) before it sends that section.
37
+ */
38
+ /** What one planned transaction does. */
39
+ export type PlannedTxKind = 'approve' | 'bridge' | 'swap' | 'wrap' | 'unwrap' | 'claim';
40
+ /** One transaction for the wallet to sign and send, in plan order. */
41
+ export type PlannedTx = {
42
+ readonly chainId: number;
43
+ readonly kind: PlannedTxKind;
44
+ readonly to: Hex;
45
+ readonly data: Hex;
46
+ readonly value: bigint;
47
+ /** The gas limit the quote names, or null to let the wallet estimate it. */
48
+ readonly gasLimit: bigint | null;
49
+ /** True when the next transaction depends on this one, so the wallet must wait for its receipt first. */
50
+ readonly waitForReceipt: boolean;
51
+ };
52
+ /**
53
+ * Reads an ERC-20 allowance on chain.
54
+ *
55
+ * @param chainId - the chain the token lives on
56
+ * @param token - the token
57
+ * @param owner - the account that sends the plan
58
+ * @param spender - the contract that pulls the token
59
+ * @returns the current allowance, in the token's base units
60
+ */
61
+ export type AllowanceReader = (chainId: number, token: Hex, owner: Hex, spender: Hex) => Promise<bigint>;
62
+ /**
63
+ * An {@link AllowanceReader} that reports no allowance anywhere, so the plan
64
+ * includes every approval. For a caller that reads allowances itself at send
65
+ * time.
66
+ */
67
+ export declare const assumeNoAllowance: AllowanceReader;
68
+ /**
69
+ * The delivery fee terms, quoted before the plan is built. They become the
70
+ * on-chain fee director, so the reader sees exactly what the router may take.
71
+ */
72
+ export type QuotedDeliveryFee = {
73
+ readonly feeType: FeeType;
74
+ /**
75
+ * The most the delivery router may take, in base units of {@link assetOut}.
76
+ * It is the fee director's `limit` in every mode: the fixed fee, the gas
77
+ * cap, or the percent fee's own cap.
78
+ */
79
+ readonly maximumFee: bigint;
80
+ /** The percent rate as a fraction of one ether (5e14 is 0.05%). Read in percent mode only. */
81
+ readonly percentFee: bigint;
82
+ /** The tip over the gas cost as a fraction of one ether. Read in gas mode only. */
83
+ readonly gasTipFee: bigint;
84
+ /** The native-coin price in the delivered token, as `priceCorrective` reads it in `settings.ts`. */
85
+ readonly priceCorrective: bigint;
86
+ /** The token the destination router delivers and takes its fee in. */
87
+ readonly assetOut: Token;
88
+ };
89
+ /**
90
+ * Whether the reader buys delivery, and at what fee. There is no default: the
91
+ * caller states it.
92
+ *
93
+ * Only a pathway whose `requiresDelivery` is true sells delivery (PulseChain
94
+ * to Ethereum or BNB Smart Chain). On the way home to PulseChain the bridge
95
+ * itself delivers, so the only accepted choice there is `shouldDeliver: false`.
96
+ */
97
+ export type DeliveryChoice = {
98
+ readonly shouldDeliver: false;
99
+ } | {
100
+ readonly shouldDeliver: true;
101
+ readonly fee: QuotedDeliveryFee;
102
+ };
103
+ /** A direct omnibridge crossing: `relayTokens`, `relayTokensAndCall`, `wrapAndRelayTokens` or `transferAndCall`. */
104
+ export type OmnibridgeLeg = {
105
+ readonly kind: 'omnibridge';
106
+ readonly bridgeKey: BridgeKey;
107
+ /** True reads only the mainnet pathways; false also reads the testnet ones. */
108
+ readonly isProd: boolean;
109
+ readonly assetIn: Token;
110
+ readonly assetLink: TokenBridgeInfo;
111
+ readonly amountIn: bigint;
112
+ readonly recipient: Hex;
113
+ readonly delivery: DeliveryChoice;
114
+ /** Whether the crossing unwraps to the native coin on arrival. Pass the value the pair allows, not only the reader's wish. */
115
+ readonly unwrap: boolean;
116
+ };
117
+ /** A PulseX swap, signed along the path its hop was priced on. */
118
+ export type PulseXSwapLeg = {
119
+ readonly kind: 'pulsex-swap';
120
+ readonly hop: Pick<PlannedHop, 'edge' | 'outcome'>;
121
+ readonly amountIn: bigint;
122
+ readonly minAmountOut: bigint;
123
+ readonly recipient: Hex;
124
+ /** The unix-seconds deadline the router enforces. */
125
+ readonly deadline: bigint;
126
+ };
127
+ /** A native-coin wrap or unwrap on the wrapped token's own contract. */
128
+ export type WrapLeg = {
129
+ readonly kind: 'wrap';
130
+ readonly edge: HopEdge;
131
+ readonly amountIn: bigint;
132
+ };
133
+ /** An aggregator's origin deposit, from a LIVE quote asked for the reader's own wallet. */
134
+ export type AggregatorLeg = {
135
+ readonly kind: 'aggregator';
136
+ readonly quote: ConsolidatedQuote;
137
+ readonly request: ConsolidatedQuoteRequest;
138
+ };
139
+ /** One signature's worth of work, in concrete terms. */
140
+ export type ExecutionLeg = OmnibridgeLeg | PulseXSwapLeg | WrapLeg | AggregatorLeg;
141
+ /** Why a leg or a section cannot be planned. */
142
+ export type ExecutionRefusal = {
143
+ readonly reason: 'amount-not-positive';
144
+ } | {
145
+ readonly reason: 'no-pathway';
146
+ } | {
147
+ readonly reason: 'delivery-not-offered';
148
+ } | {
149
+ readonly reason: 'delivery-fee-missing';
150
+ } | {
151
+ readonly reason: 'delivery-fee-unencodable';
152
+ } | {
153
+ readonly reason: 'bridge-call-refused';
154
+ } | {
155
+ readonly reason: 'swap-refused';
156
+ } | {
157
+ readonly reason: 'swap-estimate-only';
158
+ } | {
159
+ readonly reason: 'swap-quote-not-positive';
160
+ } | {
161
+ readonly reason: 'wrap-refused';
162
+ } | {
163
+ readonly reason: 'aggregator-origin-refused';
164
+ readonly origin: AggregatorOriginRefusal;
165
+ } | {
166
+ readonly reason: 'live-quote-required';
167
+ } | {
168
+ readonly reason: 'quote-provider-mismatch';
169
+ readonly quoteProvider: string;
170
+ readonly sectionCarrier: string;
171
+ } | {
172
+ readonly reason: 'paid-by-hand';
173
+ } | {
174
+ readonly reason: 'section-inputs-missing';
175
+ readonly needs: 'omnibridge' | 'swap';
176
+ } | {
177
+ readonly reason: 'section-shape';
178
+ readonly detail: string;
179
+ };
180
+ /** The delivery one omnibridge leg buys. */
181
+ export type DeliveryTerms = {
182
+ readonly status: 'not-requested';
183
+ } | {
184
+ readonly status: 'requested';
185
+ readonly feeType: FeeType;
186
+ /** The most the router may take, in base units of {@link feeToken}. */
187
+ readonly maximumFee: bigint;
188
+ readonly feeToken: Token;
189
+ };
190
+ /** The delivery a planned leg buys, so the wallet can show the fee before signing. */
191
+ export type PlannedDelivery = DeliveryTerms & {
192
+ readonly legIndex: number;
193
+ };
194
+ /** The transactions for a list of legs, or the first leg that cannot be planned. */
195
+ export type ExecutionPlan = {
196
+ readonly kind: 'planned';
197
+ readonly transactions: readonly PlannedTx[];
198
+ /** One entry per omnibridge leg, in leg order. */
199
+ readonly deliveries: readonly PlannedDelivery[];
200
+ } | {
201
+ readonly kind: 'refused';
202
+ readonly legIndex: number;
203
+ readonly refusal: ExecutionRefusal;
204
+ };
205
+ /**
206
+ * Plans the transactions for a list of legs, in order.
207
+ *
208
+ * Each leg contributes the exact approval it needs when the allowance on
209
+ * chain does not cover it (a reset to zero first when a smaller allowance
210
+ * remains), then its own call. Nothing is sent.
211
+ *
212
+ * @param options.account - the account that signs every transaction
213
+ * @param options.legs - the legs, in the order the wallet signs them
214
+ * @param options.readAllowance - reads an allowance on chain; see {@link AllowanceReader}
215
+ * @returns the ordered transactions, or the first leg that cannot be planned
216
+ */
217
+ export declare const planExecution: ({ account, legs, readAllowance, }: {
218
+ readonly account: Hex;
219
+ readonly legs: readonly ExecutionLeg[];
220
+ readonly readAllowance: AllowanceReader;
221
+ }) => Promise<ExecutionPlan>;
222
+ /**
223
+ * What the caller supplies for one signature section of a candidate. Each
224
+ * kind-specific group is read only when the section needs it.
225
+ */
226
+ export type SectionExecutionInputs = {
227
+ /** The amount this section spends, in its first token's base units. */
228
+ readonly amountIn: bigint;
229
+ /** Where this section delivers: the reader's own wallet, or their chosen address on the last section. */
230
+ readonly recipient: Hex;
231
+ /** Needed by an omnibridge section. */
232
+ readonly omnibridge?: {
233
+ readonly isProd: boolean;
234
+ readonly assetLink: TokenBridgeInfo;
235
+ readonly delivery: DeliveryChoice;
236
+ readonly unwrap: boolean;
237
+ };
238
+ /** Needed by a PulseX swap section. */
239
+ readonly swap?: {
240
+ readonly slippageBasisPoints: bigint;
241
+ /**
242
+ * The unix-seconds deadline the router enforces. A section planned late
243
+ * should pass a fresh deadline, not one chosen before the crossing before it.
244
+ */
245
+ readonly deadline: bigint;
246
+ /**
247
+ * A fresh quote of what the swap delivers for this section's `amountIn`,
248
+ * read just before signing (see {@link readPulseXSectionQuote}). When
249
+ * given, the slippage floor comes from it and not from the hop's
250
+ * search-time figure, so the hop may be an estimate. When absent, the
251
+ * floor comes from the hop, which must hold a real quote.
252
+ */
253
+ readonly quotedAmountOut?: bigint;
254
+ };
255
+ /**
256
+ * Needed by an aggregator section: the LIVE quote asked for this reader's
257
+ * wallet, recipient and amount, with the request it answered. A route's
258
+ * display price is a dry probe and cannot be signed, so the candidate's own
259
+ * quote is never used in its place.
260
+ */
261
+ readonly aggregator?: {
262
+ readonly quote: ConsolidatedQuote;
263
+ readonly request: ConsolidatedQuoteRequest;
264
+ };
265
+ };
266
+ /** What {@link planCandidateExecution} reads. */
267
+ export type CandidateExecutionInputs = {
268
+ readonly candidate: RouteCandidate;
269
+ readonly account: Hex;
270
+ readonly readAllowance: AllowanceReader;
271
+ /** The resolver the candidate was built with; turns a plan's graph node into its token. */
272
+ readonly resolveToken: ResolveNodeToken;
273
+ /**
274
+ * The index of the section that `sections[0]` plans. It defaults to 0.
275
+ * Pass it to plan a later section after the earlier ones landed, with the
276
+ * amount that actually arrived and fresh swap figures. Then `sections[i]`
277
+ * plans section `firstSectionIndex + i`.
278
+ */
279
+ readonly firstSectionIndex?: number;
280
+ /**
281
+ * One entry per section to plan now, first section first. Pass one entry
282
+ * to plan only the signature the reader can make now; pass more to plan
283
+ * later sections whose amounts are already known.
284
+ */
285
+ readonly sections: readonly SectionExecutionInputs[];
286
+ };
287
+ /**
288
+ * The transactions for the planned sections of a candidate, or the first
289
+ * section that cannot be planned. Every section index is absolute: it counts
290
+ * from the first section of the candidate, not from `firstSectionIndex`.
291
+ */
292
+ export type CandidateExecutionPlan = {
293
+ readonly kind: 'planned';
294
+ readonly transactions: readonly PlannedTx[];
295
+ /** One entry per omnibridge section planned; `legIndex` is the absolute section index. */
296
+ readonly deliveries: readonly PlannedDelivery[];
297
+ /** How many sections still follow the planned ones (after `firstSectionIndex + sections.length`). Each needs its own plan later. */
298
+ readonly remainingSectionCount: number;
299
+ } | {
300
+ readonly kind: 'refused';
301
+ readonly sectionIndex: number;
302
+ readonly refusal: ExecutionRefusal;
303
+ };
304
+ /**
305
+ * Plans the transactions for a chosen route candidate: the candidate
306
+ * `buildRouteCandidateFromPlan` returns for an engine plan (the interface's
307
+ * `buildCandidateFromEnginePlan`), or a candidate built without a plan.
308
+ *
309
+ * ONE SECTION IS ONE SIGNATURE. A plan's `signatures` groups its hops into
310
+ * sections; the section's first hop names its carrier. An omnibridge section
311
+ * becomes a crossing, a PulseX section a swap signed on its recorded path, a
312
+ * wrap section a wrap or unwrap, and any other wallet-signed carrier an
313
+ * aggregator deposit from the live quote the caller supplies. A section paid
314
+ * by hand has nothing to sign and is refused.
315
+ *
316
+ * A LATER SECTION CAN BE PLANNED ALONE. Pass `firstSectionIndex` to skip the
317
+ * sections that already landed. The wallet then plans the swap after the
318
+ * crossing arrived, from the amount that arrived, with a fresh
319
+ * `swap.quotedAmountOut` and a fresh `swap.deadline`. The slippage floor and the
320
+ * deadline are not fixed minutes before the swap is signed. Every safety check
321
+ * still applies to the later section: verified spenders, live quotes for
322
+ * aggregator sections, exact approvals.
323
+ *
324
+ * Every `sectionIndex` in a refusal and every `legIndex` in `deliveries` is
325
+ * the absolute section index.
326
+ *
327
+ * @param inputs - see {@link CandidateExecutionInputs}
328
+ * @returns the ordered transactions with the deliveries they buy, or the first section that cannot be planned
329
+ */
330
+ export declare const planCandidateExecution: (inputs: CandidateExecutionInputs) => Promise<CandidateExecutionPlan>;
331
+ /**
332
+ * Reads a fresh quote for a PulseX section: what the router's `getAmountsOut`
333
+ * says the swap delivers for `amountIn`, along the exact path the swap signs
334
+ * ({@link pulseXSwapPathForHop}) on the edge's own router. A wallet passes the
335
+ * result as `swap.quotedAmountOut` just before it signs.
336
+ *
337
+ * @param options.hop - the swap hop; its recorded path and edge name what to read
338
+ * @param options.amountIn - the amount the swap spends, in base units
339
+ * @param options.client - a client that can call `readContract`
340
+ * @returns the amount the last token of the path delivers, or null when the hop records no path, names no known router, the amount is not positive, or the read fails or returns nothing
341
+ */
342
+ export declare const readPulseXSectionQuote: ({ hop, amountIn, client, }: {
343
+ readonly hop: Pick<PlannedHop, "edge" | "outcome">;
344
+ readonly amountIn: bigint;
345
+ readonly client: Pick<PublicClient, "readContract">;
346
+ }) => Promise<bigint | null>;