@upshiftfinance/sdk 0.0.0-stage → 0.2.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 (344) 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/client.d.ts +83 -0
  116. package/lib/adapters/sui/client.js +216 -0
  117. package/lib/adapters/sui/constants.d.ts +33 -0
  118. package/lib/adapters/sui/constants.js +31 -0
  119. package/lib/adapters/sui/index.d.ts +57 -0
  120. package/lib/adapters/sui/index.js +100 -0
  121. package/lib/adapters/sui/targets.d.ts +171 -0
  122. package/lib/adapters/sui/targets.js +225 -0
  123. package/lib/adapters/sui/utils.d.ts +8 -0
  124. package/lib/adapters/sui/utils.js +17 -0
  125. package/lib/core/analytics/app-name.d.ts +27 -0
  126. package/lib/core/analytics/app-name.js +48 -0
  127. package/lib/core/analytics/chain-name.d.ts +9 -0
  128. package/lib/core/analytics/chain-name.js +34 -0
  129. package/lib/core/analytics/constants.d.ts +15 -0
  130. package/lib/core/analytics/constants.js +28 -0
  131. package/lib/core/analytics/env.d.ts +46 -0
  132. package/lib/core/analytics/env.js +147 -0
  133. package/lib/core/analytics/index.d.ts +39 -0
  134. package/lib/core/analytics/index.js +83 -0
  135. package/lib/core/analytics/instrumentation.d.ts +29 -0
  136. package/lib/core/analytics/instrumentation.js +292 -0
  137. package/lib/core/analytics/method-taxonomy.d.ts +19 -0
  138. package/lib/core/analytics/method-taxonomy.js +156 -0
  139. package/lib/core/analytics/metrics.d.ts +48 -0
  140. package/lib/core/analytics/metrics.js +142 -0
  141. package/lib/core/analytics/sanitize.d.ts +57 -0
  142. package/lib/core/analytics/sanitize.js +272 -0
  143. package/lib/core/analytics/sentry-runtime.d.ts +15 -0
  144. package/lib/core/analytics/sentry-runtime.js +131 -0
  145. package/lib/core/analytics/sentry.d.ts +100 -0
  146. package/lib/core/analytics/sentry.js +696 -0
  147. package/lib/core/analytics/types.d.ts +55 -0
  148. package/lib/core/analytics/types.js +3 -0
  149. package/lib/core/analytics/user-identity.d.ts +55 -0
  150. package/lib/core/analytics/user-identity.js +218 -0
  151. package/lib/core/analytics/version.d.ts +6 -0
  152. package/lib/core/analytics/version.js +10 -0
  153. package/lib/core/attribution.d.ts +159 -0
  154. package/lib/core/attribution.js +194 -0
  155. package/lib/core/auth/index.d.ts +1 -0
  156. package/lib/core/auth/index.js +18 -0
  157. package/lib/core/auth/verify.d.ts +2 -0
  158. package/lib/core/auth/verify.js +35 -0
  159. package/lib/core/base.class.d.ts +193 -0
  160. package/lib/core/base.class.js +163 -0
  161. package/lib/core/cache.d.ts +9 -0
  162. package/lib/core/cache.js +31 -0
  163. package/lib/core/constants/adapters.d.ts +103 -0
  164. package/lib/core/constants/adapters.js +180 -0
  165. package/lib/core/constants/core.d.ts +162 -0
  166. package/lib/core/constants/core.js +281 -0
  167. package/lib/core/constants/swap-router.d.ts +180 -0
  168. package/lib/core/constants/swap-router.js +203 -0
  169. package/lib/core/constants/vaults.d.ts +93 -0
  170. package/lib/core/constants/vaults.js +277 -0
  171. package/lib/core/constants/web3.d.ts +106 -0
  172. package/lib/core/constants/web3.js +251 -0
  173. package/lib/core/errors/index.d.ts +177 -0
  174. package/lib/core/errors/index.js +257 -0
  175. package/lib/core/fetcher.d.ts +237 -0
  176. package/lib/core/fetcher.js +1103 -0
  177. package/lib/core/helpers/adapters.d.ts +13 -0
  178. package/lib/core/helpers/adapters.js +39 -0
  179. package/lib/core/helpers/chain-address.d.ts +13 -0
  180. package/lib/core/helpers/chain-address.js +47 -0
  181. package/lib/core/helpers/chain-error.d.ts +207 -0
  182. package/lib/core/helpers/chain-error.js +697 -0
  183. package/lib/core/helpers/chain-support.d.ts +98 -0
  184. package/lib/core/helpers/chain-support.js +139 -0
  185. package/lib/core/helpers/concurrency.d.ts +51 -0
  186. package/lib/core/helpers/concurrency.js +79 -0
  187. package/lib/core/helpers/core.d.ts +92 -0
  188. package/lib/core/helpers/core.js +368 -0
  189. package/lib/core/helpers/explorer-link.d.ts +16 -0
  190. package/lib/core/helpers/explorer-link.js +26 -0
  191. package/lib/core/helpers/multicall.d.ts +68 -0
  192. package/lib/core/helpers/multicall.js +103 -0
  193. package/lib/core/helpers/revert-decode.d.ts +248 -0
  194. package/lib/core/helpers/revert-decode.js +515 -0
  195. package/lib/core/helpers/signer.d.ts +61 -0
  196. package/lib/core/helpers/signer.js +184 -0
  197. package/lib/core/helpers/swap-router.d.ts +269 -0
  198. package/lib/core/helpers/swap-router.js +542 -0
  199. package/lib/core/helpers/vault-version.d.ts +24 -0
  200. package/lib/core/helpers/vault-version.js +83 -0
  201. package/lib/core/helpers/vaults.d.ts +89 -0
  202. package/lib/core/helpers/vaults.js +241 -0
  203. package/lib/core/helpers/web3.d.ts +366 -0
  204. package/lib/core/helpers/web3.js +1034 -0
  205. package/lib/core/index.d.ts +23 -0
  206. package/lib/core/index.js +40 -0
  207. package/lib/core/logger/curator-alert.d.ts +217 -0
  208. package/lib/core/logger/curator-alert.js +276 -0
  209. package/lib/core/logger/index.d.ts +99 -0
  210. package/lib/core/logger/index.js +163 -0
  211. package/lib/core/logger/slack.d.ts +49 -0
  212. package/lib/core/logger/slack.js +111 -0
  213. package/lib/core/vault-metadata.d.ts +12 -0
  214. package/lib/core/vault-metadata.js +42 -0
  215. package/lib/core/version-check.d.ts +58 -0
  216. package/lib/core/version-check.js +182 -0
  217. package/lib/evm/index.d.ts +2 -0
  218. package/lib/evm/index.js +19 -0
  219. package/lib/evm/methods/crossChainVault.d.ts +132 -0
  220. package/lib/evm/methods/crossChainVault.js +857 -0
  221. package/lib/evm/methods/crossChainVaultRegistry.d.ts +92 -0
  222. package/lib/evm/methods/crossChainVaultRegistry.js +239 -0
  223. package/lib/evm/methods/index.d.ts +2 -0
  224. package/lib/evm/methods/index.js +19 -0
  225. package/lib/evm/types/crossChain.d.ts +363 -0
  226. package/lib/evm/types/crossChain.js +20 -0
  227. package/lib/evm/types/index.d.ts +1 -0
  228. package/lib/evm/types/index.js +18 -0
  229. package/lib/index.d.ts +30 -0
  230. package/lib/index.js +52 -0
  231. package/lib/main.d.ts +596 -0
  232. package/lib/main.js +681 -0
  233. package/lib/modules/api/fetcher.d.ts +108 -0
  234. package/lib/modules/api/fetcher.js +187 -0
  235. package/lib/modules/api/index.d.ts +1 -0
  236. package/lib/modules/api/index.js +6 -0
  237. package/lib/modules/api/main.d.ts +587 -0
  238. package/lib/modules/api/main.js +911 -0
  239. package/lib/modules/sub-accounts/fetcher.d.ts +53 -0
  240. package/lib/modules/sub-accounts/fetcher.js +96 -0
  241. package/lib/modules/sub-accounts/index.d.ts +2 -0
  242. package/lib/modules/sub-accounts/index.js +19 -0
  243. package/lib/modules/sub-accounts/main.d.ts +249 -0
  244. package/lib/modules/sub-accounts/main.js +211 -0
  245. package/lib/modules/sub-accounts/utils.d.ts +106 -0
  246. package/lib/modules/sub-accounts/utils.js +112 -0
  247. package/lib/modules/vaults/adapter.helpers.d.ts +84 -0
  248. package/lib/modules/vaults/adapter.helpers.js +202 -0
  249. package/lib/modules/vaults/fetcher.d.ts +147 -0
  250. package/lib/modules/vaults/fetcher.js +357 -0
  251. package/lib/modules/vaults/getters.d.ts +1060 -0
  252. package/lib/modules/vaults/getters.js +4079 -0
  253. package/lib/modules/vaults/index.d.ts +20 -0
  254. package/lib/modules/vaults/index.js +44 -0
  255. package/lib/modules/vaults/main.d.ts +607 -0
  256. package/lib/modules/vaults/main.js +1687 -0
  257. package/lib/modules/vaults/prefetch.d.ts +65 -0
  258. package/lib/modules/vaults/prefetch.js +120 -0
  259. package/lib/modules/vaults/read.actions.d.ts +406 -0
  260. package/lib/modules/vaults/read.actions.js +891 -0
  261. package/lib/modules/vaults/types.d.ts +149 -0
  262. package/lib/modules/vaults/types.js +3 -0
  263. package/lib/modules/vaults/utils/call-data-decoder.d.ts +61 -0
  264. package/lib/modules/vaults/utils/call-data-decoder.js +194 -0
  265. package/lib/modules/vaults/utils/date-utils.d.ts +50 -0
  266. package/lib/modules/vaults/utils/date-utils.js +84 -0
  267. package/lib/modules/vaults/utils.d.ts +153 -0
  268. package/lib/modules/vaults/utils.js +818 -0
  269. package/lib/modules/vaults/write.actions.d.ts +812 -0
  270. package/lib/modules/vaults/write.actions.js +2377 -0
  271. package/lib/polyfills.d.ts +1 -0
  272. package/lib/polyfills.js +12 -0
  273. package/lib/sdk.d.ts +30173 -0
  274. package/lib/services/coingecko/fetcher.d.ts +15 -0
  275. package/lib/services/coingecko/fetcher.js +67 -0
  276. package/lib/services/coingecko/index.d.ts +2 -0
  277. package/lib/services/coingecko/index.js +19 -0
  278. package/lib/services/coingecko/utils.d.ts +1 -0
  279. package/lib/services/coingecko/utils.js +24 -0
  280. package/lib/services/debank/fetcher.d.ts +126 -0
  281. package/lib/services/debank/fetcher.js +47 -0
  282. package/lib/services/debank/index.d.ts +2 -0
  283. package/lib/services/debank/index.js +19 -0
  284. package/lib/services/debank/utils.d.ts +50 -0
  285. package/lib/services/debank/utils.js +325 -0
  286. package/lib/services/layerzero/deposits.d.ts +55 -0
  287. package/lib/services/layerzero/deposits.js +174 -0
  288. package/lib/services/layerzero/redeems.d.ts +20 -0
  289. package/lib/services/layerzero/redeems.js +92 -0
  290. package/lib/services/layerzero/utils.d.ts +9 -0
  291. package/lib/services/layerzero/utils.js +22 -0
  292. package/lib/services/octavfi/fetcher.d.ts +33 -0
  293. package/lib/services/octavfi/fetcher.js +39 -0
  294. package/lib/services/octavfi/index.d.ts +3 -0
  295. package/lib/services/octavfi/index.js +20 -0
  296. package/lib/services/octavfi/types.d.ts +34 -0
  297. package/lib/services/octavfi/types.js +3 -0
  298. package/lib/services/octavfi/utils.d.ts +16 -0
  299. package/lib/services/octavfi/utils.js +244 -0
  300. package/lib/services/subgraph/fetcher.d.ts +2 -0
  301. package/lib/services/subgraph/fetcher.js +66 -0
  302. package/lib/services/subgraph/index.d.ts +2 -0
  303. package/lib/services/subgraph/index.js +19 -0
  304. package/lib/services/subgraph/schema.d.ts +48 -0
  305. package/lib/services/subgraph/schema.js +87 -0
  306. package/lib/services/subgraph/vaults.d.ts +83 -0
  307. package/lib/services/subgraph/vaults.js +1282 -0
  308. package/lib/services/swap-quotes/index.d.ts +105 -0
  309. package/lib/services/swap-quotes/index.js +77 -0
  310. package/lib/services/swap-quotes/paraswap.d.ts +51 -0
  311. package/lib/services/swap-quotes/paraswap.js +138 -0
  312. package/lib/services/untangled/fetcher.d.ts +40 -0
  313. package/lib/services/untangled/fetcher.js +110 -0
  314. package/lib/services/untangled/index.d.ts +3 -0
  315. package/lib/services/untangled/index.js +20 -0
  316. package/lib/services/untangled/types.d.ts +83 -0
  317. package/lib/services/untangled/types.js +10 -0
  318. package/lib/services/untangled/utils.d.ts +91 -0
  319. package/lib/services/untangled/utils.js +339 -0
  320. package/lib/types/api.d.ts +498 -0
  321. package/lib/types/api.js +3 -0
  322. package/lib/types/index.d.ts +12 -0
  323. package/lib/types/index.js +28 -0
  324. package/lib/types/points.d.ts +28 -0
  325. package/lib/types/points.js +3 -0
  326. package/lib/types/pools.d.ts +144 -0
  327. package/lib/types/pools.js +3 -0
  328. package/lib/types/staking.d.ts +28 -0
  329. package/lib/types/staking.js +3 -0
  330. package/lib/types/sub-accounts.d.ts +150 -0
  331. package/lib/types/sub-accounts.js +3 -0
  332. package/lib/types/subgraph.d.ts +84 -0
  333. package/lib/types/subgraph.js +3 -0
  334. package/lib/types/typed-contract.d.ts +102 -0
  335. package/lib/types/typed-contract.js +3 -0
  336. package/lib/types/user.d.ts +1 -0
  337. package/lib/types/user.js +3 -0
  338. package/lib/types/vaults.d.ts +886 -0
  339. package/lib/types/vaults.js +30 -0
  340. package/lib/types/web3.d.ts +100 -0
  341. package/lib/types/web3.js +14 -0
  342. package/lib/types/webserver.d.ts +730 -0
  343. package/lib/types/webserver.js +3 -0
  344. package/package.json +79 -3
@@ -0,0 +1,657 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.describeSolanaError = describeSolanaError;
4
+ exports.slippageHint = slippageHint;
5
+ exports.validateExplicitFloor = validateExplicitFloor;
6
+ exports.handleSolanaDeposit = handleSolanaDeposit;
7
+ exports.handleSolanaRedeem = handleSolanaRedeem;
8
+ const anchor_1 = require("@coral-xyz/anchor");
9
+ const web3_js_1 = require("@solana/web3.js");
10
+ const spl_token_1 = require("@solana/spl-token");
11
+ const pricing_1 = require("./pricing");
12
+ const utils_1 = require("./utils");
13
+ const core_1 = require("../../core");
14
+ const token_reads_1 = require("./token-reads");
15
+ const queue_hints_1 = require("./queue-hints");
16
+ /**
17
+ * User-facing fallback for a throwable that carries no extractable reason.
18
+ * Surfaces as e.g. `"Solana deposit failed: please try again"` — actionable,
19
+ * and without telling the user we couldn't classify the failure.
20
+ */
21
+ const REASONLESS_SOLANA_ERROR = 'please try again';
22
+ /**
23
+ * Extract a human- and machine-readable reason from a thrown Solana/Anchor
24
+ * error.
25
+ *
26
+ * Anchor's {@link https://github.com/coral-xyz/anchor `ProgramError`} calls
27
+ * `super()` with no argument, so its `.message` is the empty string by
28
+ * construction — the real reason lives on `.msg`/`.code` (and `.toString()`).
29
+ * `AnchorError` puts it on `.error.errorMessage` / `.error.errorCode.number`.
30
+ * Reading `.message` directly (as this file used to) therefore rendered
31
+ * `"Solana deposit failed: "` for every recognized on-chain revert — dropping
32
+ * the numeric code the team needs to tell "Vault is paused" from
33
+ * "Insufficient amount" from an account-constraint violation.
34
+ *
35
+ * When no reason can be extracted, returns an actionable, user-facing fallback
36
+ * rather than an "unknown error" admission — the raw throwable is still
37
+ * preserved on the wrapped error's `cause` and in telemetry for diagnosis.
38
+ */
39
+ function describeSolanaError(e) {
40
+ if (!(e instanceof Error))
41
+ return REASONLESS_SOLANA_ERROR;
42
+ const anchor = e;
43
+ const reason = anchor.error?.errorMessage ?? anchor.msg ?? '';
44
+ const code = anchor.error?.errorCode?.number ?? anchor.code;
45
+ if (reason)
46
+ return code === undefined ? reason : `${reason} (code ${code})`;
47
+ // SendTransactionError / generic Error carry a non-empty `.message`.
48
+ if (e.message)
49
+ return e.message;
50
+ // Last resort: a subclass may override `toString()` (never the empty string).
51
+ const str = e.toString();
52
+ return str && str !== e.name && str !== `${e.name}: `
53
+ ? str
54
+ : REASONLESS_SOLANA_ERROR;
55
+ }
56
+ /** `SlippageExceeded` in `august_vault`'s error enum (ordinal 18 + Anchor's 6000 offset). */
57
+ const SLIPPAGE_EXCEEDED_CODE = 6018;
58
+ /**
59
+ * A sentence to append when the program rejected the instruction for
60
+ * slippage, so the caller learns what to do rather than just what happened.
61
+ * Empty for every other error.
62
+ *
63
+ * Not merely a restatement of the program's reason string. Both checked
64
+ * instructions share error 6018, whose on-chain message is share-worded —
65
+ * "Received fewer shares than the caller's minimum" — so on a *redeem*, where
66
+ * the floor is denominated in assets, the program describes the wrong
67
+ * quantity. This sentence is what makes that case readable. The numeric code
68
+ * `describeSolanaError` renders alongside it is kept deliberately: it is the
69
+ * handle support and telemetry group on, and it survives a reword of the
70
+ * program's message.
71
+ */
72
+ function slippageHint(e) {
73
+ const anchor = e;
74
+ const code = anchor?.error?.errorCode?.number ?? anchor?.code;
75
+ const name = anchor?.error?.errorCode?.code;
76
+ return code === SLIPPAGE_EXCEEDED_CODE || name === 'SlippageExceeded'
77
+ ? ' The share price moved past your slippage tolerance between the quote and execution; retry, or pass a higher `slippageBps`.'
78
+ : '';
79
+ }
80
+ /** Largest value Anchor's `u64` encoder can represent. */
81
+ const U64_MAX = 18446744073709551615n;
82
+ /**
83
+ * Validate a caller-supplied slippage floor before it reaches Anchor's `u64`
84
+ * encoder.
85
+ *
86
+ * Anchor serializes a `BN` to `u64` via `toArrayLike`, which writes the
87
+ * magnitude and drops the sign — a `-1n` floor would reach the program as a
88
+ * floor of `1`, inverting the caller's intent instead of failing. Values above
89
+ * `u64` fare no better: they surface as an untyped "byte array longer than
90
+ * desired length" from inside the encoder, naming nothing the caller passed.
91
+ * Both are caught here, at the public-API boundary.
92
+ *
93
+ * @param value - The caller's `minSharesOut` / `minAssetsOut`, in raw base units.
94
+ * @param label - Option name, quoted in the error.
95
+ * @returns `value`, once known to fit an unsigned 64-bit integer.
96
+ * @throws {@link UpshiftValidationError} when it is not a `bigint` in `0 .. 2^64-1`.
97
+ */
98
+ function validateExplicitFloor(value, label) {
99
+ if (typeof value !== 'bigint' || value < 0n || value > U64_MAX) {
100
+ throw new core_1.UpshiftValidationError('INVALID_INPUT', `${label} must be a bigint between 0 and ${U64_MAX} raw base units, got ${String(value)}.`);
101
+ }
102
+ return value;
103
+ }
104
+ /**
105
+ * Decide whether a handler can send the slippage-checked instruction, or must
106
+ * fall back to the plain one.
107
+ *
108
+ * `idl` is caller-supplied, and an IDL generated before the program shipped
109
+ * `deposit_checked` / `redeem_checked` produces a `Program` with no such
110
+ * method. Until 9.4.0 the handlers sent the plain instructions, so those same
111
+ * inputs used to work; calling the checked method on them throws a TypeError
112
+ * before anything is sent (AUGUST-8023). The program still accepts the plain
113
+ * instructions, with the behaviour a floor of `0` gives the checked ones, so
114
+ * falling back preserves what those callers had.
115
+ *
116
+ * The fallback is refused when the caller asked for protection — a non-zero
117
+ * explicit floor, or any `slippageBps` — since the plain instruction would
118
+ * silently drop it. An explicit floor of `0n` is the documented "no floor" and
119
+ * falls back.
120
+ *
121
+ * Probes `program.methods` rather than `idl.instructions`: that is the object
122
+ * the handler calls, and it already reflects Anchor's camelCase conversion.
123
+ *
124
+ * @param program - Anchor program built from the caller's IDL.
125
+ * @param checkedMethod - `'depositChecked'` or `'redeemChecked'`.
126
+ * @param floor - The caller's explicit `minSharesOut` / `minAssetsOut`, if any.
127
+ * @param slippageBps - The caller's tolerance, if any.
128
+ * @param handler - Handler name, for the log line and the error.
129
+ * @returns `true` to send the checked instruction, `false` for the plain one.
130
+ * @throws {@link UpshiftValidationError} when the IDL lacks the checked
131
+ * instruction and the caller asked for a floor.
132
+ */
133
+ function sendsCheckedInstruction({ program, checkedMethod, floor, slippageBps, handler, }) {
134
+ const methods = program.methods;
135
+ if (typeof methods[checkedMethod] === 'function')
136
+ return true;
137
+ const instruction = checkedMethod === 'depositChecked' ? 'deposit_checked' : 'redeem_checked';
138
+ const floorOption = checkedMethod === 'depositChecked' ? 'minSharesOut' : 'minAssetsOut';
139
+ if ((floor !== undefined && floor !== 0n) || slippageBps !== undefined) {
140
+ throw new core_1.UpshiftValidationError('INVALID_INPUT', `${handler}: the supplied IDL does not declare \`${instruction}\`, so ` +
141
+ `the requested ${floorOption} / slippageBps cannot be enforced. Pass ` +
142
+ "the SDK's bundled IDL (`Solana.constants.vaultIdl`), or omit both " +
143
+ 'options to send the unguarded instruction.');
144
+ }
145
+ core_1.Logger.log.warn(handler, `Supplied IDL does not declare \`${instruction}\`; sending the plain ` +
146
+ "instruction without a slippage floor. Pass the SDK's bundled IDL to " +
147
+ 'enable slippage protection.');
148
+ return false;
149
+ }
150
+ /**
151
+ * Resolve the two token accounts a vault instruction needs, concurrently.
152
+ *
153
+ * The lookups are independent, so running them in sequence doubles the
154
+ * round-trip latency on the hot path for no benefit — both results are needed
155
+ * before anything is submitted either way.
156
+ *
157
+ * Rejections are surfaced in argument order rather than in whichever order the
158
+ * RPC happened to fail, so the error a user sees does not depend on network
159
+ * timing. `Promise.all` would reject with whichever call failed *first*, which
160
+ * on a malformed RPC response (both lookups throwing) would name a different
161
+ * account run to run.
162
+ *
163
+ * @param mints - `[first, second]`; the returned tuple matches this order.
164
+ */
165
+ async function resolveUserTokenAccountPair({ connection, owner, mints, }) {
166
+ const settled = await Promise.allSettled(mints.map((mint) => (0, token_reads_1.resolveUserTokenAccount)({ connection, owner, mint })));
167
+ const resolved = settled.map((outcome) => {
168
+ if (outcome.status === 'rejected')
169
+ throw outcome.reason;
170
+ return outcome.value;
171
+ });
172
+ return [resolved[0], resolved[1]];
173
+ }
174
+ /**
175
+ * Deposit funds into a Solana Upshift vault and mint share tokens.
176
+ *
177
+ * @param depositAmount `bigint` is treated as raw on-chain units (preferred
178
+ * — no JS-float round-trip). `number` is treated as a UI amount and
179
+ * scaled by the deposit mint's decimals via {@link uiAmountToRawBn}.
180
+ * @throws UpshiftValidationError on missing wallet/programId or invalid amount,
181
+ * or when the wallet's deposit-mint balance is below `depositAmount`.
182
+ * @throws UpshiftSDKError when a candidate token account's balance cannot be
183
+ * read, or wrapping any downstream failure (`cause` preserved).
184
+ * @throws UpshiftTransactionError (`TRANSACTION_UNCONFIRMED`) when the
185
+ * transaction was sent but its outcome could not be established; check
186
+ * `signature` before resubmitting.
187
+ * @remarks **Side effects.** Submits exactly one transaction, signed by the
188
+ * provider's wallet. When the wallet has no share account, that transaction
189
+ * also creates one, and `publicKey` pays its rent — roughly 0.00204 SOL,
190
+ * non-refundable while the account stays open — on top of the network fee.
191
+ * Callers should ensure the wallet holds enough SOL for both before
192
+ * prompting the user to sign.
193
+ * @remarks Sends `deposit_checked`, not `deposit`. Unless `options.minSharesOut`
194
+ * is given, the vault state and share mint are read to quote the shares this
195
+ * deposit should mint, and that quote lowered by `options.slippageBps`
196
+ * (default {@link DEFAULT_SLIPPAGE_BPS}) is passed as the floor; the program
197
+ * reverts with `SlippageExceeded` if execution would mint fewer. An `idl`
198
+ * that predates `deposit_checked` gets the plain `deposit` with no floor,
199
+ * unless `options` asks for one — then it throws {@link UpshiftValidationError}.
200
+ */
201
+ async function handleSolanaDeposit({ provider, connection, vaultProgramId, vaultAddress, depositAmount, publicKey, idl, options = {}, }) {
202
+ try {
203
+ if (!publicKey)
204
+ throw new core_1.UpshiftValidationError('INVALID_INPUT', 'handleSolanaDeposit: wallet not connected');
205
+ if (depositAmount === undefined ||
206
+ depositAmount === null ||
207
+ (typeof depositAmount === 'bigint' && depositAmount <= 0n) ||
208
+ (typeof depositAmount === 'number' && !(depositAmount > 0)))
209
+ throw new core_1.UpshiftValidationError('INVALID_INPUT', 'handleSolanaDeposit: depositAmount is required and must be > 0');
210
+ if (!vaultProgramId)
211
+ throw new core_1.UpshiftValidationError('INVALID_INPUT', 'handleSolanaDeposit: vaultProgramId is required');
212
+ // Before any RPC: an unusable floor should cost the caller nothing.
213
+ if (options.minSharesOut !== undefined)
214
+ validateExplicitFloor(options.minSharesOut, 'minSharesOut');
215
+ const _vaultProgramId = new web3_js_1.PublicKey(vaultProgramId);
216
+ const program = utils_1.SolanaUtils.getProgram({
217
+ provider,
218
+ idl,
219
+ programId: _vaultProgramId.toBase58(),
220
+ });
221
+ // Also before any RPC: a floor the caller's IDL cannot enforce is refused
222
+ // on the spot rather than after the mint and token-account reads.
223
+ const checked = sendsCheckedInstruction({
224
+ program,
225
+ checkedMethod: 'depositChecked',
226
+ floor: options.minSharesOut,
227
+ slippageBps: options.slippageBps,
228
+ handler: 'handleSolanaDeposit',
229
+ });
230
+ // `getVaultMints` throws a typed `UpshiftSDKError` when the state cannot be
231
+ // read, so both mints are present here.
232
+ const { depositMint, shareMint, vaultVersion } = await utils_1.SolanaUtils.getVaultMints({
233
+ connection,
234
+ vaultProgramId,
235
+ vaultAddress,
236
+ idl,
237
+ });
238
+ const _publicKey = new web3_js_1.PublicKey(publicKey);
239
+ const _depositMint = new web3_js_1.PublicKey(depositMint);
240
+ core_1.Logger.log.info('handleSolanaDeposit', 'Program', program);
241
+ const vaultStatePda = vaultAddress
242
+ ? new web3_js_1.PublicKey(vaultAddress)
243
+ : utils_1.SolanaUtils.deriveVaultStatePda(_vaultProgramId);
244
+ core_1.Logger.log.info('handleSolanaDeposit', 'Vault state PDA', vaultStatePda.toBase58());
245
+ const vaultTokenAtaPda = utils_1.SolanaUtils.deriveVaultTokenAtaPda(_vaultProgramId, _depositMint, vaultVersion);
246
+ core_1.Logger.log.info('handleSolanaDeposit', 'Vault token ATA PDA', vaultTokenAtaPda.toBase58());
247
+ // Use on-chain share mint from vault state instead of deriving a PDA,
248
+ // since PDA derivation assumes one share mint per program (single-vault only).
249
+ const shareMintAddr = new web3_js_1.PublicKey(shareMint);
250
+ core_1.Logger.log.info('handleSolanaDeposit', 'Share mint', shareMintAddr.toBase58());
251
+ // Get mint info to handle decimals
252
+ const mintInfo = await connection.getParsedAccountInfo(_depositMint);
253
+ if (!mintInfo.value) {
254
+ throw new core_1.UpshiftSDKError('UNKNOWN', `Could not fetch deposit mint info: account ${_depositMint.toBase58()} not found on the connected RPC`, { context: { depositMint: _depositMint.toBase58() } });
255
+ }
256
+ const { decimals } = mintInfo.value.data.parsed.info;
257
+ let depositAmountRaw;
258
+ if (typeof depositAmount === 'bigint') {
259
+ depositAmountRaw = new anchor_1.BN(depositAmount.toString());
260
+ }
261
+ else {
262
+ if (isNaN(depositAmount)) {
263
+ throw new core_1.UpshiftValidationError('INVALID_INPUT', 'Please enter a valid number for the deposit amount');
264
+ }
265
+ if (depositAmount <= 0) {
266
+ throw new core_1.UpshiftValidationError('INVALID_INPUT', 'Deposit amount must be greater than 0');
267
+ }
268
+ depositAmountRaw = (0, utils_1.uiAmountToRawBn)(depositAmount, decimals);
269
+ }
270
+ // Re-check *after* scaling. The guard above tests the caller's number, but
271
+ // a positive UI amount below one raw unit (1e-7 into a 6-decimal mint)
272
+ // truncates to zero here. Zero would then pass the balance gate below
273
+ // (`0n < 0n` is false) and submit a no-op transfer — from an account that
274
+ // may not even exist, since a zero balance is also what an absent account
275
+ // reports.
276
+ if (depositAmountRaw.lten(0)) {
277
+ throw new core_1.UpshiftValidationError('INVALID_INPUT', `Deposit amount is too small: ${depositAmount} is below one raw unit ` +
278
+ `of a ${decimals}-decimal mint.`);
279
+ }
280
+ // Match whatever this connection *reads* at. A `Connection` built without
281
+ // a commitment omits the parameter, so its reads take the RPC's default —
282
+ // `finalized`. Confirming writes at `confirmed` there would put reads
283
+ // behind writes again, which is the mismatch this whole change removes.
284
+ // `SolanaAdapter` always sets one explicitly, so this fallback only
285
+ // applies to callers reaching these handlers directly via `Solana.actions`.
286
+ const txCommitment = connection.commitment ?? 'finalized';
287
+ // `depositAccount` funds the transfer; `shareAccount` receives the minted
288
+ // shares. Independent lookups, so they run concurrently — but the guards
289
+ // below stay in a fixed order so the first problem a user hits is always
290
+ // reported the same way.
291
+ const [depositAccount, shareAccount] = await resolveUserTokenAccountPair({
292
+ connection,
293
+ owner: _publicKey,
294
+ mints: [_depositMint, shareMintAddr],
295
+ });
296
+ // Gate on the balance, not on whether an account exists: an empty leftover
297
+ // account is a real state, and letting it through only trades this error
298
+ // for an insufficient-funds revert the user pays a signature to discover.
299
+ // The balance is already in hand from the lookup, so this costs no extra
300
+ // RPC.
301
+ if (depositAccount.frozen) {
302
+ throw new core_1.UpshiftValidationError('INVALID_INPUT', 'Your token account for the deposit mint is frozen by the token issuer, ' +
303
+ 'so the deposit cannot be transferred out of it.');
304
+ }
305
+ if (depositAccount.balance < BigInt(depositAmountRaw.toString())) {
306
+ throw new core_1.UpshiftValidationError('INVALID_INPUT', `Insufficient balance to deposit: this wallet holds ${depositAccount.balance} ` +
307
+ `raw units of the deposit mint, and the deposit requires ${depositAmountRaw.toString()}.`);
308
+ }
309
+ const senderTokenAccount = depositAccount.address;
310
+ // A missing share account is routine — every first-time depositor starts
311
+ // here, as does anyone whose account was closed after redeeming their full
312
+ // balance — so it is created inline rather than rejecting the deposit.
313
+ // Minting into a *frozen* one fails just as transferring out of one does,
314
+ // so this destination needs the same guard as the funding account above.
315
+ if (shareAccount.frozen) {
316
+ throw new core_1.UpshiftValidationError('INVALID_INPUT', 'Your share account is frozen by the token issuer, so it cannot ' +
317
+ 'receive the shares this deposit would mint.');
318
+ }
319
+ const senderShareAccount = shareAccount.address;
320
+ const preInstructions = shareAccount.createIx
321
+ ? [shareAccount.createIx]
322
+ : [];
323
+ core_1.Logger.log.info('handleSolanaDeposit', 'Sender token account', senderTokenAccount.toBase58());
324
+ core_1.Logger.log.info('handleSolanaDeposit', shareAccount.createIx
325
+ ? 'Sender share account (created in this tx)'
326
+ : 'Sender share account (existing)', senderShareAccount.toBase58());
327
+ core_1.Logger.log.info('handleSolanaDeposit', '\n\nDeposit TX Params:\n');
328
+ core_1.Logger.log.info('handleSolanaDeposit', 'Program', depositAmountRaw);
329
+ core_1.Logger.log.info('handleSolanaDeposit', 'Vault state PDA', vaultStatePda.toBase58());
330
+ core_1.Logger.log.info('handleSolanaDeposit', 'Vault token ATA PDA', vaultTokenAtaPda.toBase58());
331
+ core_1.Logger.log.info('handleSolanaDeposit', 'Share mint', shareMintAddr.toBase58());
332
+ core_1.Logger.log.info('handleSolanaDeposit', 'Deposit mint', _depositMint?.toBase58());
333
+ core_1.Logger.log.info('handleSolanaDeposit', 'Signer', _publicKey.toBase58());
334
+ let minSharesOut;
335
+ if (!checked) {
336
+ // The plain instruction takes no floor, so there is nothing to quote.
337
+ }
338
+ else if (options.minSharesOut !== undefined) {
339
+ minSharesOut = options.minSharesOut;
340
+ }
341
+ else {
342
+ // One read the unguarded `deposit` never needed: the vault state (assets
343
+ // and offset) and the share mint (supply) in a single snapshot, since
344
+ // pricing against a mismatched pair is worse than not quoting at all —
345
+ // see `readPricingSnapshot`. A caller already holding a quote can pass
346
+ // `minSharesOut` and skip it.
347
+ const { vaultStateData, supply } = await (0, token_reads_1.readPricingSnapshot)({
348
+ connection,
349
+ program,
350
+ vaultStatePda,
351
+ shareMintAddr,
352
+ });
353
+ minSharesOut = (0, pricing_1.quoteDepositFloor)({
354
+ supply,
355
+ totalAssets: (0, pricing_1.totalAssetsOf)(vaultStateData),
356
+ amount: BigInt(depositAmountRaw.toString()),
357
+ offset: (0, pricing_1.resolveShareOffset)(vaultStateData.shareOffset),
358
+ slippageBps: options.slippageBps ?? pricing_1.DEFAULT_SLIPPAGE_BPS,
359
+ });
360
+ }
361
+ core_1.Logger.log.info('handleSolanaDeposit', 'Min shares out (raw)', minSharesOut?.toString() ?? 'none (plain deposit)');
362
+ const methods = program.methods;
363
+ const tx = await (minSharesOut === undefined
364
+ ? methods.deposit(depositAmountRaw)
365
+ : methods.depositChecked(depositAmountRaw, new anchor_1.BN(minSharesOut.toString())))
366
+ .accounts({
367
+ vaultState: vaultStatePda,
368
+ vaultTokenAta: vaultTokenAtaPda,
369
+ senderTokenAccount,
370
+ senderShareAccount,
371
+ shareMint: shareMintAddr,
372
+ depositMint: _depositMint,
373
+ signer: _publicKey,
374
+ tokenProgram: spl_token_1.TOKEN_PROGRAM_ID,
375
+ })
376
+ .preInstructions(preInstructions)
377
+ // `.rpc()` builds, signs, submits and confirms in one step. The extra
378
+ // `getLatestBlockhash` + `confirmTransaction` this module used to run
379
+ // afterwards re-confirmed an already-confirmed signature against a
380
+ // blockhash the transaction never carried.
381
+ //
382
+ // Commitment is taken from the same `Connection` every read in this
383
+ // adapter uses, so a caller who asks for 'finalized' gets it on both
384
+ // sides rather than finalized reads racing confirmed writes.
385
+ .rpc({
386
+ skipPreflight: false,
387
+ preflightCommitment: txCommitment,
388
+ commitment: txCommitment,
389
+ });
390
+ core_1.Logger.log.info('handleSolanaDeposit', 'Deposit successful:', tx);
391
+ return tx;
392
+ }
393
+ catch (e) {
394
+ if (e instanceof core_1.UpshiftSDKError)
395
+ throw e;
396
+ const depositAmountForLog = typeof depositAmount === 'bigint'
397
+ ? depositAmount.toString()
398
+ : depositAmount;
399
+ core_1.Logger.log.error('handleSolanaDeposit', e, {
400
+ vaultProgramId: String(vaultProgramId),
401
+ vaultAddress: vaultAddress ? String(vaultAddress) : undefined,
402
+ depositAmount: depositAmountForLog,
403
+ });
404
+ throw new core_1.UpshiftSDKError('UNKNOWN', `Solana deposit failed: ${describeSolanaError(e)}${slippageHint(e)}`, {
405
+ cause: e,
406
+ context: {
407
+ vaultProgramId: String(vaultProgramId),
408
+ vaultAddress: vaultAddress ? String(vaultAddress) : undefined,
409
+ depositAmount: depositAmountForLog,
410
+ },
411
+ });
412
+ }
413
+ }
414
+ /**
415
+ * Redeem vault shares back into the underlying mint on a Solana Upshift vault.
416
+ *
417
+ * @param redeemShares `bigint` is treated as raw share-token units;
418
+ * `number` is treated as a UI amount.
419
+ * @remarks Sends `redeem_checked`, not `redeem`. Unless `options.minAssetsOut`
420
+ * is given, the payout is quoted from the vault state and share supply the
421
+ * handler already reads, **net of the withdrawal fee**, and that quote
422
+ * lowered by `options.slippageBps` (default {@link DEFAULT_SLIPPAGE_BPS}) is
423
+ * passed as the floor; the program reverts with `SlippageExceeded` below it.
424
+ * An `idl` that predates `redeem_checked` gets the plain `redeem` with no
425
+ * floor, unless `options` asks for one — then it throws
426
+ * {@link UpshiftValidationError}.
427
+ * @throws UpshiftValidationError on missing wallet/programId or invalid amount,
428
+ * or when the wallet holds fewer shares than `redeemShares`.
429
+ * @throws UpshiftSDKError when a candidate token account's balance cannot be
430
+ * read, or wrapping any downstream failure (`cause` preserved).
431
+ * @throws UpshiftTransactionError (`TRANSACTION_UNCONFIRMED`) when the
432
+ * transaction was sent but its outcome could not be established; check
433
+ * `signature` before resubmitting.
434
+ * @remarks **Side effects.** Submits exactly one transaction, signed by the
435
+ * provider's wallet. That transaction also creates the payout account when
436
+ * the wallet has none, and the vault's fee-recipient account when *it* has
437
+ * none — `publicKey` pays rent for both, roughly 0.00204 SOL each and
438
+ * non-refundable, on top of the network fee. Callers should ensure the
439
+ * wallet holds enough SOL for all of it before prompting the user to sign.
440
+ */
441
+ async function handleSolanaRedeem({ provider, connection, vaultProgramId, vaultAddress, publicKey, redeemShares, idl, options = {}, }) {
442
+ try {
443
+ if (!publicKey)
444
+ throw new core_1.UpshiftValidationError('INVALID_INPUT', 'handleSolanaRedeem: wallet not connected');
445
+ if (redeemShares === undefined ||
446
+ redeemShares === null ||
447
+ (typeof redeemShares === 'bigint' && redeemShares <= 0n) ||
448
+ (typeof redeemShares === 'number' && !(redeemShares > 0)))
449
+ throw new core_1.UpshiftValidationError('INVALID_INPUT', 'handleSolanaRedeem: redeemShares is required and must be > 0');
450
+ if (!vaultProgramId)
451
+ throw new core_1.UpshiftValidationError('INVALID_INPUT', 'handleSolanaRedeem: vaultProgramId is required');
452
+ // Before any RPC: an unusable floor should cost the caller nothing.
453
+ if (options.minAssetsOut !== undefined)
454
+ validateExplicitFloor(options.minAssetsOut, 'minAssetsOut');
455
+ const _vaultProgramId = new web3_js_1.PublicKey(vaultProgramId);
456
+ const program = utils_1.SolanaUtils.getProgram({
457
+ provider,
458
+ idl,
459
+ programId: _vaultProgramId.toBase58(),
460
+ });
461
+ // See `handleSolanaDeposit`: refused before any RPC.
462
+ const checked = sendsCheckedInstruction({
463
+ program,
464
+ checkedMethod: 'redeemChecked',
465
+ floor: options.minAssetsOut,
466
+ slippageBps: options.slippageBps,
467
+ handler: 'handleSolanaRedeem',
468
+ });
469
+ // `getVaultMints` throws a typed `UpshiftSDKError` when the state cannot be
470
+ // read, so both mints are present here.
471
+ const { depositMint, shareMint, vaultVersion } = await utils_1.SolanaUtils.getVaultMints({
472
+ connection,
473
+ vaultProgramId,
474
+ vaultAddress,
475
+ idl,
476
+ });
477
+ const _depositMint = new web3_js_1.PublicKey(depositMint);
478
+ const _publicKey = new web3_js_1.PublicKey(publicKey);
479
+ const vaultStatePda = vaultAddress
480
+ ? new web3_js_1.PublicKey(vaultAddress)
481
+ : utils_1.SolanaUtils.deriveVaultStatePda(_vaultProgramId);
482
+ const vaultTokenAtaPda = utils_1.SolanaUtils.deriveVaultTokenAtaPda(_vaultProgramId, _depositMint, vaultVersion);
483
+ // Use on-chain share mint from vault state instead of deriving a PDA,
484
+ // since PDA derivation assumes one share mint per program (single-vault only).
485
+ const shareMintAddr = new web3_js_1.PublicKey(shareMint);
486
+ // Share-mint decimals and supply plus the vault state, from one slot. This
487
+ // replaces a `getParsedAccountInfo` here and a `vaultState.fetch` further
488
+ // down — one round trip rather than two, and supply and assets can no
489
+ // longer be read either side of someone else's deposit.
490
+ const { vaultStateData, supply: shareSupply, shareDecimals, } = await (0, token_reads_1.readPricingSnapshot)({
491
+ connection,
492
+ program,
493
+ vaultStatePda,
494
+ shareMintAddr,
495
+ });
496
+ // A vault with a queue attached accepts a redeem from the queue alone, so
497
+ // a holder's direct redeem can only revert with `WithdrawalQueueRequired`.
498
+ // Say so before the wallet is asked to sign.
499
+ const gate = vaultStateData.withdrawalQueueAuthority;
500
+ if (gate && !new web3_js_1.PublicKey(gate).equals(web3_js_1.PublicKey.default)) {
501
+ throw new core_1.UpshiftValidationError('INVALID_INPUT', 'This vault redeems through its withdrawal queue: request with ' +
502
+ '`vaultRequestRedeem`, then claim the request with `vaultRedeem` and ' +
503
+ '`options.request` once its cooldown has run.');
504
+ }
505
+ let redeemSharesRaw;
506
+ if (typeof redeemShares === 'bigint') {
507
+ redeemSharesRaw = new anchor_1.BN(redeemShares.toString());
508
+ }
509
+ else {
510
+ if (isNaN(redeemShares)) {
511
+ throw new core_1.UpshiftValidationError('INVALID_INPUT', 'Please enter a valid number for the shares to redeem');
512
+ }
513
+ if (redeemShares <= 0) {
514
+ throw new core_1.UpshiftValidationError('INVALID_INPUT', 'Shares to redeem must be greater than 0');
515
+ }
516
+ redeemSharesRaw = (0, utils_1.uiAmountToRawBn)(redeemShares, shareDecimals);
517
+ }
518
+ // See `handleSolanaDeposit` — a positive UI amount can truncate to zero,
519
+ // which would pass the share-balance gate below and burn nothing.
520
+ if (redeemSharesRaw.lten(0)) {
521
+ throw new core_1.UpshiftValidationError('INVALID_INPUT', `Redemption amount is too small: ${redeemShares} is below one raw unit ` +
522
+ `of a ${shareDecimals}-decimal share mint.`);
523
+ }
524
+ // Match whatever this connection *reads* at. A `Connection` built without
525
+ // a commitment omits the parameter, so its reads take the RPC's default —
526
+ // `finalized`. Confirming writes at `confirmed` there would put reads
527
+ // behind writes again, which is the mismatch this whole change removes.
528
+ // `SolanaAdapter` always sets one explicitly, so this fallback only
529
+ // applies to callers reaching these handlers directly via `Solana.actions`.
530
+ const txCommitment = connection.commitment ?? 'finalized';
531
+ // `shareAccount` is burned from; `payoutAccount` receives the underlying.
532
+ // Independent lookups, so they run concurrently — guards stay ordered.
533
+ const [shareAccount, payoutAccount] = await resolveUserTokenAccountPair({
534
+ connection,
535
+ owner: _publicKey,
536
+ mints: [shareMintAddr, _depositMint],
537
+ });
538
+ // Gated on balance for the same reason as the deposit's funding account.
539
+ if (shareAccount.frozen) {
540
+ throw new core_1.UpshiftValidationError('INVALID_INPUT', 'Your share account is frozen by the token issuer, so these shares ' +
541
+ 'cannot be redeemed.');
542
+ }
543
+ if (shareAccount.balance < BigInt(redeemSharesRaw.toString())) {
544
+ throw new core_1.UpshiftValidationError('INVALID_INPUT', `Insufficient shares to redeem: this wallet holds ${shareAccount.balance} ` +
545
+ `raw share units, and the redemption requires ${redeemSharesRaw.toString()}.`);
546
+ }
547
+ const senderShareAccount = shareAccount.address;
548
+ // Redeeming is precisely how a holder first receives the deposit mint, so
549
+ // requiring the payout account to pre-exist (as this module used to) left
550
+ // shares unredeemable through this SDK for everyone who acquired them any
551
+ // way other than depositing from this same wallet — a transfer, an
552
+ // airdrop, a market buy — as well as any depositor who later closed their
553
+ // deposit-mint account. A frozen account cannot receive either, so the
554
+ // payout would revert.
555
+ if (payoutAccount.frozen) {
556
+ throw new core_1.UpshiftValidationError('INVALID_INPUT', 'Your token account for the deposit mint is frozen by the token issuer, ' +
557
+ 'so it cannot receive the redemption proceeds.');
558
+ }
559
+ const senderTokenAccount = payoutAccount.address;
560
+ // No extra reads here: the share mint (supply) and vault state (assets,
561
+ // offset, fee, fee recipient) came from the snapshot above.
562
+ let minAssetsOut;
563
+ if (!checked) {
564
+ // The plain instruction takes no floor, so there is nothing to quote.
565
+ }
566
+ else if (options.minAssetsOut !== undefined) {
567
+ minAssetsOut = options.minAssetsOut;
568
+ }
569
+ else {
570
+ minAssetsOut = (0, pricing_1.quoteRedeemFloor)({
571
+ supply: shareSupply,
572
+ totalAssets: (0, pricing_1.totalAssetsOf)(vaultStateData),
573
+ shares: BigInt(redeemSharesRaw.toString()),
574
+ offset: (0, pricing_1.resolveShareOffset)(vaultStateData.shareOffset),
575
+ feePpm: (0, pricing_1.toBigInt)(vaultStateData.withdrawalFee, 'withdrawalFee'),
576
+ slippageBps: options.slippageBps ?? pricing_1.DEFAULT_SLIPPAGE_BPS,
577
+ });
578
+ }
579
+ // The fee recipient's token account. Off-curve allowed (as in the queue
580
+ // claim path): a multisig vault or program PDA can be the fee recipient,
581
+ // and the default `allowOwnerOffCurve: false` throws
582
+ // `TokenOwnerOffCurveError` for one, blocking every direct redeem.
583
+ const feeRecipientTokenAccount = (0, spl_token_1.getAssociatedTokenAddressSync)(_depositMint, vaultStateData.feeRecipient, // This is the actual fee recipient from vault state
584
+ true);
585
+ // Every account this handler might have to create is created in the same
586
+ // transaction that uses it. The fee recipient's ATA is created
587
+ // unconditionally: the idempotent instruction is a no-op when the account
588
+ // already exists (costing the user nothing), which buys us one fewer RPC
589
+ // round trip and removes the read-then-create window entirely. The user
590
+ // pays the rent when it is genuinely absent, as before.
591
+ const preInstructions = [
592
+ (0, spl_token_1.createAssociatedTokenAccountIdempotentInstruction)(_publicKey, // payer (user pays for the account creation)
593
+ feeRecipientTokenAccount, // associated token account
594
+ vaultStateData.feeRecipient, // owner (the actual fee recipient)
595
+ _depositMint),
596
+ ];
597
+ if (payoutAccount.createIx)
598
+ preInstructions.push(payoutAccount.createIx);
599
+ core_1.Logger.log.info('handleSolanaRedeem', '\n\nRedeem TX Params:\n');
600
+ core_1.Logger.log.info('handleSolanaRedeem', 'Redeem shares (UI):', redeemShares);
601
+ core_1.Logger.log.info('handleSolanaRedeem', 'Redeem shares (raw):', redeemSharesRaw);
602
+ core_1.Logger.log.info('handleSolanaRedeem', 'Share decimals:', shareDecimals);
603
+ core_1.Logger.log.info('handleSolanaRedeem', 'Vault state PDA:', vaultStatePda.toBase58());
604
+ core_1.Logger.log.info('handleSolanaRedeem', 'Vault token ATA PDA:', vaultTokenAtaPda.toBase58());
605
+ core_1.Logger.log.info('handleSolanaRedeem', 'Sender token account:', senderTokenAccount?.toBase58());
606
+ core_1.Logger.log.info('handleSolanaRedeem', 'Sender share account:', senderShareAccount?.toBase58());
607
+ core_1.Logger.log.info('handleSolanaRedeem', 'Fee recipient account:', feeRecipientTokenAccount.toBase58());
608
+ core_1.Logger.log.info('handleSolanaRedeem', 'Share mint:', shareMintAddr.toBase58());
609
+ core_1.Logger.log.info('handleSolanaRedeem', 'Deposit mint:', _depositMint?.toBase58());
610
+ core_1.Logger.log.info('handleSolanaRedeem', 'Signer:', _publicKey.toBase58());
611
+ core_1.Logger.log.info('handleSolanaRedeem', 'Min assets out, net of fee (raw):', minAssetsOut?.toString() ?? 'none (plain redeem)');
612
+ const methods = program.methods;
613
+ const tx = await (minAssetsOut === undefined
614
+ ? methods.redeem(redeemSharesRaw)
615
+ : methods.redeemChecked(redeemSharesRaw, new anchor_1.BN(minAssetsOut.toString())))
616
+ .accounts({
617
+ vaultState: vaultStatePda,
618
+ vaultDepositAta: vaultTokenAtaPda,
619
+ senderTokenAccount,
620
+ senderShareAccount,
621
+ feeRecipientAccount: feeRecipientTokenAccount, // The actual fee recipient's token account
622
+ shareMint: shareMintAddr,
623
+ depositMint: _depositMint,
624
+ signer: _publicKey,
625
+ tokenProgram: spl_token_1.TOKEN_PROGRAM_ID,
626
+ })
627
+ .preInstructions(preInstructions)
628
+ // See `handleSolanaDeposit` for why `.rpc()` owns the confirmation and
629
+ // why the commitment comes from the connection.
630
+ .rpc({
631
+ skipPreflight: false,
632
+ preflightCommitment: txCommitment,
633
+ commitment: txCommitment,
634
+ });
635
+ core_1.Logger.log.info('handleSolanaRedeem', 'Redeem successful:', tx);
636
+ return tx;
637
+ }
638
+ catch (e) {
639
+ if (e instanceof core_1.UpshiftSDKError)
640
+ throw e;
641
+ const redeemSharesForLog = typeof redeemShares === 'bigint' ? redeemShares.toString() : redeemShares;
642
+ core_1.Logger.log.error('handleSolanaRedeem', e, {
643
+ vaultProgramId: String(vaultProgramId),
644
+ vaultAddress: vaultAddress ? String(vaultAddress) : undefined,
645
+ redeemShares: redeemSharesForLog,
646
+ });
647
+ throw new core_1.UpshiftSDKError('UNKNOWN', `Solana redeem failed: ${describeSolanaError(e)}${slippageHint(e)}${(0, queue_hints_1.redeemQueueHint)(e)}`, {
648
+ cause: e,
649
+ context: {
650
+ vaultProgramId: String(vaultProgramId),
651
+ vaultAddress: vaultAddress ? String(vaultAddress) : undefined,
652
+ redeemShares: redeemSharesForLog,
653
+ },
654
+ });
655
+ }
656
+ }
657
+ //# sourceMappingURL=vault.actions.js.map