@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,1074 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.assetOut = exports.assetOutKey = exports.transactionInputs = exports.pulseXSwapTransactionInputs = exports.assertCandidatePickAgrees = exports.candidatePickRefusal = exports.assertSwapAgrees = exports.swapRefusal = exports.assertCrossingAgrees = exports.crossingRefusal = exports.isUndercompensated = exports.availableCompensationMaximum = exports.desiredCompensationRatio = exports.reasonablePercentOnTopOfGasFee = exports.destinationDataParam = exports.feeDirectorStructEncoded = exports.interactingWithBridgeToken = exports.reasonablePercentFee = exports.reasonablePercentOnGasLimit = exports.reasonableFixedFee = exports.omnibridgeApproval = exports.approvalAmounts = exports.approveCall = exports.feeTypeSettings = exports.deliveryFee = exports.desiredExcessCompensationBasisPoints = exports.networkSwitchAssetOutAddress = exports.limit = exports.oneTokenInt = exports.estimatedTokenNetworkCost = exports.estimatedNativeNetworkCost = exports.estimatedFee = exports.estimatedAmountOut = exports.amountAfterBridgeFee = exports.bridgeCost = exports.amountToBridge = exports.bridgePathway = exports.basisPoints = exports.oneEther = void 0;
37
+ const viem_1 = require("viem");
38
+ const abis = __importStar(require("./abis.js"));
39
+ const config_js_1 = require("./config.js");
40
+ const fee_type_js_1 = require("./fee-type.js");
41
+ exports.oneEther = 10n ** 18n;
42
+ exports.basisPoints = 10000n;
43
+ /**
44
+ * Returns the bridge pathway (configuration) for a given bridge key, asset in, and whether to use the production pathway
45
+ * @param bridgeKey - the bridge key to use
46
+ * @param isProd - whether to use the production pathway
47
+ * @param assetIn - the asset in to bridge
48
+ * @returns the bridge pathway
49
+ */
50
+ const bridgePathway = ({ bridgeKey, isProd, assetIn, }) => (0, config_js_1.pathway)(bridgeKey, isProd, assetIn?.address) ?? null;
51
+ exports.bridgePathway = bridgePathway;
52
+ /**
53
+ * Retrieves the amount to bridge from the amount and asset in. If either of them is nil, returns 0n
54
+ * @param amountIn - the amount to bridge
55
+ * @param assetIn - the asset in to bridge
56
+ * @returns the amount to bridge
57
+ */
58
+ const amountToBridge = ({ amountIn, assetIn, }) => {
59
+ if (!amountIn || amountIn === 0n || !assetIn) {
60
+ return 0n;
61
+ }
62
+ return amountIn;
63
+ };
64
+ exports.amountToBridge = amountToBridge;
65
+ /**
66
+ * Calculates the bridge cost from the amount to bridge and bridge fee
67
+ * @param amountToBridge - the amount to bridge
68
+ * @param bridgeFee - the bridge fee
69
+ * @returns the bridge cost
70
+ */
71
+ const bridgeCost = ({ amountToBridge, bridgeFee, }) => {
72
+ if (bridgeFee === null)
73
+ return null;
74
+ return (amountToBridge * bridgeFee) / exports.oneEther;
75
+ };
76
+ exports.bridgeCost = bridgeCost;
77
+ /**
78
+ * Calculates the amount after bridge fee from the amount to bridge and bridge cost
79
+ * @param amountToBridge - the amount to bridge
80
+ * @param bridgeCost - the bridge cost
81
+ * @returns the amount after bridge fee
82
+ */
83
+ const amountAfterBridgeFee = ({ amountToBridge, bridgeCost, }) => {
84
+ if (bridgeCost === null)
85
+ return null;
86
+ const afterFee = amountToBridge - bridgeCost;
87
+ if (afterFee < 0n)
88
+ return 0n;
89
+ return afterFee;
90
+ };
91
+ exports.amountAfterBridgeFee = amountAfterBridgeFee;
92
+ /**
93
+ * Calculates the estimated amount out from the amount after bridge fee and fee
94
+ * @param amountAfterBridgeFee - the amount after bridge fee
95
+ * @param fee - the fee
96
+ * @returns the estimated amount out
97
+ */
98
+ const estimatedAmountOut = ({ amountAfterBridgeFee, fee, }) => {
99
+ if (typeof fee !== 'bigint')
100
+ return null;
101
+ if (amountAfterBridgeFee === null)
102
+ return null;
103
+ if (fee > amountAfterBridgeFee)
104
+ return 0n;
105
+ return amountAfterBridgeFee - fee;
106
+ };
107
+ exports.estimatedAmountOut = estimatedAmountOut;
108
+ /**
109
+ * Calculates the estimated fee from the amount after bridge fee, fee, percent fee, fee type, limit, and whether to deliver the costs
110
+ * @param amountAfterBridgeFee - the amount after bridge fee
111
+ * @param fee - the fee
112
+ * @param percentFee - the percent fee
113
+ * @param feeType - the fee type
114
+ * @param limit - the limit
115
+ * @param costsToDeliver - whether to deliver the costs
116
+ * @returns the estimated fee
117
+ */
118
+ const estimatedFee = ({ amountAfterBridgeFee, fee, percentFee, feeType, limit, costsToDeliver, }) => {
119
+ const fixedFee = amountAfterBridgeFee ? (amountAfterBridgeFee * percentFee) / exports.oneEther : null;
120
+ if (!costsToDeliver) {
121
+ return 0n;
122
+ }
123
+ if (feeType === fee_type_js_1.FeeType.FIXED) {
124
+ return fee;
125
+ }
126
+ else if (feeType === fee_type_js_1.FeeType.PERCENT) {
127
+ if (amountAfterBridgeFee === null)
128
+ return null;
129
+ return fixedFee;
130
+ }
131
+ else if (feeType === fee_type_js_1.FeeType.GAS_TIP) {
132
+ return limit;
133
+ }
134
+ return null;
135
+ };
136
+ exports.estimatedFee = estimatedFee;
137
+ /**
138
+ * Calculates the estimated native network cost from the estimated gas and latest base fee per gas
139
+ * @param estimatedGas - the estimated gas
140
+ * @param latestBaseFeePerGas - the latest base fee per gas
141
+ * @param requiresDelivery - whether to deliver the costs
142
+ * @returns the estimated native network cost
143
+ */
144
+ const estimatedNativeNetworkCost = ({ estimatedGas, latestBaseFeePerGas, requiresDelivery, }) => {
145
+ if (!estimatedGas || !latestBaseFeePerGas || !requiresDelivery) {
146
+ return null;
147
+ }
148
+ return BigInt(estimatedGas * latestBaseFeePerGas);
149
+ };
150
+ exports.estimatedNativeNetworkCost = estimatedNativeNetworkCost;
151
+ /**
152
+ * Calculates the estimated token network cost from the estimated native
153
+ * network cost, price corrective, decimals, and one token int
154
+ * @param estimatedNativeNetworkCost - the estimated native network cost
155
+ * @param priceCorrective - the price corrective
156
+ * @param decimals - the decimals
157
+ * @param oneTokenInt - the one token int
158
+ * @returns the estimated token network cost
159
+ */
160
+ const estimatedTokenNetworkCost = ({ estimatedNativeNetworkCost, priceCorrective, decimals, oneTokenInt, }) => {
161
+ if (!priceCorrective || !oneTokenInt || !estimatedNativeNetworkCost || !decimals) {
162
+ return null;
163
+ }
164
+ const tokenCost = (estimatedNativeNetworkCost * oneTokenInt) / priceCorrective;
165
+ return tokenCost;
166
+ };
167
+ exports.estimatedTokenNetworkCost = estimatedTokenNetworkCost;
168
+ /**
169
+ * Calculates one token of the asset in as an int
170
+ * @param assetIn - the asset in to bridge
171
+ * @returns the one token int
172
+ */
173
+ const oneTokenInt = ({ assetIn }) => {
174
+ if (!assetIn)
175
+ return 1n;
176
+ return 10n ** BigInt(assetIn.decimals);
177
+ };
178
+ exports.oneTokenInt = oneTokenInt;
179
+ /**
180
+ * Returns the limit as a bigint. Nil uses 0n
181
+ * @param lim - the limit
182
+ * @returns the limit
183
+ */
184
+ const limit = (lim) => {
185
+ if (!lim) {
186
+ return 0n;
187
+ }
188
+ return lim;
189
+ };
190
+ exports.limit = limit;
191
+ /**
192
+ * Returns the network switch asset out address from the asset out, unwrap, and to chain
193
+ * @param assetOut - the asset out
194
+ * @param unwrap - whether to unwrap
195
+ * @param toChain - the chain to switch to
196
+ * @returns the network switch asset out address
197
+ */
198
+ const networkSwitchAssetOutAddress = ({ assetOut, unwrap, toChain, }) => {
199
+ if (!assetOut)
200
+ return null;
201
+ if (!unwrap)
202
+ return assetOut.address;
203
+ const wrappedNative = config_js_1.nativeAssetOut[toChain];
204
+ // Addresses arrive in whatever case their source used (a checksummed literal
205
+ // here, a lower-cased list entry there), so equality must ignore case.
206
+ const isWrappedNative = !!wrappedNative && (0, viem_1.isAddress)(assetOut.address, { strict: false }) && (0, viem_1.isAddressEqual)(wrappedNative, assetOut.address);
207
+ return isWrappedNative ? viem_1.zeroAddress : assetOut.address;
208
+ };
209
+ exports.networkSwitchAssetOutAddress = networkSwitchAssetOutAddress;
210
+ /**
211
+ * Calculates the desired excess compensation basis points from the path, asset in, asset out, bridge key, fee type, list, and asset out address
212
+ * @param path - the path
213
+ * @param assetIn - the asset in to bridge
214
+ * @param assetOut - the asset out
215
+ * @param bridgeKey - the bridge key
216
+ * @param feeType - the fee type
217
+ * @param list - the list
218
+ * @param assetOutAddress - the asset out address
219
+ * @returns the desired excess compensation basis points
220
+ */
221
+ const desiredExcessCompensationBasisPoints = ({ path, assetIn, assetOut, bridgeKey, feeType, list, assetOutAddress, }) => {
222
+ if (!path?.requiresDelivery) {
223
+ return 0n;
224
+ }
225
+ return !assetIn
226
+ ? 0n
227
+ : feeType === fee_type_js_1.FeeType.PERCENT
228
+ ? 1000n
229
+ : (0, config_js_1.isNative)(assetIn, bridgeKey) || (0, config_js_1.isNative)(assetOut, bridgeKey)
230
+ ? 1000n
231
+ : list.has((0, viem_1.getAddress)(assetIn?.address ?? '')) ||
232
+ list.has(assetOutAddress ? (0, viem_1.getAddress)(assetOutAddress) : '0x')
233
+ ? 5000n
234
+ : 10000n;
235
+ };
236
+ exports.desiredExcessCompensationBasisPoints = desiredExcessCompensationBasisPoints;
237
+ /**
238
+ * Works out the Gibs delivery fee for a transfer, as a {@link DeliveryFee}.
239
+ *
240
+ * Each mode reads the SAME figure the delivered estimate subtracts
241
+ * ({@link estimatedFee}), so a route's cost and its delivered value reconcile:
242
+ *
243
+ * - percent: the arriving value times the rate. The router computes
244
+ * `value * multiplier / 1 ether`.
245
+ * - fixed: the fixed amount. The router takes `limit` as the fee.
246
+ * - gas: the limit. The router takes the gas cost, capped at the limit, so the
247
+ * limit is the most the reader pays and the figure the delivered estimate
248
+ * already assumes.
249
+ *
250
+ * `percentFee` must be null when the rate is not known. Passing a zero stand-in
251
+ * would state a free delivery.
252
+ *
253
+ * @param options.shouldDeliver - whether the reader asked for delivery
254
+ * @param options.routeOffersDelivery - whether this pathway delivers for a fee at all
255
+ * @param options.feeType - the delivery fee mode
256
+ * @param options.amountAfterBridgeFee - the value that reaches the destination router, or null
257
+ * @param options.percentFee - the percent rate as a fraction of one ether, or null when unknown
258
+ * @param options.fixedFee - the fixed fee in base units, or null when unknown
259
+ * @param options.limit - the gas mode cap in base units, or null when unknown
260
+ * @returns the delivery fee
261
+ */
262
+ const deliveryFee = ({ shouldDeliver, routeOffersDelivery, feeType, amountAfterBridgeFee, percentFee, fixedFee, limit, }) => {
263
+ if (!shouldDeliver || !routeOffersDelivery) {
264
+ return { status: 'not-requested' };
265
+ }
266
+ if (feeType === fee_type_js_1.FeeType.FIXED) {
267
+ return { status: 'requested', amount: fixedFee, rate: null };
268
+ }
269
+ if (feeType === fee_type_js_1.FeeType.GAS_TIP) {
270
+ return { status: 'requested', amount: limit, rate: null };
271
+ }
272
+ if (amountAfterBridgeFee === null || percentFee === null) {
273
+ return { status: 'requested', amount: null, rate: percentFee };
274
+ }
275
+ return {
276
+ status: 'requested',
277
+ amount: (amountAfterBridgeFee * percentFee) / exports.oneEther,
278
+ rate: percentFee,
279
+ };
280
+ };
281
+ exports.deliveryFee = deliveryFee;
282
+ /**
283
+ * The four-bit fee-type settings word a fee director carries.
284
+ *
285
+ * - bit 0: fixed fee mode.
286
+ * - bit 1: unwrap the delivered token to the native coin.
287
+ * - bit 2: exclude the priority fee from the delivery cost. Always set.
288
+ * - bit 3: percent fee mode.
289
+ *
290
+ * @param options.feeType - the delivery fee mode
291
+ * @param options.unwrap - whether the delivery unwraps to the native coin
292
+ * @returns the settings word for {@link feeDirectorStructEncoded}
293
+ */
294
+ const feeTypeSettings = ({ feeType, unwrap }) => {
295
+ const fixedBit = feeType === fee_type_js_1.FeeType.FIXED ? 1n : 0n;
296
+ const unwrapBit = unwrap ? 1n : 0n;
297
+ const excludePriorityBit = 1n;
298
+ const percentBit = feeType === fee_type_js_1.FeeType.PERCENT ? 1n : 0n;
299
+ return (percentBit << 3n) | (excludePriorityBit << 2n) | (unwrapBit << 1n) | fixedBit;
300
+ };
301
+ exports.feeTypeSettings = feeTypeSettings;
302
+ /**
303
+ * The ERC-20 `approve` call, as a target, a value and calldata. The
304
+ * interface's approval broadcast and the SDK's execution planner both build it
305
+ * here.
306
+ *
307
+ * @param options.token - the token to approve
308
+ * @param options.spender - the address allowed to pull it
309
+ * @param options.amount - the allowance to set
310
+ * @returns the call
311
+ */
312
+ const approveCall = ({ token, spender, amount, }) => ({
313
+ to: token,
314
+ value: 0n,
315
+ data: (0, viem_1.encodeFunctionData)({ abi: viem_1.erc20Abi, functionName: 'approve', args: [spender, amount] }),
316
+ });
317
+ exports.approveCall = approveCall;
318
+ /**
319
+ * The `approve` amounts to send, in order, so the spender may pull exactly
320
+ * `minimum`. Empty when the allowance on chain already covers it.
321
+ *
322
+ * EXACT, NEVER UNLIMITED. An unlimited approval lets the spender pull the
323
+ * reader's whole balance for as long as the approval stands, so a later fault
324
+ * in that contract, or a spender a compromised quote named, costs everything
325
+ * rather than one transfer. The owner chose exact approvals everywhere
326
+ * (2026-10-07); the interface and the SDK's execution planner both decide
327
+ * here.
328
+ *
329
+ * A SHORT, NON-ZERO ALLOWANCE IS RESET TO ZERO FIRST. Some tokens (Tether on
330
+ * Ethereum is the known one) revert an `approve` that changes one non-zero
331
+ * allowance into another. Exact approvals leave such remainders more often,
332
+ * because an aggregator may spend less than it was allowed. A reset first
333
+ * works for every token, at the cost of one extra transaction in that case.
334
+ *
335
+ * @param options.allowance - the allowance on chain now
336
+ * @param options.minimum - the amount the next transaction pulls
337
+ * @returns the amounts to approve, in order: none, `[minimum]`, or `[0n, minimum]`
338
+ */
339
+ const approvalAmounts = ({ allowance, minimum, }) => {
340
+ if (allowance >= minimum)
341
+ return [];
342
+ if (allowance === 0n)
343
+ return [minimum];
344
+ return [0n, minimum];
345
+ };
346
+ exports.approvalAmounts = approvalAmounts;
347
+ /**
348
+ * The allowance a direct omnibridge crossing needs, or null when it needs none.
349
+ *
350
+ * Reads the SAME predicate {@link transactionInputs} uses to pick the call: a
351
+ * token the bridge minted ({@link interactingWithBridgeToken}) is burned by
352
+ * `transferAndCall` and needs no allowance, and the native coin is sent as
353
+ * value. Every other token is pulled by the pathway's `from` mediator through
354
+ * `relayTokens` or `relayTokensAndCall`.
355
+ *
356
+ * @param options.bridgePathway - the crossing's pathway
357
+ * @param options.assetIn - the token the crossing spends
358
+ * @param options.assetLink - the token's bridge link
359
+ * @param options.amountToBridge - the amount the crossing pulls
360
+ * @returns the approval the crossing needs, or null
361
+ */
362
+ const omnibridgeApproval = ({ bridgePathway, assetIn, assetLink, amountToBridge, }) => {
363
+ if (assetIn.address === viem_1.zeroAddress)
364
+ return null;
365
+ if ((0, exports.interactingWithBridgeToken)({ assetLink, assetInAddress: assetIn.address }))
366
+ return null;
367
+ return {
368
+ chainId: assetIn.chainId,
369
+ token: assetIn.address,
370
+ spender: bridgePathway.from,
371
+ minimum: amountToBridge,
372
+ };
373
+ };
374
+ exports.omnibridgeApproval = omnibridgeApproval;
375
+ /**
376
+ * Calculates the reasonable fixed fee from the estimated token network cost and desired excess compensation basis points
377
+ * @param estimatedTokenNetworkCost - the estimated token network cost
378
+ * @param desiredExcessCompensationBasisPoints - the desired excess compensation basis points
379
+ * @returns the reasonable fixed fee
380
+ */
381
+ const reasonableFixedFee = ({ estimatedTokenNetworkCost, desiredExcessCompensationBasisPoints, }) => {
382
+ if (!estimatedTokenNetworkCost) {
383
+ return null;
384
+ }
385
+ return ((estimatedTokenNetworkCost * (25000n + desiredExcessCompensationBasisPoints)) / exports.basisPoints);
386
+ };
387
+ exports.reasonableFixedFee = reasonableFixedFee;
388
+ /**
389
+ * Calculates the reasonable percent on gas limit from the gas tip fee and estimated token network cost
390
+ * @param gasTipFee - the gas tip fee
391
+ * @param estimatedTokenNetworkCost - the estimated token network cost
392
+ * @returns the reasonable percent on gas limit
393
+ */
394
+ const reasonablePercentOnGasLimit = ({ gasTipFee, estimatedTokenNetworkCost, }) => {
395
+ return ((25000n * ((exports.oneEther + (gasTipFee ?? 0n)) * (estimatedTokenNetworkCost ?? 0n))) /
396
+ (exports.oneEther * exports.basisPoints));
397
+ };
398
+ exports.reasonablePercentOnGasLimit = reasonablePercentOnGasLimit;
399
+ /**
400
+ * Calculates the reasonable percent fee from the reasonable fixed fee and amount after bridge fee
401
+ * @param reasonableFixedFee - the reasonable fixed fee
402
+ * @param amountAfterBridgeFee - the amount after bridge fee
403
+ * @returns the reasonable percent fee
404
+ */
405
+ const reasonablePercentFee = ({ reasonableFixedFee, amountAfterBridgeFee, }) => {
406
+ if (!reasonableFixedFee) {
407
+ return null;
408
+ }
409
+ if (!amountAfterBridgeFee) {
410
+ return null;
411
+ }
412
+ const highFee = amountAfterBridgeFee / 10n;
413
+ const basisFeeTruncator = 10n ** 14n;
414
+ const max = 1000n * basisFeeTruncator;
415
+ const min = 5n * basisFeeTruncator;
416
+ if (highFee < reasonableFixedFee) {
417
+ return max; // 10%
418
+ }
419
+ const highResPercent = (reasonableFixedFee * exports.oneEther) / amountAfterBridgeFee;
420
+ if (highResPercent < min) {
421
+ return min;
422
+ }
423
+ else if (highResPercent > max) {
424
+ return max;
425
+ }
426
+ const basisPoint = highResPercent / basisFeeTruncator;
427
+ return basisPoint * basisFeeTruncator;
428
+ };
429
+ exports.reasonablePercentFee = reasonablePercentFee;
430
+ /**
431
+ * Returns whether the asset in address is interacting with a bridge token
432
+ * @param assetLink - the asset link
433
+ * @param assetInAddress - the asset in address
434
+ * @returns whether the asset in address is interacting with a bridge token
435
+ */
436
+ const interactingWithBridgeToken = ({ assetLink, assetInAddress, }) => {
437
+ const { toForeign, toHome } = assetLink || {};
438
+ const { foreign } = toForeign || {};
439
+ const { home } = toHome || {};
440
+ if (!assetInAddress)
441
+ return false;
442
+ return !!((foreign && (0, viem_1.getAddress)(foreign) === (0, viem_1.getAddress)(assetInAddress)) ||
443
+ (home && (0, viem_1.getAddress)(home) === (0, viem_1.getAddress)(assetInAddress)));
444
+ };
445
+ exports.interactingWithBridgeToken = interactingWithBridgeToken;
446
+ /**
447
+ * Calculates the fee director struct encoded from the recipient, bridge pathway, fee type, price corrective, gas tip fee, percent fee, fee type settings, limit, and asset out
448
+ * @param recipient - the recipient
449
+ * @param bridgePathway - the bridge pathway
450
+ * @param feeType - the fee type
451
+ * @param priceCorrective - the price corrective
452
+ * @param gasTipFee - the gas tip fee
453
+ * @param percentFee - the percent fee
454
+ * @param feeTypeSettings - the fee type settings
455
+ * @param limit - the limit
456
+ * @param assetOut - the asset out
457
+ * @returns the fee director struct encoded
458
+ */
459
+ const feeDirectorStructEncoded = ({ recipient, bridgePathway, feeType, priceCorrective, gasTipFee, percentFee, feeTypeSettings, limit, assetOut, }) => {
460
+ if (!assetOut || !bridgePathway) {
461
+ return null;
462
+ }
463
+ if (!bridgePathway.requiresDelivery) {
464
+ return null;
465
+ }
466
+ if (!priceCorrective) {
467
+ return null;
468
+ }
469
+ let multiplier = 0n;
470
+ if (feeType === fee_type_js_1.FeeType.GAS_TIP && priceCorrective > 0n) {
471
+ multiplier =
472
+ ((exports.oneEther + (gasTipFee ?? 0n)) * 10n ** BigInt(assetOut.decimals)) / priceCorrective;
473
+ }
474
+ else if (feeType === fee_type_js_1.FeeType.PERCENT) {
475
+ multiplier = percentFee ?? 0n;
476
+ }
477
+ if (!recipient || !(0, viem_1.isAddress)(recipient)) {
478
+ return null;
479
+ }
480
+ return (0, viem_1.encodeAbiParameters)(abis.feeDeliveryStruct, [
481
+ [recipient, feeTypeSettings, limit, multiplier],
482
+ ]);
483
+ };
484
+ exports.feeDirectorStructEncoded = feeDirectorStructEncoded;
485
+ /**
486
+ * Calculates the destination data param from the recipient, bridge pathway, asset in, destination router, fee director struct encoded, asset link, should deliver, and unwrap
487
+ * @param recipient - the recipient
488
+ * @param bridgePathway - the bridge pathway
489
+ * @param assetIn - the asset in to bridge
490
+ * @param destinationRouter - the destination router
491
+ * @param feeDirectorStructEncoded - the fee director struct encoded
492
+ * @param assetLink - the asset link
493
+ * @param shouldDeliver - whether to deliver the costs
494
+ * @param unwrap - whether to unwrap
495
+ * @returns the destination data param
496
+ */
497
+ const destinationDataParam = ({ recipient, bridgePathway, assetIn, destinationRouter, feeDirectorStructEncoded, assetLink, shouldDeliver, unwrap, }) => {
498
+ // const recipient = input.recipient.value
499
+ if (!recipient) {
500
+ return null;
501
+ }
502
+ if (!bridgePathway || !assetIn) {
503
+ return null;
504
+ }
505
+ if (!destinationRouter) {
506
+ return null;
507
+ }
508
+ // Only a delivery needs the fee director. A crossing without delivery sends
509
+ // to the recipient, whatever the fee director would have said.
510
+ if (bridgePathway.requiresDelivery && shouldDeliver && !feeDirectorStructEncoded) {
511
+ return null;
512
+ }
513
+ if (!assetLink) {
514
+ return null;
515
+ }
516
+ if (bridgePathway.requiresDelivery) {
517
+ // going from home to foreign
518
+ if (!shouldDeliver) {
519
+ // act like a regular bridge
520
+ return recipient;
521
+ }
522
+ // going from foreign to home
523
+ if (feeDirectorStructEncoded) {
524
+ return (0, viem_1.concatHex)([destinationRouter, feeDirectorStructEncoded]);
525
+ }
526
+ return recipient;
527
+ }
528
+ if (!unwrap) {
529
+ return recipient;
530
+ }
531
+ // unwrap wpls->pls
532
+ return (0, viem_1.concatHex)([destinationRouter, recipient]);
533
+ };
534
+ exports.destinationDataParam = destinationDataParam;
535
+ /**
536
+ * Converts a desired excess compensation basis point value into a percentage as an integer, with the denominator assumed to be 1e18
537
+ * @param desiredExcessCompensationBasisPoints - the desired excess compensation basis points
538
+ * @returns the reasonable percent on top of gas fee
539
+ */
540
+ const reasonablePercentOnTopOfGasFee = ({ desiredExcessCompensationBasisPoints, }) => {
541
+ return desiredExcessCompensationBasisPoints * (exports.oneEther / exports.basisPoints);
542
+ };
543
+ exports.reasonablePercentOnTopOfGasFee = reasonablePercentOnTopOfGasFee;
544
+ /**
545
+ * Calculates the desired compensation ratio from the desired excess compensation basis points
546
+ * @param desiredExcessCompensationBasisPoints - the desired excess compensation basis points
547
+ * @returns the desired compensation ratio
548
+ */
549
+ const desiredCompensationRatio = ({ desiredExcessCompensationBasisPoints, }) => {
550
+ return exports.oneEther + (desiredExcessCompensationBasisPoints * exports.oneEther) / exports.basisPoints;
551
+ };
552
+ exports.desiredCompensationRatio = desiredCompensationRatio;
553
+ /**
554
+ * Calculates the available compensation maximum from the amount after bridge fee, percent fee, fee type, fixed fee, and limit
555
+ * @param amountAfterBridgeFee - the amount after bridge fee
556
+ * @param percentFee - the percent fee
557
+ * @param feeType - the fee type
558
+ * @param fixedFee - the fixed fee
559
+ * @param limit - the limit
560
+ * @returns the available compensation maximum
561
+ */
562
+ const availableCompensationMaximum = ({ amountAfterBridgeFee, percentFee, feeType, fixedFee, limit, }) => {
563
+ if (feeType === fee_type_js_1.FeeType.PERCENT) {
564
+ if (amountAfterBridgeFee === null)
565
+ return null;
566
+ return (amountAfterBridgeFee * (percentFee ?? 0n)) / exports.oneEther;
567
+ }
568
+ else if (feeType === fee_type_js_1.FeeType.GAS_TIP) {
569
+ return limit;
570
+ }
571
+ else if (feeType === fee_type_js_1.FeeType.FIXED) {
572
+ return fixedFee ?? 0n;
573
+ }
574
+ return 0n;
575
+ };
576
+ exports.availableCompensationMaximum = availableCompensationMaximum;
577
+ /**
578
+ * Determines if the bridge is undercompensated based on network costs vs compensation limit using desired compensation rate
579
+ * @param estimatedTokenNetworkCost - the estimated token network cost
580
+ * @param feeType - the fee type
581
+ * @param limit - the maximum compensation limit
582
+ * @param amountAfterBridgeFee - the amount after bridge fee
583
+ * @param desiredExcessCompensationBasisPoints - the desired excess compensation basis points
584
+ * @returns whether the bridge is undercompensated
585
+ */
586
+ const isUndercompensated = ({ estimatedTokenNetworkCost, feeType, limit, amountAfterBridgeFee, desiredExcessCompensationBasisPoints, }) => {
587
+ // No undercompensation if no amount to bridge
588
+ if (!amountAfterBridgeFee || amountAfterBridgeFee <= 0n) {
589
+ return false;
590
+ }
591
+ // GAS_TIP fee type doesn't have undercompensation issues
592
+ if (feeType === fee_type_js_1.FeeType.GAS_TIP) {
593
+ return false;
594
+ }
595
+ // No network cost estimate means we can't determine undercompensation
596
+ if (!estimatedTokenNetworkCost) {
597
+ return false;
598
+ }
599
+ // Calculate desired compensation using the actual desired compensation ratio
600
+ const desiredCompensationRatio = exports.oneEther + (desiredExcessCompensationBasisPoints * exports.oneEther) / exports.basisPoints;
601
+ const desiredCompensationForNetworkCost = (estimatedTokenNetworkCost * desiredCompensationRatio) / exports.oneEther;
602
+ // Undercompensated if desired compensation exceeds the limit
603
+ return desiredCompensationForNetworkCost > limit;
604
+ };
605
+ exports.isUndercompensated = isUndercompensated;
606
+ /**
607
+ * Why a bridge key must not be built into a transaction for the pair on screen,
608
+ * or null when the two agree.
609
+ *
610
+ * WHY THIS EXISTS, in the reader's words: "i just tried to swap from weth from
611
+ * ethereum on pls, to pls, and the calldata that i must have signed was to
612
+ * bridge back from pls to eth". A selection of PulseChain on BOTH sides is a
613
+ * swap; it has no pathway, so the bridge key kept whatever crossing it last
614
+ * held — or the address bar was repaired to a crossing — and the settings
615
+ * cascade went on building a real, signable transfer of the reader's bridged
616
+ * wrapped ether to Ethereum while the screen still named PulseChain.
617
+ *
618
+ * Three refusals, and each one is a separate way the two can part company:
619
+ *
620
+ * - A SAME-CHAIN SELECTION IS NEVER A CROSSING. Origin and destination on one
621
+ * chain describes a swap. No omnibridge pathway can serve it, so any pathway
622
+ * reached for here belongs to some other journey.
623
+ * - THE PATHWAY MUST LEAVE THE CHAIN THE READER'S FUNDS ARE ON. A key whose
624
+ * source chain differs spends a token the reader is not looking at.
625
+ * - THE PATHWAY MUST LAND WHERE THE READER ASKED. This is the reported defect:
626
+ * the destination silently became Ethereum.
627
+ *
628
+ * `signedCrossing` is `null` for a call no reader composed — the aggregator's
629
+ * executor call built by `buildDestinationCalldata`, where the chain pair IS
630
+ * the pathway and there is no screen to disagree with. Nullable rather than
631
+ * optional so every caller has to decide, and the decision is visible at the
632
+ * call site.
633
+ *
634
+ * @param bridgeKey - the key the pathway was resolved from
635
+ * @param signedCrossing - the pair on screen, or null when no surface composed it
636
+ * @returns the reason to refuse, or null when the two agree
637
+ */
638
+ const crossingRefusal = ({ bridgeKey, signedCrossing, }) => {
639
+ // `undefined` is treated as `null` here, and only here. The field is REQUIRED
640
+ // by the type, so no compiled caller can omit it — but a test double that
641
+ // returns a partial object can, and a crash inside the settings cascade blanks
642
+ // the page rather than refusing a transaction.
643
+ if (signedCrossing === null || signedCrossing === undefined) {
644
+ return null;
645
+ }
646
+ const { originChainId, destinationChainId } = signedCrossing;
647
+ if (originChainId === destinationChainId) {
648
+ return `Refusing to build a crossing for a selection that stays on chain ${originChainId}. Origin and destination are the same chain, which is a swap, not a bridge.`;
649
+ }
650
+ if (!bridgeKey) {
651
+ return `Refusing to build a crossing from chain ${originChainId} to chain ${destinationChainId}: no bridge key was resolved for it.`;
652
+ }
653
+ const pathwayOriginChainId = Number(bridgeKey[1]);
654
+ const pathwayDestinationChainId = Number(bridgeKey[2]);
655
+ if (pathwayOriginChainId !== originChainId) {
656
+ return `Refusing to build a crossing that leaves chain ${pathwayOriginChainId} while the selection starts on chain ${originChainId}.`;
657
+ }
658
+ if (pathwayDestinationChainId !== destinationChainId) {
659
+ return `Refusing to build a crossing that delivers on chain ${pathwayDestinationChainId} while the selection asks for chain ${destinationChainId}.`;
660
+ }
661
+ return null;
662
+ };
663
+ exports.crossingRefusal = crossingRefusal;
664
+ /**
665
+ * Throws when the bridge key and the pair on screen describe different journeys.
666
+ *
667
+ * The LOUD half of {@link crossingRefusal}. {@link transactionInputs} runs
668
+ * during render, where a throw would blank the application, so it refuses
669
+ * quietly by returning null and the button it feeds stays inert. This is for
670
+ * the broadcast funnel, where a disagreement means something reconstructed the
671
+ * call another way and the reader is one signature from a transfer they never
672
+ * asked for — there, silence is the worse failure.
673
+ *
674
+ * @param bridgeKey - the key the pathway was resolved from
675
+ * @param signedCrossing - the pair on screen, or null when no surface composed it
676
+ * @throws when the two describe different journeys
677
+ */
678
+ const assertCrossingAgrees = ({ bridgeKey, signedCrossing, }) => {
679
+ const refusal = (0, exports.crossingRefusal)({ bridgeKey, signedCrossing });
680
+ if (refusal !== null) {
681
+ throw new Error(refusal);
682
+ }
683
+ };
684
+ exports.assertCrossingAgrees = assertCrossingAgrees;
685
+ /**
686
+ * Why a same-chain PulseX swap transaction must not be built for the leg on
687
+ * screen, or null when they agree. The swap-side sibling of
688
+ * {@link crossingRefusal}.
689
+ *
690
+ * Two refusals, each a separate way the two can part company:
691
+ *
692
+ * - THE LEG ON SCREEN NAMES A CROSSING. A caller building a swap transaction
693
+ * while the reader is looking at a two-chain crossing would sign the wrong
694
+ * kind of thing for what is on screen.
695
+ * - THE SWAP DOES NOT EXECUTE ON THE CHAIN THE READER IS LOOKING AT. A stale
696
+ * candidate built for a chain the address bar has since left.
697
+ *
698
+ * @param signedLeg - what the surface believes this signature does, or null
699
+ * when no surface composed it
700
+ * @param chainId - the chain the candidate swap transaction actually executes on
701
+ * @returns the reason to refuse, or null when the two agree
702
+ */
703
+ const swapRefusal = ({ signedLeg, chainId, }) => {
704
+ // `undefined` treated as `null`, matching `crossingRefusal`'s own guard: the
705
+ // field is required by the type, so only a test double or a crash inside the
706
+ // cascade could omit it.
707
+ if (signedLeg === null || signedLeg === undefined) {
708
+ return null;
709
+ }
710
+ if (signedLeg.kind !== 'swap') {
711
+ return `Refusing to build a same-chain swap for a selection that names a ${signedLeg.kind} (chain ${signedLeg.originChainId} to chain ${signedLeg.destinationChainId}).`;
712
+ }
713
+ if (chainId === null) {
714
+ return `Refusing to build a same-chain swap: no chain was resolved for it.`;
715
+ }
716
+ if (signedLeg.chainId !== chainId) {
717
+ return `Refusing to build a swap on chain ${chainId} while the selection names chain ${signedLeg.chainId}.`;
718
+ }
719
+ return null;
720
+ };
721
+ exports.swapRefusal = swapRefusal;
722
+ /**
723
+ * Throws when the leg on screen and the candidate swap transaction describe
724
+ * different journeys. The swap-side sibling of {@link assertCrossingAgrees} —
725
+ * loud where {@link swapRefusal} is quiet, for the same reason: this runs one
726
+ * step before the wallet, where silence is what lets a reader sign.
727
+ *
728
+ * @param signedLeg - what the surface believes this signature does, or null
729
+ * @param chainId - the chain the candidate swap transaction actually executes on
730
+ * @throws when the two describe different journeys
731
+ */
732
+ const assertSwapAgrees = ({ signedLeg, chainId, }) => {
733
+ const refusal = (0, exports.swapRefusal)({ signedLeg, chainId });
734
+ if (refusal !== null) {
735
+ throw new Error(refusal);
736
+ }
737
+ };
738
+ exports.assertSwapAgrees = assertSwapAgrees;
739
+ /**
740
+ * Why a candidate must not be signed for the leg and section a caller is
741
+ * about to build calldata for, or null when they agree. The candidate-pick
742
+ * sibling of {@link crossingRefusal}/{@link swapRefusal}.
743
+ *
744
+ * UNLIKE THOSE TWO, A MISSING PICK IS ITSELF A REFUSAL. `crossingRefusal` and
745
+ * `swapRefusal` let a null leg through because some calls compose no screen at
746
+ * all (the aggregator's own executor call). A candidate-signing sender always
747
+ * has a screen — the route the reader picked — so a candidate id with no
748
+ * recorded leg is exactly the gap this type exists to close: `candidateId`
749
+ * alone used to be treated as sufficient identity, and this function is what
750
+ * stops it from being treated that way again.
751
+ *
752
+ * @param pick - what the route recorded it picked, or null/undefined when the
753
+ * producer that built the route never set one
754
+ * @param leg - the leg the caller is about to build calldata for
755
+ * @param sectionIndex - the route section the caller is about to build
756
+ * calldata for
757
+ * @returns the reason to refuse, or null when they agree
758
+ */
759
+ const candidatePickRefusal = ({ pick, leg, sectionIndex, }) => {
760
+ if (pick === null || pick === undefined) {
761
+ return `Refusing to sign a ${leg} at section ${sectionIndex}: the route named no candidate to sign.`;
762
+ }
763
+ if (pick.leg !== leg) {
764
+ return `Refusing to sign candidate ${pick.candidateId}'s ${pick.leg} leg as a ${leg}: the route picked a different kind of leg.`;
765
+ }
766
+ if (pick.sectionIndex !== sectionIndex) {
767
+ return `Refusing to sign candidate ${pick.candidateId} for section ${sectionIndex}: the route picked it for section ${pick.sectionIndex}.`;
768
+ }
769
+ return null;
770
+ };
771
+ exports.candidatePickRefusal = candidatePickRefusal;
772
+ /**
773
+ * Throws when a candidate pick and the leg/section a caller is about to build
774
+ * calldata for describe different signatures. The candidate-pick sibling of
775
+ * {@link assertCrossingAgrees}/{@link assertSwapAgrees} — loud where {@link
776
+ * candidatePickRefusal} is quiet, for the same reason: this runs one step
777
+ * before the wallet, where silence is what lets a reader sign the wrong thing.
778
+ *
779
+ * @param pick - what the route recorded it picked, or null
780
+ * @param leg - the leg the caller is about to build calldata for
781
+ * @param sectionIndex - the route section the caller is about to build
782
+ * calldata for
783
+ * @throws when the pick and the leg/section being built describe different
784
+ * signatures
785
+ */
786
+ const assertCandidatePickAgrees = ({ pick, leg, sectionIndex, }) => {
787
+ const refusal = (0, exports.candidatePickRefusal)({ pick, leg, sectionIndex });
788
+ if (refusal !== null) {
789
+ throw new Error(refusal);
790
+ }
791
+ };
792
+ exports.assertCandidatePickAgrees = assertCandidatePickAgrees;
793
+ /**
794
+ * Calculates the same-chain PulseX swap transaction inputs, or null when the
795
+ * inputs cannot form a call — including when the leg on screen and the swap's
796
+ * own chain disagree. The swap-side sibling of {@link transactionInputs}.
797
+ *
798
+ * SAME SHAPE AS `transactionInputs`, deliberately: `{ to, value, data } | null`,
799
+ * so a caller can dispatch either builder's result through one `sendTransaction`
800
+ * without a second shape to handle.
801
+ *
802
+ * WRAPPING AND UNWRAPPING THE NATIVE COIN USE THE ROUTER'S OWN NATIVE-COIN
803
+ * FUNCTIONS, not a separate deposit/withdraw step — one router contract wraps
804
+ * on the way in (`swapExactETHForTokens`) and unwraps on the way out
805
+ * (`swapExactTokensForETH`), the same contract `swapExactTokensForTokens`
806
+ * already targets when neither side is native.
807
+ *
808
+ * @param signedLeg - what the surface believes this signature does, or null
809
+ * @param chainId - the chain the swap actually executes on
810
+ * @param routerAddress - the PulseX router this swap is sent to, or null when
811
+ * none is deployed for this chain
812
+ * @param fromTokenAddress - the input token address, or the zero address for
813
+ * the chain's native coin
814
+ * @param toTokenAddress - the output token address, or the zero address for
815
+ * the chain's native coin
816
+ * @param swapPath - the ordered swap path — for a route-search hop, the one
817
+ * its quote was priced along (`pulseXSwapPathForHop`),
818
+ * already expressed in the router's own token addresses — the wrapped-native
819
+ * token stands in for either native end
820
+ * @param amountIn - the amount to swap, in the input token's base units
821
+ * @param minAmountOut - the minimum acceptable output after slippage, in the
822
+ * output token's base units
823
+ * @param recipient - the address the swap delivers to
824
+ * @param deadline - the unix-seconds deadline the router enforces
825
+ * @returns the transaction inputs, or null when the inputs cannot form a call
826
+ */
827
+ const pulseXSwapTransactionInputs = ({ signedLeg, chainId, routerAddress, fromTokenAddress, toTokenAddress, swapPath, amountIn, minAmountOut, recipient, deadline, }) => {
828
+ // FIRST, BEFORE ANY ENCODING — see `transactionInputs`'s identical note.
829
+ if ((0, exports.swapRefusal)({ signedLeg, chainId }) !== null) {
830
+ return null;
831
+ }
832
+ if (!routerAddress) {
833
+ return null;
834
+ }
835
+ if (!recipient || !(0, viem_1.isAddress)(recipient) || recipient === viem_1.zeroAddress) {
836
+ return null;
837
+ }
838
+ if (swapPath.length < 2) {
839
+ return null;
840
+ }
841
+ if (amountIn <= 0n) {
842
+ return null;
843
+ }
844
+ const fromIsNative = fromTokenAddress === viem_1.zeroAddress;
845
+ const toIsNative = toTokenAddress === viem_1.zeroAddress;
846
+ // Native-to-native names no real swap — there is nothing for the router to do.
847
+ if (fromIsNative && toIsNative) {
848
+ return null;
849
+ }
850
+ if (fromIsNative) {
851
+ return {
852
+ to: routerAddress,
853
+ value: amountIn,
854
+ data: (0, viem_1.encodeFunctionData)({
855
+ abi: abis.univ2Router,
856
+ functionName: 'swapExactETHForTokens',
857
+ args: [minAmountOut, swapPath, recipient, deadline],
858
+ }),
859
+ };
860
+ }
861
+ if (toIsNative) {
862
+ return {
863
+ to: routerAddress,
864
+ value: 0n,
865
+ data: (0, viem_1.encodeFunctionData)({
866
+ abi: abis.univ2Router,
867
+ functionName: 'swapExactTokensForETH',
868
+ args: [amountIn, minAmountOut, swapPath, recipient, deadline],
869
+ }),
870
+ };
871
+ }
872
+ return {
873
+ to: routerAddress,
874
+ value: 0n,
875
+ data: (0, viem_1.encodeFunctionData)({
876
+ abi: abis.univ2Router,
877
+ functionName: 'swapExactTokensForTokens',
878
+ args: [amountIn, minAmountOut, swapPath, recipient, deadline],
879
+ }),
880
+ };
881
+ };
882
+ exports.pulseXSwapTransactionInputs = pulseXSwapTransactionInputs;
883
+ /**
884
+ * Calculates the transaction inputs from the bridge pathway, asset in, recipient, account, asset link, destination data param, amount to bridge, fee director struct encoded, and should deliver
885
+ * @param bridgeKey - the key the pathway was resolved from, for {@link crossingRefusal}
886
+ * @param signedCrossing - the chain pair on screen, or null when no surface composed it
887
+ * @param bridgePathway - the bridge pathway to use
888
+ * @param assetIn - the asset in to bridge
889
+ * @param recipient - the recipient of the bridge
890
+ * @param account - the account to bridge from
891
+ * @param assetLink - the asset link to use
892
+ * @param destinationDataParam - the destination data param to use
893
+ * @param amountToBridge - the amount to bridge
894
+ * @param feeDirectorStructEncoded - the fee director struct encoded to use
895
+ * @param shouldDeliver - whether to deliver the tokens to the recipient
896
+ * @returns the transaction inputs, or null when the inputs cannot form a call —
897
+ * including when the pathway crosses somewhere other than the pair on screen
898
+ */
899
+ const transactionInputs = ({ bridgeKey, signedCrossing, bridgePathway, assetIn, recipient, account, assetLink, destinationDataParam, amountToBridge, feeDirectorStructEncoded, shouldDeliver, }) => {
900
+ // FIRST, BEFORE ANY ENCODING. Every branch below writes a real mediator call;
901
+ // by the time one is chosen the disagreement is already encoded.
902
+ if ((0, exports.crossingRefusal)({ bridgeKey, signedCrossing }) !== null) {
903
+ return null;
904
+ }
905
+ if (!bridgePathway) {
906
+ return null;
907
+ }
908
+ // check that recipient is valid
909
+ if (!recipient || !(0, viem_1.isAddress)(recipient) || recipient === viem_1.zeroAddress) {
910
+ return null;
911
+ }
912
+ // check that wallet account is valid
913
+ if (!account || !(0, viem_1.isAddress)(account) || account === viem_1.zeroAddress) {
914
+ return null;
915
+ }
916
+ // check that asset in is valid
917
+ if (!assetIn) {
918
+ return null;
919
+ }
920
+ // check that asset link is valid
921
+ if (!assetLink) {
922
+ return null;
923
+ }
924
+ let value = 0n;
925
+ // we are moving "from" this side, so we need to call a function on the "from" address
926
+ // only relevant for the relayTokens(AndCall) pathway outside of native tokens
927
+ let toAddress = bridgePathway.from;
928
+ let data = '0x';
929
+ const inputIsBridgeToken = (0, exports.interactingWithBridgeToken)({
930
+ assetLink,
931
+ assetInAddress: assetIn.address,
932
+ });
933
+ if (inputIsBridgeToken) {
934
+ // when interacting with a bridged token, we need to call the token address directly
935
+ toAddress = assetIn.address;
936
+ value = 0n;
937
+ // if we want delivery of the tokens (going from home to foreign) then we need to have the foreign data param
938
+ // and it needs to start with the destination router
939
+ if (!destinationDataParam) {
940
+ return null;
941
+ }
942
+ data = bridgePathway.usesExtraParam
943
+ ? (0, viem_1.encodeFunctionData)({
944
+ abi: abis.erc677ExtraInput,
945
+ functionName: 'transferAndCall',
946
+ args: [bridgePathway.from, amountToBridge, destinationDataParam, account],
947
+ })
948
+ : (0, viem_1.encodeFunctionData)({
949
+ abi: abis.erc677,
950
+ functionName: 'transferAndCall',
951
+ args: [bridgePathway.from, amountToBridge, destinationDataParam],
952
+ });
953
+ }
954
+ else if (assetIn.address === viem_1.zeroAddress) {
955
+ value = amountToBridge;
956
+ toAddress = bridgePathway.nativeRouter;
957
+ if (bridgePathway.feeManager === 'from' && shouldDeliver) {
958
+ // transferring native to foreign
959
+ if (!feeDirectorStructEncoded)
960
+ return null;
961
+ if (!bridgePathway.destinationRouter)
962
+ return null;
963
+ data = bridgePathway.usesExtraParam
964
+ ? (0, viem_1.encodeFunctionData)({
965
+ abi: abis.nativeRouterExtraInput,
966
+ functionName: 'relayTokensAndCall',
967
+ args: [bridgePathway.destinationRouter, feeDirectorStructEncoded, account],
968
+ })
969
+ : (0, viem_1.encodeFunctionData)({
970
+ abi: abis.nativeRouter,
971
+ functionName: 'relayTokensAndCall',
972
+ args: [bridgePathway.destinationRouter, feeDirectorStructEncoded],
973
+ });
974
+ }
975
+ else {
976
+ // delivery always occurs when moving from foreign to home
977
+ data = bridgePathway.usesExtraParam
978
+ ? (0, viem_1.encodeFunctionData)({
979
+ abi: abis.nativeRouterExtraInput,
980
+ functionName: 'wrapAndRelayTokens',
981
+ args: [recipient, account],
982
+ })
983
+ : (0, viem_1.encodeFunctionData)({
984
+ abi: abis.nativeRouter,
985
+ functionName: 'wrapAndRelayTokens',
986
+ args: [recipient],
987
+ });
988
+ }
989
+ }
990
+ else {
991
+ // tokens native to this side, entering the bridge
992
+ if (shouldDeliver && bridgePathway.requiresDelivery) {
993
+ if (!feeDirectorStructEncoded)
994
+ return null;
995
+ if (!bridgePathway.destinationRouter)
996
+ return null;
997
+ data = bridgePathway.usesExtraParam
998
+ ? (0, viem_1.encodeFunctionData)({
999
+ abi: abis.inputBridgeExtraInput,
1000
+ functionName: 'relayTokensAndCall',
1001
+ args: [
1002
+ assetIn.address,
1003
+ bridgePathway.destinationRouter,
1004
+ amountToBridge,
1005
+ feeDirectorStructEncoded,
1006
+ account,
1007
+ ],
1008
+ })
1009
+ : (0, viem_1.encodeFunctionData)({
1010
+ abi: abis.inputBridge,
1011
+ functionName: 'relayTokensAndCall',
1012
+ args: [
1013
+ assetIn.address,
1014
+ bridgePathway.destinationRouter,
1015
+ amountToBridge,
1016
+ feeDirectorStructEncoded,
1017
+ ],
1018
+ });
1019
+ }
1020
+ else {
1021
+ data = bridgePathway.usesExtraParam
1022
+ ? (0, viem_1.encodeFunctionData)({
1023
+ abi: abis.inputBridgeExtraInput,
1024
+ functionName: 'relayTokens',
1025
+ args: [assetIn.address, recipient, amountToBridge, account],
1026
+ })
1027
+ : (0, viem_1.encodeFunctionData)({
1028
+ abi: abis.inputBridge,
1029
+ functionName: 'relayTokens',
1030
+ args: [assetIn.address, recipient, amountToBridge],
1031
+ });
1032
+ }
1033
+ }
1034
+ return {
1035
+ to: toAddress,
1036
+ value,
1037
+ data,
1038
+ };
1039
+ };
1040
+ exports.transactionInputs = transactionInputs;
1041
+ /**
1042
+ * Calculates the asset out key from the bridge key path, asset in address, and unwrap
1043
+ * @param bridgeKeyPath - the bridge key path
1044
+ * @param assetInAddress - the asset in address
1045
+ * @param unwrap - whether to unwrap
1046
+ * @returns the asset out key
1047
+ */
1048
+ const assetOutKey = ({ bridgeKeyPath, assetInAddress, unwrap, }) => {
1049
+ if (!bridgeKeyPath || !assetInAddress)
1050
+ return null;
1051
+ return `${bridgeKeyPath}/${unwrap ? 'native' : 'erc20'}/${assetInAddress.toLowerCase()}`;
1052
+ };
1053
+ exports.assetOutKey = assetOutKey;
1054
+ /**
1055
+ * Returns the asset out from the asset in address, assets out, bridge key path, and unwrap
1056
+ * @param assetInAddress - the asset in address
1057
+ * @param assetsOut - the assets out
1058
+ * @param bridgeKeyPath - the bridge key path
1059
+ * @param unwrap - whether to unwrap
1060
+ * @returns the asset out
1061
+ */
1062
+ const assetOut = ({ assetInAddress, assetsOut, bridgeKeyPath, unwrap, }) => {
1063
+ if (!assetInAddress)
1064
+ return null;
1065
+ const key = (0, exports.assetOutKey)({
1066
+ bridgeKeyPath,
1067
+ assetInAddress,
1068
+ unwrap,
1069
+ });
1070
+ if (!key)
1071
+ return null;
1072
+ return assetsOut.get(key) ?? null;
1073
+ };
1074
+ exports.assetOut = assetOut;