@upshiftfinance/sdk 0.0.0-stage → 0.1.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 (346) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +408 -2
  3. package/lib/abis/AddressResolver.d.ts +28 -0
  4. package/lib/abis/AddressResolver.js +23 -0
  5. package/lib/abis/ChainlinkV3.d.ts +87 -0
  6. package/lib/abis/ChainlinkV3.js +117 -0
  7. package/lib/abis/ERC20.d.ts +168 -0
  8. package/lib/abis/ERC20.js +226 -0
  9. package/lib/abis/ERC20_Bytes32.d.ts +139 -0
  10. package/lib/abis/ERC20_Bytes32.js +196 -0
  11. package/lib/abis/ERC4626.d.ts +364 -0
  12. package/lib/abis/ERC4626.js +507 -0
  13. package/lib/abis/ERC721.d.ts +231 -0
  14. package/lib/abis/ERC721.js +321 -0
  15. package/lib/abis/FeeOracle.d.ts +120 -0
  16. package/lib/abis/FeeOracle.js +162 -0
  17. package/lib/abis/LendingPool.d.ts +1393 -0
  18. package/lib/abis/LendingPool.js +1807 -0
  19. package/lib/abis/LendingPoolV2.d.ts +1413 -0
  20. package/lib/abis/LendingPoolV2.js +1833 -0
  21. package/lib/abis/LendingPoolV3.d.ts +1677 -0
  22. package/lib/abis/LendingPoolV3.js +1160 -0
  23. package/lib/abis/Loan.d.ts +837 -0
  24. package/lib/abis/Loan.js +1080 -0
  25. package/lib/abis/MultiAssetNativeDepositWrapper.d.ts +137 -0
  26. package/lib/abis/MultiAssetNativeDepositWrapper.js +125 -0
  27. package/lib/abis/Multicall3.d.ts +30 -0
  28. package/lib/abis/Multicall3.js +97 -0
  29. package/lib/abis/OFT.d.ts +116 -0
  30. package/lib/abis/OFT.js +85 -0
  31. package/lib/abis/PoolAdapter.d.ts +36 -0
  32. package/lib/abis/PoolAdapter.js +51 -0
  33. package/lib/abis/RewardDistributor.d.ts +267 -0
  34. package/lib/abis/RewardDistributor.js +352 -0
  35. package/lib/abis/RwaRedeemSubaccount.d.ts +747 -0
  36. package/lib/abis/RwaRedeemSubaccount.js +548 -0
  37. package/lib/abis/SmartAccount.d.ts +17 -0
  38. package/lib/abis/SmartAccount.js +19 -0
  39. package/lib/abis/SwapRouter.d.ts +953 -0
  40. package/lib/abis/SwapRouter.js +1228 -0
  41. package/lib/abis/TextResolver.d.ts +16 -0
  42. package/lib/abis/TextResolver.js +16 -0
  43. package/lib/abis/TokenizedVaultV2.d.ts +1364 -0
  44. package/lib/abis/TokenizedVaultV2.js +1041 -0
  45. package/lib/abis/TokenizedVaultV2DepositWithPermit.d.ts +1456 -0
  46. package/lib/abis/TokenizedVaultV2DepositWithPermit.js +1878 -0
  47. package/lib/abis/TokenizedVaultV2Receipt.d.ts +1568 -0
  48. package/lib/abis/TokenizedVaultV2Receipt.js +1061 -0
  49. package/lib/abis/TokenizedVaultV2SenderAllocationWhitelist.d.ts +454 -0
  50. package/lib/abis/TokenizedVaultV2SenderAllocationWhitelist.js +327 -0
  51. package/lib/abis/TokenizedVaultV2WhitelistedAllocation.d.ts +1466 -0
  52. package/lib/abis/TokenizedVaultV2WhitelistedAllocation.js +1092 -0
  53. package/lib/abis/TokenizedVaultV2WhitelistedAssets.d.ts +274 -0
  54. package/lib/abis/TokenizedVaultV2WhitelistedAssets.js +167 -0
  55. package/lib/abis/UniversalResolverResolve.d.ts +69 -0
  56. package/lib/abis/UniversalResolverResolve.js +35 -0
  57. package/lib/abis/UniversalSignatureValidator.d.ts +17 -0
  58. package/lib/abis/UniversalSignatureValidator.js +30 -0
  59. package/lib/abis/WrapperAdapter.d.ts +71 -0
  60. package/lib/abis/WrapperAdapter.js +77 -0
  61. package/lib/abis/index.d.ts +34 -0
  62. package/lib/abis/index.js +51 -0
  63. package/lib/adapters/evm/getters.d.ts +19 -0
  64. package/lib/adapters/evm/getters.js +249 -0
  65. package/lib/adapters/evm/index.d.ts +539 -0
  66. package/lib/adapters/evm/index.js +656 -0
  67. package/lib/adapters/evm/utils.d.ts +8 -0
  68. package/lib/adapters/evm/utils.js +51 -0
  69. package/lib/adapters/solana/confirm.d.ts +88 -0
  70. package/lib/adapters/solana/confirm.js +291 -0
  71. package/lib/adapters/solana/constants.d.ts +42 -0
  72. package/lib/adapters/solana/constants.js +59 -0
  73. package/lib/adapters/solana/getters.d.ts +42 -0
  74. package/lib/adapters/solana/getters.js +275 -0
  75. package/lib/adapters/solana/idl/vault-idl.d.ts +700 -0
  76. package/lib/adapters/solana/idl/vault-idl.js +2101 -0
  77. package/lib/adapters/solana/idl/withdrawal-queue-idl.d.ts +795 -0
  78. package/lib/adapters/solana/idl/withdrawal-queue-idl.js +1864 -0
  79. package/lib/adapters/solana/index.d.ts +372 -0
  80. package/lib/adapters/solana/index.js +459 -0
  81. package/lib/adapters/solana/pricing.d.ts +184 -0
  82. package/lib/adapters/solana/pricing.js +239 -0
  83. package/lib/adapters/solana/queue-hints.d.ts +29 -0
  84. package/lib/adapters/solana/queue-hints.js +59 -0
  85. package/lib/adapters/solana/queue.actions.d.ts +97 -0
  86. package/lib/adapters/solana/queue.actions.js +468 -0
  87. package/lib/adapters/solana/token-reads.d.ts +108 -0
  88. package/lib/adapters/solana/token-reads.js +145 -0
  89. package/lib/adapters/solana/types.d.ts +325 -0
  90. package/lib/adapters/solana/types.js +3 -0
  91. package/lib/adapters/solana/utils.d.ts +229 -0
  92. package/lib/adapters/solana/utils.js +773 -0
  93. package/lib/adapters/solana/vault.actions.d.ts +140 -0
  94. package/lib/adapters/solana/vault.actions.js +657 -0
  95. package/lib/adapters/solana/withdrawal-queue.d.ts +125 -0
  96. package/lib/adapters/solana/withdrawal-queue.js +301 -0
  97. package/lib/adapters/stellar/actions.d.ts +41 -0
  98. package/lib/adapters/stellar/actions.js +126 -0
  99. package/lib/adapters/stellar/constants.d.ts +43 -0
  100. package/lib/adapters/stellar/constants.js +53 -0
  101. package/lib/adapters/stellar/getters.d.ts +68 -0
  102. package/lib/adapters/stellar/getters.js +290 -0
  103. package/lib/adapters/stellar/index.d.ts +126 -0
  104. package/lib/adapters/stellar/index.js +187 -0
  105. package/lib/adapters/stellar/invocation.d.ts +55 -0
  106. package/lib/adapters/stellar/invocation.js +92 -0
  107. package/lib/adapters/stellar/soroban.d.ts +131 -0
  108. package/lib/adapters/stellar/soroban.js +617 -0
  109. package/lib/adapters/stellar/submit.d.ts +42 -0
  110. package/lib/adapters/stellar/submit.js +195 -0
  111. package/lib/adapters/stellar/types.d.ts +57 -0
  112. package/lib/adapters/stellar/types.js +6 -0
  113. package/lib/adapters/stellar/utils.d.ts +24 -0
  114. package/lib/adapters/stellar/utils.js +34 -0
  115. package/lib/adapters/sui/constants.d.ts +1 -0
  116. package/lib/adapters/sui/constants.js +9 -0
  117. package/lib/adapters/sui/getters.d.ts +24 -0
  118. package/lib/adapters/sui/getters.js +134 -0
  119. package/lib/adapters/sui/index.d.ts +53 -0
  120. package/lib/adapters/sui/index.js +96 -0
  121. package/lib/adapters/sui/transformer.d.ts +10 -0
  122. package/lib/adapters/sui/transformer.js +115 -0
  123. package/lib/adapters/sui/types.d.ts +70 -0
  124. package/lib/adapters/sui/types.js +3 -0
  125. package/lib/adapters/sui/utils.d.ts +8 -0
  126. package/lib/adapters/sui/utils.js +17 -0
  127. package/lib/core/analytics/app-name.d.ts +27 -0
  128. package/lib/core/analytics/app-name.js +48 -0
  129. package/lib/core/analytics/chain-name.d.ts +9 -0
  130. package/lib/core/analytics/chain-name.js +34 -0
  131. package/lib/core/analytics/constants.d.ts +15 -0
  132. package/lib/core/analytics/constants.js +28 -0
  133. package/lib/core/analytics/env.d.ts +46 -0
  134. package/lib/core/analytics/env.js +147 -0
  135. package/lib/core/analytics/index.d.ts +39 -0
  136. package/lib/core/analytics/index.js +83 -0
  137. package/lib/core/analytics/instrumentation.d.ts +29 -0
  138. package/lib/core/analytics/instrumentation.js +292 -0
  139. package/lib/core/analytics/method-taxonomy.d.ts +19 -0
  140. package/lib/core/analytics/method-taxonomy.js +156 -0
  141. package/lib/core/analytics/metrics.d.ts +48 -0
  142. package/lib/core/analytics/metrics.js +142 -0
  143. package/lib/core/analytics/sanitize.d.ts +57 -0
  144. package/lib/core/analytics/sanitize.js +272 -0
  145. package/lib/core/analytics/sentry-runtime.d.ts +15 -0
  146. package/lib/core/analytics/sentry-runtime.js +131 -0
  147. package/lib/core/analytics/sentry.d.ts +100 -0
  148. package/lib/core/analytics/sentry.js +696 -0
  149. package/lib/core/analytics/types.d.ts +55 -0
  150. package/lib/core/analytics/types.js +3 -0
  151. package/lib/core/analytics/user-identity.d.ts +55 -0
  152. package/lib/core/analytics/user-identity.js +218 -0
  153. package/lib/core/analytics/version.d.ts +6 -0
  154. package/lib/core/analytics/version.js +10 -0
  155. package/lib/core/attribution.d.ts +159 -0
  156. package/lib/core/attribution.js +194 -0
  157. package/lib/core/auth/index.d.ts +1 -0
  158. package/lib/core/auth/index.js +18 -0
  159. package/lib/core/auth/verify.d.ts +2 -0
  160. package/lib/core/auth/verify.js +35 -0
  161. package/lib/core/base.class.d.ts +193 -0
  162. package/lib/core/base.class.js +163 -0
  163. package/lib/core/cache.d.ts +9 -0
  164. package/lib/core/cache.js +31 -0
  165. package/lib/core/constants/adapters.d.ts +103 -0
  166. package/lib/core/constants/adapters.js +180 -0
  167. package/lib/core/constants/core.d.ts +162 -0
  168. package/lib/core/constants/core.js +281 -0
  169. package/lib/core/constants/swap-router.d.ts +180 -0
  170. package/lib/core/constants/swap-router.js +203 -0
  171. package/lib/core/constants/vaults.d.ts +93 -0
  172. package/lib/core/constants/vaults.js +277 -0
  173. package/lib/core/constants/web3.d.ts +106 -0
  174. package/lib/core/constants/web3.js +251 -0
  175. package/lib/core/errors/index.d.ts +177 -0
  176. package/lib/core/errors/index.js +257 -0
  177. package/lib/core/fetcher.d.ts +237 -0
  178. package/lib/core/fetcher.js +1103 -0
  179. package/lib/core/helpers/adapters.d.ts +13 -0
  180. package/lib/core/helpers/adapters.js +39 -0
  181. package/lib/core/helpers/chain-address.d.ts +13 -0
  182. package/lib/core/helpers/chain-address.js +47 -0
  183. package/lib/core/helpers/chain-error.d.ts +207 -0
  184. package/lib/core/helpers/chain-error.js +697 -0
  185. package/lib/core/helpers/chain-support.d.ts +98 -0
  186. package/lib/core/helpers/chain-support.js +139 -0
  187. package/lib/core/helpers/concurrency.d.ts +51 -0
  188. package/lib/core/helpers/concurrency.js +79 -0
  189. package/lib/core/helpers/core.d.ts +92 -0
  190. package/lib/core/helpers/core.js +368 -0
  191. package/lib/core/helpers/explorer-link.d.ts +16 -0
  192. package/lib/core/helpers/explorer-link.js +26 -0
  193. package/lib/core/helpers/multicall.d.ts +68 -0
  194. package/lib/core/helpers/multicall.js +103 -0
  195. package/lib/core/helpers/revert-decode.d.ts +248 -0
  196. package/lib/core/helpers/revert-decode.js +515 -0
  197. package/lib/core/helpers/signer.d.ts +61 -0
  198. package/lib/core/helpers/signer.js +184 -0
  199. package/lib/core/helpers/swap-router.d.ts +269 -0
  200. package/lib/core/helpers/swap-router.js +542 -0
  201. package/lib/core/helpers/vault-version.d.ts +24 -0
  202. package/lib/core/helpers/vault-version.js +83 -0
  203. package/lib/core/helpers/vaults.d.ts +89 -0
  204. package/lib/core/helpers/vaults.js +241 -0
  205. package/lib/core/helpers/web3.d.ts +366 -0
  206. package/lib/core/helpers/web3.js +1034 -0
  207. package/lib/core/index.d.ts +23 -0
  208. package/lib/core/index.js +40 -0
  209. package/lib/core/logger/curator-alert.d.ts +217 -0
  210. package/lib/core/logger/curator-alert.js +276 -0
  211. package/lib/core/logger/index.d.ts +99 -0
  212. package/lib/core/logger/index.js +163 -0
  213. package/lib/core/logger/slack.d.ts +49 -0
  214. package/lib/core/logger/slack.js +111 -0
  215. package/lib/core/vault-metadata.d.ts +12 -0
  216. package/lib/core/vault-metadata.js +42 -0
  217. package/lib/core/version-check.d.ts +58 -0
  218. package/lib/core/version-check.js +182 -0
  219. package/lib/evm/index.d.ts +2 -0
  220. package/lib/evm/index.js +19 -0
  221. package/lib/evm/methods/crossChainVault.d.ts +132 -0
  222. package/lib/evm/methods/crossChainVault.js +857 -0
  223. package/lib/evm/methods/crossChainVaultRegistry.d.ts +92 -0
  224. package/lib/evm/methods/crossChainVaultRegistry.js +239 -0
  225. package/lib/evm/methods/index.d.ts +2 -0
  226. package/lib/evm/methods/index.js +19 -0
  227. package/lib/evm/types/crossChain.d.ts +363 -0
  228. package/lib/evm/types/crossChain.js +20 -0
  229. package/lib/evm/types/index.d.ts +1 -0
  230. package/lib/evm/types/index.js +18 -0
  231. package/lib/index.d.ts +30 -0
  232. package/lib/index.js +52 -0
  233. package/lib/main.d.ts +596 -0
  234. package/lib/main.js +681 -0
  235. package/lib/modules/api/fetcher.d.ts +108 -0
  236. package/lib/modules/api/fetcher.js +187 -0
  237. package/lib/modules/api/index.d.ts +1 -0
  238. package/lib/modules/api/index.js +6 -0
  239. package/lib/modules/api/main.d.ts +587 -0
  240. package/lib/modules/api/main.js +911 -0
  241. package/lib/modules/sub-accounts/fetcher.d.ts +53 -0
  242. package/lib/modules/sub-accounts/fetcher.js +96 -0
  243. package/lib/modules/sub-accounts/index.d.ts +2 -0
  244. package/lib/modules/sub-accounts/index.js +19 -0
  245. package/lib/modules/sub-accounts/main.d.ts +249 -0
  246. package/lib/modules/sub-accounts/main.js +211 -0
  247. package/lib/modules/sub-accounts/utils.d.ts +106 -0
  248. package/lib/modules/sub-accounts/utils.js +112 -0
  249. package/lib/modules/vaults/adapter.helpers.d.ts +84 -0
  250. package/lib/modules/vaults/adapter.helpers.js +202 -0
  251. package/lib/modules/vaults/fetcher.d.ts +147 -0
  252. package/lib/modules/vaults/fetcher.js +357 -0
  253. package/lib/modules/vaults/getters.d.ts +1060 -0
  254. package/lib/modules/vaults/getters.js +4079 -0
  255. package/lib/modules/vaults/index.d.ts +20 -0
  256. package/lib/modules/vaults/index.js +44 -0
  257. package/lib/modules/vaults/main.d.ts +607 -0
  258. package/lib/modules/vaults/main.js +1687 -0
  259. package/lib/modules/vaults/prefetch.d.ts +65 -0
  260. package/lib/modules/vaults/prefetch.js +120 -0
  261. package/lib/modules/vaults/read.actions.d.ts +406 -0
  262. package/lib/modules/vaults/read.actions.js +891 -0
  263. package/lib/modules/vaults/types.d.ts +149 -0
  264. package/lib/modules/vaults/types.js +3 -0
  265. package/lib/modules/vaults/utils/call-data-decoder.d.ts +61 -0
  266. package/lib/modules/vaults/utils/call-data-decoder.js +194 -0
  267. package/lib/modules/vaults/utils/date-utils.d.ts +50 -0
  268. package/lib/modules/vaults/utils/date-utils.js +84 -0
  269. package/lib/modules/vaults/utils.d.ts +153 -0
  270. package/lib/modules/vaults/utils.js +818 -0
  271. package/lib/modules/vaults/write.actions.d.ts +812 -0
  272. package/lib/modules/vaults/write.actions.js +2377 -0
  273. package/lib/polyfills.d.ts +1 -0
  274. package/lib/polyfills.js +12 -0
  275. package/lib/sdk.d.ts +30154 -0
  276. package/lib/services/coingecko/fetcher.d.ts +15 -0
  277. package/lib/services/coingecko/fetcher.js +67 -0
  278. package/lib/services/coingecko/index.d.ts +2 -0
  279. package/lib/services/coingecko/index.js +19 -0
  280. package/lib/services/coingecko/utils.d.ts +1 -0
  281. package/lib/services/coingecko/utils.js +24 -0
  282. package/lib/services/debank/fetcher.d.ts +126 -0
  283. package/lib/services/debank/fetcher.js +47 -0
  284. package/lib/services/debank/index.d.ts +2 -0
  285. package/lib/services/debank/index.js +19 -0
  286. package/lib/services/debank/utils.d.ts +50 -0
  287. package/lib/services/debank/utils.js +325 -0
  288. package/lib/services/layerzero/deposits.d.ts +55 -0
  289. package/lib/services/layerzero/deposits.js +174 -0
  290. package/lib/services/layerzero/redeems.d.ts +20 -0
  291. package/lib/services/layerzero/redeems.js +92 -0
  292. package/lib/services/layerzero/utils.d.ts +9 -0
  293. package/lib/services/layerzero/utils.js +22 -0
  294. package/lib/services/octavfi/fetcher.d.ts +33 -0
  295. package/lib/services/octavfi/fetcher.js +39 -0
  296. package/lib/services/octavfi/index.d.ts +3 -0
  297. package/lib/services/octavfi/index.js +20 -0
  298. package/lib/services/octavfi/types.d.ts +34 -0
  299. package/lib/services/octavfi/types.js +3 -0
  300. package/lib/services/octavfi/utils.d.ts +16 -0
  301. package/lib/services/octavfi/utils.js +244 -0
  302. package/lib/services/subgraph/fetcher.d.ts +2 -0
  303. package/lib/services/subgraph/fetcher.js +66 -0
  304. package/lib/services/subgraph/index.d.ts +2 -0
  305. package/lib/services/subgraph/index.js +19 -0
  306. package/lib/services/subgraph/schema.d.ts +48 -0
  307. package/lib/services/subgraph/schema.js +87 -0
  308. package/lib/services/subgraph/vaults.d.ts +83 -0
  309. package/lib/services/subgraph/vaults.js +1282 -0
  310. package/lib/services/swap-quotes/index.d.ts +105 -0
  311. package/lib/services/swap-quotes/index.js +77 -0
  312. package/lib/services/swap-quotes/paraswap.d.ts +51 -0
  313. package/lib/services/swap-quotes/paraswap.js +138 -0
  314. package/lib/services/untangled/fetcher.d.ts +40 -0
  315. package/lib/services/untangled/fetcher.js +110 -0
  316. package/lib/services/untangled/index.d.ts +3 -0
  317. package/lib/services/untangled/index.js +20 -0
  318. package/lib/services/untangled/types.d.ts +83 -0
  319. package/lib/services/untangled/types.js +10 -0
  320. package/lib/services/untangled/utils.d.ts +91 -0
  321. package/lib/services/untangled/utils.js +339 -0
  322. package/lib/types/api.d.ts +498 -0
  323. package/lib/types/api.js +3 -0
  324. package/lib/types/index.d.ts +12 -0
  325. package/lib/types/index.js +28 -0
  326. package/lib/types/points.d.ts +28 -0
  327. package/lib/types/points.js +3 -0
  328. package/lib/types/pools.d.ts +144 -0
  329. package/lib/types/pools.js +3 -0
  330. package/lib/types/staking.d.ts +28 -0
  331. package/lib/types/staking.js +3 -0
  332. package/lib/types/sub-accounts.d.ts +150 -0
  333. package/lib/types/sub-accounts.js +3 -0
  334. package/lib/types/subgraph.d.ts +84 -0
  335. package/lib/types/subgraph.js +3 -0
  336. package/lib/types/typed-contract.d.ts +102 -0
  337. package/lib/types/typed-contract.js +3 -0
  338. package/lib/types/user.d.ts +1 -0
  339. package/lib/types/user.js +3 -0
  340. package/lib/types/vaults.d.ts +886 -0
  341. package/lib/types/vaults.js +30 -0
  342. package/lib/types/web3.d.ts +81 -0
  343. package/lib/types/web3.js +14 -0
  344. package/lib/types/webserver.d.ts +730 -0
  345. package/lib/types/webserver.js +3 -0
  346. package/package.json +78 -3
@@ -0,0 +1,617 @@
1
+ "use strict";
2
+ /**
3
+ * Shared Soroban RPC utilities
4
+ *
5
+ * Common transaction building and read-only query helpers used by
6
+ * actions, submit, and getters modules.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.createServer = createServer;
10
+ exports.resolveNetworkConfig = resolveNetworkConfig;
11
+ exports.resetHealthyServerCache = resetHealthyServerCache;
12
+ exports.redactRpcUrl = redactRpcUrl;
13
+ exports.getHealthyServer = getHealthyServer;
14
+ exports.isRetryableSorobanRpcError = isRetryableSorobanRpcError;
15
+ exports.isRetryableSimulationError = isRetryableSimulationError;
16
+ exports.withEndpointFailover = withEndpointFailover;
17
+ exports.toBigIntAmount = toBigIntAmount;
18
+ exports.queryContract = queryContract;
19
+ exports.buildSorobanTx = buildSorobanTx;
20
+ const stellar_sdk_1 = require("@stellar/stellar-sdk");
21
+ const core_1 = require("../../core");
22
+ const concurrency_1 = require("../../core/helpers/concurrency");
23
+ const constants_1 = require("./constants");
24
+ function createServer(rpcUrl) {
25
+ return new stellar_sdk_1.rpc.Server(rpcUrl, {
26
+ allowHttp: rpcUrl.startsWith('http://'),
27
+ });
28
+ }
29
+ /**
30
+ * Ordered public Soroban RPC endpoints per network, for health-gated failover.
31
+ *
32
+ * The first entry is the default primary ({@link SOROBAN_RPC_URLS}); the rest
33
+ * are keyless public fallbacks. A provider node can stall — most visibly around
34
+ * a protocol upgrade, when it freezes behind the network head and every
35
+ * simulation fails with a snapshot error — so a single endpoint means one bad
36
+ * node takes down all reads, deposits, and submits. Module-private: an internal
37
+ * resilience detail, not part of the adapter's public surface.
38
+ */
39
+ const SOROBAN_FALLBACK_RPC_URLS = {
40
+ mainnet: [constants_1.SOROBAN_RPC_URLS.mainnet, 'https://mainnet.sorobanrpc.com'],
41
+ testnet: [constants_1.SOROBAN_RPC_URLS.testnet],
42
+ };
43
+ /**
44
+ * Resolve the ordered RPC endpoints and network passphrase for a Stellar network.
45
+ *
46
+ * When `overrideRpcUrl` is supplied (e.g. a consumer's keyed Alchemy endpoint),
47
+ * it becomes the primary with the built-in public endpoints kept behind it as
48
+ * failover — so opting into a premium provider still degrades to the public
49
+ * network rather than becoming a new single point of failure. The endpoint is
50
+ * injected rather than hardcoded, so the adapter depends on configuration, not a
51
+ * constant.
52
+ */
53
+ function resolveNetworkConfig(network, overrideRpcUrl) {
54
+ const defaults = SOROBAN_FALLBACK_RPC_URLS[network];
55
+ const rpcUrls = overrideRpcUrl
56
+ ? [overrideRpcUrl, ...defaults]
57
+ : [...defaults];
58
+ return {
59
+ rpcUrl: rpcUrls[0],
60
+ rpcUrls,
61
+ passphrase: constants_1.NETWORK_PASSPHRASES[network],
62
+ };
63
+ }
64
+ /** How long a health-checked endpoint choice is reused before re-probing. */
65
+ const HEALTHY_SERVER_TTL_MS = 30_000;
66
+ /**
67
+ * Shorter reuse window after a fully-failed probe (no endpoint healthy). Caps
68
+ * probe traffic during an outage — failing fast on the primary beats re-probing
69
+ * every endpoint on every call — while keeping recovery within a few seconds.
70
+ */
71
+ const NEGATIVE_CACHE_TTL_MS = 5_000;
72
+ /**
73
+ * Bound on a single `getHealth` probe so a *hung* (not erroring) node can't
74
+ * block the failover loop; a timeout is treated like an unhealthy endpoint.
75
+ */
76
+ const HEALTH_PROBE_TIMEOUT_MS = 3_000;
77
+ /**
78
+ * Bound on a single real RPC operation (simulate / getAccount / build) so an
79
+ * endpoint that passed `getHealth()` but then *hangs* on the actual call fails
80
+ * over instead of blocking indefinitely; a timeout is treated as retryable.
81
+ */
82
+ const RPC_OPERATION_TIMEOUT_MS = 15_000;
83
+ const healthyServerCache = new Map();
84
+ // De-dupes concurrent probes for the same endpoint set (e.g. the parallel reads
85
+ // a vault listing issues) so a cold cache costs one probe, not one per call.
86
+ const inFlightProbes = new Map();
87
+ /**
88
+ * Clear the health-check cache and any in-flight probes. Test-only seam.
89
+ * @internal
90
+ */
91
+ function resetHealthyServerCache() {
92
+ healthyServerCache.clear();
93
+ inFlightProbes.clear();
94
+ }
95
+ /**
96
+ * Host-only view of an RPC URL, safe for logs. Keyed provider endpoints put the
97
+ * API key in the path (e.g. Alchemy `/v2/<key>`), so logging the raw URL would
98
+ * leak the secret into SDK logs / crash reporters. Returns just protocol+host.
99
+ * @internal
100
+ */
101
+ function redactRpcUrl(url) {
102
+ try {
103
+ const { protocol, host } = new URL(url);
104
+ return `${protocol}//${host}`;
105
+ }
106
+ catch {
107
+ return '<invalid-url>';
108
+ }
109
+ }
110
+ /**
111
+ * Return a copy of `value` with every configured RPC URL reduced to protocol+host
112
+ * in any string it carries, so a keyed endpoint (e.g. Alchemy `/v2/<key>`) can't
113
+ * leak its API key through a thrown error's chained `cause`.
114
+ *
115
+ * Handles Errors, plain objects, and arrays — not just Errors: Soroban's
116
+ * JSON-RPC helper throws the raw `{ code, message, data }` object, which
117
+ * `UpshiftSDKError.toJSON()` serializes wholesale, so an unscrubbed object cause
118
+ * would leak the key. Cloned recursively (depth- and cycle-bounded); the
119
+ * original is never mutated.
120
+ */
121
+ function scrubErrorUrls(value, scrub, depth = 0, seen = new WeakSet()) {
122
+ if (typeof value === 'string')
123
+ return scrub(value);
124
+ if (value === null || typeof value !== 'object')
125
+ return value;
126
+ if (depth >= 4)
127
+ return '[TRUNCATED]';
128
+ if (seen.has(value))
129
+ return '[Circular]';
130
+ seen.add(value);
131
+ if (value instanceof Error) {
132
+ const clone = new Error(scrub(value.message));
133
+ clone.name = value.name;
134
+ if (value.stack)
135
+ clone.stack = scrub(value.stack);
136
+ // Carry over any extra own props (e.g. a JSON-RPC `code` / `data`), scrubbed.
137
+ for (const key of Object.getOwnPropertyNames(value)) {
138
+ if (key === 'message' || key === 'stack' || key === 'name')
139
+ continue;
140
+ clone[key] = scrubErrorUrls(value[key], scrub, depth + 1, seen);
141
+ }
142
+ return clone;
143
+ }
144
+ if (Array.isArray(value)) {
145
+ return value.map((v) => scrubErrorUrls(v, scrub, depth + 1, seen));
146
+ }
147
+ const out = {};
148
+ for (const [key, v] of Object.entries(value)) {
149
+ out[key] = scrubErrorUrls(v, scrub, depth + 1, seen);
150
+ }
151
+ return out;
152
+ }
153
+ /**
154
+ * Return a Soroban RPC server backed by a healthy endpoint for `config`. Thin
155
+ * wrapper over {@link resolveHealthyServer} for callers (e.g. submission) that
156
+ * only need the server, not the URL it resolved to.
157
+ *
158
+ * @internal
159
+ */
160
+ function getHealthyServer(config) {
161
+ return resolveHealthyServer(config).then((r) => r.server);
162
+ }
163
+ /**
164
+ * Resolve a healthy endpoint for `config`, returning both the server and the URL
165
+ * it was built from.
166
+ *
167
+ * Probes `config.rpcUrls` in priority order via `getHealth()` and uses the first
168
+ * that reports healthy, so a stalled or lagging provider node is skipped instead
169
+ * of failing every call. The choice is cached for {@link HEALTHY_SERVER_TTL_MS},
170
+ * and concurrent callers on a cold cache share a single in-flight probe — so a
171
+ * burst of parallel reads costs one health probe, not one per call. When no
172
+ * endpoint reports healthy, falls back to the first reachable endpoint so the
173
+ * caller still attempts the request and surfaces the node's real error.
174
+ *
175
+ * The URL is returned (not just the server) so {@link withEndpointFailover} can
176
+ * skip the just-attempted endpoint and promote a working fallback into the cache.
177
+ */
178
+ function resolveHealthyServer(config) {
179
+ // Prefer the ordered failover list; fall back to the single primary for a
180
+ // hand-built config that predates `rpcUrls`.
181
+ const rpcUrls = config.rpcUrls && config.rpcUrls.length > 0
182
+ ? config.rpcUrls
183
+ : [config.rpcUrl];
184
+ // Key by the full ordered endpoint set, not just the primary: the same
185
+ // primary paired with different fallback lists selects a different server, so
186
+ // keying on `rpcUrls[0]` alone could return one endpoint set's choice for
187
+ // another during the TTL.
188
+ const cacheKey = rpcUrls.join('|');
189
+ const cached = healthyServerCache.get(cacheKey);
190
+ if (cached) {
191
+ // A fully-failed probe is cached only briefly (NEGATIVE_CACHE_TTL_MS) so an
192
+ // outage doesn't re-probe every endpoint on every call, yet recovers fast.
193
+ const ttl = cached.healthy ? HEALTHY_SERVER_TTL_MS : NEGATIVE_CACHE_TTL_MS;
194
+ if (Date.now() - cached.checkedAt < ttl) {
195
+ return Promise.resolve({
196
+ server: cached.server,
197
+ url: cached.url,
198
+ healthy: cached.healthy,
199
+ });
200
+ }
201
+ }
202
+ const existing = inFlightProbes.get(cacheKey);
203
+ if (existing)
204
+ return existing;
205
+ const probe = probeHealthyServer(rpcUrls, cacheKey).finally(() => {
206
+ inFlightProbes.delete(cacheKey);
207
+ });
208
+ inFlightProbes.set(cacheKey, probe);
209
+ return probe;
210
+ }
211
+ async function probeHealthyServer(rpcUrls, cacheKey) {
212
+ // The first endpoint we can even construct — the fallback when none report
213
+ // healthy. Tracked separately from `rpcUrls[0]` so a malformed primary (e.g. a
214
+ // typo'd consumer override) is skipped rather than disabling every call.
215
+ let firstConstructable;
216
+ let firstConstructableUrl;
217
+ for (const url of rpcUrls) {
218
+ let server;
219
+ try {
220
+ // Construct inside the guard: a malformed URL throws from the rpc.Server
221
+ // ctor, and must skip to the next endpoint rather than abort the loop and
222
+ // disable every fallback.
223
+ server = createServer(url);
224
+ }
225
+ catch (err) {
226
+ core_1.Logger.log.warn('getHealthyServer', 'Skipping invalid Soroban RPC endpoint; trying next endpoint', { url: redactRpcUrl(url), error: String(err) });
227
+ continue;
228
+ }
229
+ if (firstConstructable === undefined) {
230
+ firstConstructable = server;
231
+ firstConstructableUrl = url;
232
+ }
233
+ try {
234
+ const health = await (0, concurrency_1.withTimeout)(server.getHealth(), HEALTH_PROBE_TIMEOUT_MS, 'getHealth');
235
+ if (health.status === 'healthy') {
236
+ healthyServerCache.set(cacheKey, {
237
+ server,
238
+ url,
239
+ checkedAt: Date.now(),
240
+ healthy: true,
241
+ });
242
+ return { server, url, healthy: true };
243
+ }
244
+ core_1.Logger.log.warn('getHealthyServer', `Soroban RPC reported status "${health.status}"; trying next endpoint`, { url: redactRpcUrl(url) });
245
+ }
246
+ catch (err) {
247
+ core_1.Logger.log.warn('getHealthyServer', 'Soroban RPC health check failed; trying next endpoint',
248
+ // Scrub the endpoint from the error message too — SDK errors often
249
+ // embed the request URL (key and all).
250
+ {
251
+ url: redactRpcUrl(url),
252
+ error: String(err).split(url).join(redactRpcUrl(url)),
253
+ });
254
+ }
255
+ }
256
+ if (firstConstructable === undefined) {
257
+ // Every configured URL was malformed — there is nothing to call.
258
+ throw new core_1.UpshiftSDKError('UNKNOWN', 'No valid Soroban RPC endpoint could be constructed from the configured URLs');
259
+ }
260
+ const fallbackUrl = firstConstructableUrl;
261
+ core_1.Logger.log.warn('getHealthyServer', 'No healthy Soroban RPC endpoint; falling back to first reachable endpoint', { primary: redactRpcUrl(fallbackUrl) });
262
+ // Negative-cache the fallback (short TTL) so a sustained outage fails fast
263
+ // instead of re-probing every endpoint on every call.
264
+ healthyServerCache.set(cacheKey, {
265
+ server: firstConstructable,
266
+ url: fallbackUrl,
267
+ checkedAt: Date.now(),
268
+ healthy: false,
269
+ });
270
+ return { server: firstConstructable, url: fallbackUrl, healthy: false };
271
+ }
272
+ /**
273
+ * A thrown RPC error is retryable on another endpoint UNLESS it is one of our
274
+ * typed domain errors. Those mark a *deterministic* outcome — a contract revert,
275
+ * an unfunded account, archived state needing restore, a bad input, or a local
276
+ * assembly failure — which reproduces identically on every node, so retrying
277
+ * elsewhere only wastes calls. Any other throw (a transport hang/reset, or a
278
+ * method-specific node error from an endpoint that still answered `getHealth()`)
279
+ * is worth the next endpoint.
280
+ *
281
+ * Exported so an operation with different semantics (e.g. an idempotency-aware
282
+ * submission path) can compose or replace this policy via
283
+ * {@link FailoverOptions.isRetryable} — extension without editing the core.
284
+ *
285
+ * Named distinctly from `core/helpers/chain-error`'s `isRetryableRpcError`
286
+ * (the EVM transport classifier, deliberately public) — the internal-dts
287
+ * leak check matches `@internal` tags by name across the whole `src.ts` tree,
288
+ * so a same-named pair would make it flag the public EVM one as a leak.
289
+ * @internal
290
+ */
291
+ function isRetryableSorobanRpcError(err) {
292
+ return !(err instanceof core_1.UpshiftValidationError || err instanceof core_1.UpshiftSDKError);
293
+ }
294
+ /**
295
+ * Signatures of simulation errors that indicate a stalled/lagging *node* rather
296
+ * than a deterministic contract revert. The canonical case is the Protocol 27
297
+ * boundary, where a node frozen behind the network head answered `getHealth()`
298
+ * but reported reads with a "not present in the snapshot" error. Extend this
299
+ * list as new node-side signatures surface.
300
+ */
301
+ const RETRYABLE_SIMULATION_ERROR_SIGNATURES = ['not present in the snapshot'];
302
+ /**
303
+ * Whether a simulation *error* string is a node/infrastructure failure (which
304
+ * clears on another endpoint) rather than a genuine contract revert (which
305
+ * reproduces on every node). `isSimulationError` alone can't tell these apart —
306
+ * both arrive as a populated `error` field — so callers use this to decide
307
+ * whether to fail over or treat the error as terminal.
308
+ * @internal
309
+ */
310
+ function isRetryableSimulationError(errorText) {
311
+ const lower = errorText.toLowerCase();
312
+ return RETRYABLE_SIMULATION_ERROR_SIGNATURES.some((sig) => lower.includes(sig));
313
+ }
314
+ /**
315
+ * Drop a cached endpoint choice so a server that just failed a *real* call is
316
+ * not re-used for the remainder of its {@link HEALTHY_SERVER_TTL_MS} window.
317
+ */
318
+ function dropCachedServer(rpcUrls) {
319
+ healthyServerCache.delete(rpcUrls.join('|'));
320
+ }
321
+ /**
322
+ * Run an idempotent, side-effect-free `operation` (a read or a tx build) against
323
+ * a Soroban endpoint, failing over to the remaining endpoints on a retryable
324
+ * failure.
325
+ *
326
+ * {@link getHealthyServer} only proves an endpoint answered `getHealth()`, and
327
+ * caches that choice for {@link HEALTHY_SERVER_TTL_MS} — but the node can still
328
+ * hang or return a method-specific error on the *real* call. So we run the op on
329
+ * the health-gated server first (the fast, cached path) and, on a retryable
330
+ * failure, drop that cached choice and retry the op against every endpoint in
331
+ * priority order. Deterministic contract/domain errors short-circuit (see
332
+ * {@link isRetryableSorobanRpcError}); each attempt is time-boxed so a hung node can't
333
+ * stall the loop.
334
+ *
335
+ * The `operation` is a strategy (dependency-injected), so new read/build calls
336
+ * reuse this failover without changing it; `options` keeps retry policy and
337
+ * timeout open for extension. Submission is deliberately NOT routed through here
338
+ * — re-sending a signed transaction across endpoints risks a double-submit, so
339
+ * it needs sequence/DUPLICATE-based idempotency rather than blind retry.
340
+ * @internal
341
+ */
342
+ async function withEndpointFailover(config, method, operation, options = {}) {
343
+ const isRetryable = options.isRetryable ?? isRetryableSorobanRpcError;
344
+ const timeoutMs = options.timeoutMs ?? RPC_OPERATION_TIMEOUT_MS;
345
+ const rpcUrls = config.rpcUrls && config.rpcUrls.length > 0
346
+ ? config.rpcUrls
347
+ : [config.rpcUrl];
348
+ const runOn = (server) => (0, concurrency_1.withTimeout)(operation(server), timeoutMs, `Soroban ${method}`);
349
+ const cacheKey = rpcUrls.join('|');
350
+ // Reduce every configured endpoint URL to protocol+host in anything surfaced
351
+ // from here (logs, the thrown message, the chained cause). SDK errors embed the
352
+ // request URL — which for a keyed provider carries the API key in its path — so
353
+ // an unscrubbed `String(err)` would leak it. Belt-and-suspenders with the
354
+ // analytics sanitizer, and it also covers the thrown error that escapes to the
355
+ // caller (which our telemetry sanitizer never sees).
356
+ const scrub = (text) => rpcUrls.reduce((acc, u) => acc.split(u).join(redactRpcUrl(u)), text);
357
+ let lastError;
358
+ // A terminal "everything failed" error, scrubbed so a keyed endpoint can't
359
+ // leak through the message or chained cause.
360
+ const failAllEndpoints = () => new core_1.UpshiftSDKError('UNKNOWN', `Soroban ${method} failed on all endpoints: ${scrub(String(lastError))}`, {
361
+ cause: scrubErrorUrls(lastError, scrub),
362
+ context: { method, stage: 'rpc-failover' },
363
+ });
364
+ // Fast path: the health-gated, cross-call-cached endpoint.
365
+ const { server: primaryServer, url: primaryUrl, healthy, } = await resolveHealthyServer(config);
366
+ try {
367
+ return await runOn(primaryServer);
368
+ }
369
+ catch (err) {
370
+ if (!isRetryable(err))
371
+ throw err;
372
+ lastError = err;
373
+ if (!healthy) {
374
+ // The resolved endpoint is a negative-cached fallback: a prior probe found
375
+ // no healthy endpoint, so the whole set is down. Re-looping every endpoint
376
+ // (and re-probing on the next read) would only amplify load during the
377
+ // outage, so fail fast and leave the short-TTL negative entry in place —
378
+ // subsequent reads within NEGATIVE_CACHE_TTL_MS fast-fail on the primary too.
379
+ throw failAllEndpoints();
380
+ }
381
+ // A "healthy" endpoint failed the real call — drop it and fail over.
382
+ dropCachedServer(rpcUrls);
383
+ core_1.Logger.log.warn('withEndpointFailover', `Soroban ${method} failed on the health-gated endpoint; failing over`, { error: scrub(String(err)) });
384
+ }
385
+ // Failover: the remaining endpoints in priority order. Skip the one the fast
386
+ // path already tried (no point paying its timeout twice). On success, promote
387
+ // the working endpoint into the cache so the next call starts there instead of
388
+ // repeating the failed-primary-then-fallback sequence.
389
+ for (const url of rpcUrls) {
390
+ if (url === primaryUrl)
391
+ continue;
392
+ let server;
393
+ try {
394
+ server = createServer(url);
395
+ }
396
+ catch {
397
+ continue; // malformed endpoint URL — skip
398
+ }
399
+ try {
400
+ const result = await runOn(server);
401
+ healthyServerCache.set(cacheKey, {
402
+ server,
403
+ url,
404
+ checkedAt: Date.now(),
405
+ healthy: true,
406
+ });
407
+ return result;
408
+ }
409
+ catch (err) {
410
+ if (!isRetryable(err))
411
+ throw err;
412
+ lastError = err;
413
+ core_1.Logger.log.warn('withEndpointFailover', `Soroban ${method} failed; trying next endpoint`, {
414
+ url: redactRpcUrl(url),
415
+ error: scrub(String(err)),
416
+ });
417
+ }
418
+ }
419
+ // Every endpoint's real op failed even though one health-probed OK. Negative-
420
+ // cache the health-gated server (it constructed fine) so subsequent reads
421
+ // fast-fail within NEGATIVE_CACHE_TTL_MS instead of re-probing + re-looping the
422
+ // whole set during a sustained outage.
423
+ healthyServerCache.set(cacheKey, {
424
+ server: primaryServer,
425
+ url: primaryUrl,
426
+ checkedAt: Date.now(),
427
+ healthy: false,
428
+ });
429
+ throw failAllEndpoints();
430
+ }
431
+ /**
432
+ * Validate and convert a string amount to a non-negative BigInt.
433
+ * Throws a descriptive error if the value is not a valid non-negative integer string.
434
+ */
435
+ function toBigIntAmount(value, label) {
436
+ if (value === '') {
437
+ throw new core_1.UpshiftValidationError('INVALID_INPUT', `Invalid ${label}: value must not be empty`);
438
+ }
439
+ let result;
440
+ try {
441
+ result = BigInt(value);
442
+ }
443
+ catch {
444
+ throw new core_1.UpshiftValidationError('INVALID_INPUT', `Invalid ${label}: "${value}" is not a valid integer string`);
445
+ }
446
+ if (result < 0n) {
447
+ throw new core_1.UpshiftValidationError('INVALID_INPUT', `Invalid ${label}: value must be non-negative, got "${value}"`);
448
+ }
449
+ return result;
450
+ }
451
+ /**
452
+ * Query a read-only Soroban contract function via simulation.
453
+ * Uses a throwaway source account — simulation is off-chain and has no on-chain side effects.
454
+ * Returns the ScVal result, or null if the call fails.
455
+ */
456
+ function extractSimulationError(simulated) {
457
+ return 'error' in simulated
458
+ ? String(simulated.error)
459
+ : 'Unknown simulation error';
460
+ }
461
+ async function queryContract(config, contractId, method, args = []) {
462
+ try {
463
+ // Build the simulation tx once — it is endpoint-independent, so only the
464
+ // simulate call is failed over across endpoints (not the tx assembly).
465
+ const contract = new stellar_sdk_1.Contract(contractId);
466
+ const sourceKeypair = stellar_sdk_1.Keypair.random();
467
+ const account = new stellar_sdk_1.Account(sourceKeypair.publicKey(), '0');
468
+ // Minimal fee — simulation is off-chain; these values don't affect execution cost.
469
+ // Short timeout to avoid blocking vault listing if Soroban RPC is slow.
470
+ const tx = new stellar_sdk_1.TransactionBuilder(account, {
471
+ fee: '100',
472
+ networkPassphrase: config.passphrase,
473
+ })
474
+ .addOperation(contract.call(method, ...args))
475
+ .setTimeout(constants_1.QUERY_TIMEOUT_SECONDS)
476
+ .build();
477
+ return await withEndpointFailover(config, method, async (server) => {
478
+ const simulated = await server.simulateTransaction(tx);
479
+ if (stellar_sdk_1.rpc.Api.isSimulationError(simulated)) {
480
+ const errorText = extractSimulationError(simulated);
481
+ if (isRetryableSimulationError(errorText)) {
482
+ // A stalled/lagging node reports the read as a simulation error too
483
+ // (e.g. a post-upgrade snapshot gap) — not a real revert. Throw so the
484
+ // failover wrapper tries another endpoint instead of returning null.
485
+ throw new Error(`Soroban simulation node error for ${method}: ${errorText}`);
486
+ }
487
+ // A genuine contract revert is deterministic across nodes — surface null
488
+ // (best-effort read) rather than failing over to repeat it.
489
+ core_1.Logger.log.warn('queryContract', `Soroban simulation error for ${method}: ${errorText}`, { contractId });
490
+ return null;
491
+ }
492
+ if (stellar_sdk_1.rpc.Api.isSimulationSuccess(simulated) && simulated.result) {
493
+ return simulated.result.retval;
494
+ }
495
+ core_1.Logger.log.warn('queryContract', `Unexpected simulation state for ${method} — no result returned`, { contractId });
496
+ return null;
497
+ });
498
+ }
499
+ catch (err) {
500
+ core_1.Logger.log.warn('queryContract', `Soroban query failed: ${method}`, {
501
+ contractId,
502
+ error: String(err),
503
+ });
504
+ return null;
505
+ }
506
+ }
507
+ /**
508
+ * Read the network's wall-clock time (unix seconds) from the latest closed
509
+ * ledger, or null if the RPC can't report it.
510
+ *
511
+ * Soroban validators reject a transaction whose `maxTime` precedes the ledger
512
+ * close time (`txTOO_LATE`). Anchoring `maxTime` to the *network* clock instead
513
+ * of the signer's `Date.now()` immunises the deadline against a skewed device
514
+ * clock — a machine lagging behind real time was silently building
515
+ * already-expired transactions. Best-effort: on any RPC failure the caller
516
+ * falls back to the local clock, so this never regresses the prior behaviour.
517
+ */
518
+ async function getNetworkCloseTime(server) {
519
+ try {
520
+ const { sequence } = await server.getLatestLedger();
521
+ // `latestLedgerCloseTime` on the response envelope is the freshest network
522
+ // time; the single-ledger page is just the cheapest valid request shape.
523
+ const page = await server.getLedgers({
524
+ startLedger: sequence,
525
+ pagination: { limit: 1 },
526
+ });
527
+ return typeof page.latestLedgerCloseTime === 'number'
528
+ ? page.latestLedgerCloseTime
529
+ : null;
530
+ }
531
+ catch (err) {
532
+ core_1.Logger.log.warn('getNetworkCloseTime', `Network clock unavailable; falling back to local clock for tx timebounds: ${String(err)}`);
533
+ return null;
534
+ }
535
+ }
536
+ /**
537
+ * Build an unsigned Soroban contract invocation transaction.
538
+ * Fetches the real source account from the network (the account must exist and be funded).
539
+ * Simulates via Soroban RPC to attach resource footprint and auth entries,
540
+ * using MAX_FEE_STROOPS as the fee ceiling and incorporating the simulated resource fee.
541
+ *
542
+ * Thrown errors carry `context.stage` naming where the build broke:
543
+ * `'simulation'` (the contract itself rejected the call), `'restore-required'`,
544
+ * `'assembly'`, or `'rpc-failover'` (no endpoint answered). Callers use it to
545
+ * separate a vault-level rejection from a transport problem — see the curator
546
+ * alerting in `handleStellarRedeem`. Validation errors (e.g.
547
+ * `ACCOUNT_NOT_FUNDED`) carry no stage, so treat a missing one as "not a
548
+ * vault-level failure" rather than assuming the field is always present.
549
+ */
550
+ async function buildSorobanTx(config, sourceAddress, contractId, method, args) {
551
+ const contract = new stellar_sdk_1.Contract(contractId);
552
+ // Build is idempotent (no on-chain side effects), so the whole account-fetch →
553
+ // simulate → assemble sequence is failed over across endpoints. Deterministic
554
+ // outcomes (unfunded account, simulation/restore/assembly errors) throw typed
555
+ // errors and short-circuit the failover; transport errors get the next node.
556
+ return withEndpointFailover(config, method, async (server) => {
557
+ // Read the network clock in parallel with the account fetch — it overlaps
558
+ // the account round-trip, so it adds no latency on the happy path.
559
+ const networkCloseTimePromise = getNetworkCloseTime(server);
560
+ let account;
561
+ try {
562
+ account = await server.getAccount(sourceAddress);
563
+ }
564
+ catch (err) {
565
+ // Soroban rpc currently throws plain `Error("Account not found: ...")`
566
+ // for unfunded accounts; check `NotFoundError` too so this survives an
567
+ // SDK refactor to typed errors. An unfunded account is deterministic
568
+ // across nodes (typed error → no failover); any other getAccount error is
569
+ // transport-ish and falls over.
570
+ const msg = err instanceof Error ? err.message : String(err);
571
+ const isAccountNotFound = err instanceof stellar_sdk_1.NotFoundError || /Account not found/.test(msg);
572
+ if (isAccountNotFound) {
573
+ throw new core_1.UpshiftValidationError('ACCOUNT_NOT_FUNDED', `Stellar account ${sourceAddress} is not funded. Send at least 1 XLM to this address to activate it before depositing or redeeming.`, { cause: err, context: { sourceAddress, method, contractId } });
574
+ }
575
+ throw err;
576
+ }
577
+ const builder = new stellar_sdk_1.TransactionBuilder(account, {
578
+ fee: constants_1.MAX_FEE_STROOPS,
579
+ networkPassphrase: config.passphrase,
580
+ }).addOperation(contract.call(method, ...args));
581
+ const networkCloseTime = await networkCloseTimePromise;
582
+ if (networkCloseTime !== null) {
583
+ // Absolute deadline anchored to the network clock — survives signer skew.
584
+ builder.setTimebounds(0, networkCloseTime + constants_1.TX_TIMEOUT_SECONDS);
585
+ }
586
+ else {
587
+ // RPC couldn't report network time; fall back to the local-clock window.
588
+ builder.setTimeout(constants_1.TX_TIMEOUT_SECONDS);
589
+ }
590
+ const tx = builder.build();
591
+ const simulated = await server.simulateTransaction(tx);
592
+ if (stellar_sdk_1.rpc.Api.isSimulationError(simulated)) {
593
+ const errorText = extractSimulationError(simulated);
594
+ if (isRetryableSimulationError(errorText)) {
595
+ // Node/snapshot error (a stale node), not a contract revert — throw a
596
+ // retryable error so the failover wrapper tries another endpoint.
597
+ throw new Error(`Soroban simulation node error for ${method}: ${errorText}`);
598
+ }
599
+ throw new core_1.UpshiftSDKError('UNKNOWN', `Soroban simulation failed: ${errorText}`, { context: { method, contractId, stage: 'simulation' } });
600
+ }
601
+ if ('restorePreamble' in simulated && simulated.restorePreamble) {
602
+ throw new core_1.UpshiftSDKError('UNKNOWN', `Contract ledger state needs restoration before invoking ${method}. ` +
603
+ 'Submit a restore footprint transaction first.', { context: { method, contractId, stage: 'restore-required' } });
604
+ }
605
+ try {
606
+ const assembled = stellar_sdk_1.rpc.assembleTransaction(tx, simulated).build();
607
+ return assembled.toXDR();
608
+ }
609
+ catch (assemblyErr) {
610
+ throw new core_1.UpshiftSDKError('UNKNOWN', `Failed to assemble Soroban transaction for ${method}: ${String(assemblyErr)}`, {
611
+ cause: assemblyErr,
612
+ context: { method, contractId, stage: 'assembly' },
613
+ });
614
+ }
615
+ });
616
+ }
617
+ //# sourceMappingURL=soroban.js.map
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Stellar Transaction Submission
3
+ *
4
+ * Submits signed Soroban transactions and polls for confirmation.
5
+ */
6
+ import type { IStellarNetwork } from './types';
7
+ /**
8
+ * Submit a signed Soroban transaction and poll until confirmed.
9
+ *
10
+ * @param signedXdr - Base64-encoded XDR of the signed transaction
11
+ * @param network - Stellar network name
12
+ * @param sorobanRpcUrl - Optional override Soroban RPC endpoint (e.g. a keyed
13
+ * Alchemy URL); becomes the primary with the SDK's public endpoints kept as
14
+ * failover. Omit to use the public endpoints.
15
+ * @returns The transaction hash once the network confirms it as successful
16
+ * @throws {@link UpshiftTimeoutError} when the transaction is not confirmed
17
+ * within the poll budget (`MAX_POLL_ATTEMPTS`).
18
+ * @throws {@link UpshiftSDKError} when the RPC rejects the submission or the
19
+ * transaction confirms as failed. Its `context` carries `{ network, status }`
20
+ * plus, when the result XDR decodes, a `resultCode` string holding the
21
+ * transaction-level reason (e.g. `"txBadSeq"`, `"txTooLate"`); `resultCode`
22
+ * is `undefined` when the code cannot be decoded.
23
+ *
24
+ * Side effect: a transaction whose `resultCode` is `txFailed` — the operation
25
+ * itself ran and failed — and whose envelope shows a vault `redeem` is relayed
26
+ * to that vault's curator (fire-and-forget, deduped — see
27
+ * {@link reportRedeemFailure}). Nothing else alerts: an RPC-rejected
28
+ * broadcast is a retryable race, a poll timeout is indeterminate (the
29
+ * transaction may yet succeed), and any other result code means the redeem
30
+ * never executed.
31
+ * @example
32
+ * ```ts
33
+ * try {
34
+ * const hash = await submitStellarTransaction(signedXdr, 'mainnet');
35
+ * } catch (err) {
36
+ * if (err instanceof UpshiftSDKError && err.context?.resultCode === 'txBadSeq') {
37
+ * // stale sequence number — rebuild the transaction and resubmit
38
+ * }
39
+ * }
40
+ * ```
41
+ */
42
+ export declare function submitStellarTransaction(signedXdr: string, network: IStellarNetwork, sorobanRpcUrl?: string): Promise<string>;