@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,773 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SolanaUtils = exports.isSolanaAddress = void 0;
4
+ exports.assertSolanaProgramType = assertSolanaProgramType;
5
+ exports.undeployedProgramMessage = undeployedProgramMessage;
6
+ exports.selectRichestTokenAccount = selectRichestTokenAccount;
7
+ exports.uiAmountToRawBn = uiAmountToRawBn;
8
+ const anchor_1 = require("@coral-xyz/anchor");
9
+ const web3_js_1 = require("@solana/web3.js");
10
+ const ethers_1 = require("ethers");
11
+ const constants_1 = require("./constants");
12
+ const confirm_1 = require("./confirm");
13
+ const core_1 = require("../../core");
14
+ const cache_1 = require("../../core/cache");
15
+ // ============================================================================
16
+ // SOLANA UTILITIES
17
+ // ============================================================================
18
+ function getExplorerLink({ signature, type = 'tx', network = constants_1.fallbackNetwork, }) {
19
+ const baseUrl = 'https://solscan.io';
20
+ return `${baseUrl}/${type}/${signature}?cluster=${network}`;
21
+ }
22
+ // Re-exported from the core leaf so consumers in the core layer can import it
23
+ // without taking a dependency on the Solana adapter.
24
+ const chain_address_1 = require("../../core/helpers/chain-address");
25
+ Object.defineProperty(exports, "isSolanaAddress", { enumerable: true, get: function () { return chain_address_1.isSolanaAddress; } });
26
+ function isSolana(signature) {
27
+ if (!signature || typeof signature !== 'string')
28
+ return false;
29
+ // Check if it's an Ethereum address first
30
+ if ((0, ethers_1.isAddress)(signature))
31
+ return false;
32
+ // Check if it's a valid Solana address (including PDAs) — addresses are not signatures
33
+ if ((0, chain_address_1.isSolanaAddress)(signature))
34
+ return false;
35
+ // Check if it's a valid base58 string with correct length for Solana signatures
36
+ // Solana signatures are base58 encoded and typically 88 characters long
37
+ const base58Chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
38
+ const isValidBase58 = signature
39
+ .split('')
40
+ .every((char) => base58Chars.includes(char));
41
+ if (!isValidBase58)
42
+ return false;
43
+ // Check length - Solana signatures are typically 88 characters
44
+ return (signature.length >= 80 && signature.length <= 100);
45
+ }
46
+ /** On-chain name (IDL `metadata.name`) of each program type. */
47
+ const programNames = {
48
+ vault: 'august_vault',
49
+ withdrawalQueue: 'august_withdrawal_queue',
50
+ };
51
+ /**
52
+ * Throws unless `type` is a program type `programNames` maps. Checked at
53
+ * runtime for untyped callers: a typo would otherwise read as an undeployed
54
+ * program, and a prototype key like `toString` as a program id.
55
+ * @internal
56
+ */
57
+ function assertSolanaProgramType(type) {
58
+ if (typeof type !== 'string' || !Object.hasOwn(programNames, type)) {
59
+ throw new core_1.UpshiftValidationError('INVALID_INPUT', `Unknown Solana program type '${String(type)}'. Expected one of: ${Object.keys(programNames).join(', ')}.`);
60
+ }
61
+ }
62
+ /**
63
+ * Error text for `program` having no canonical deployment on `network`, naming
64
+ * the networks it is deployed on.
65
+ * @internal
66
+ */
67
+ function undeployedProgramMessage(program, network) {
68
+ const deployed = Object.entries(constants_1.programIds)
69
+ .filter(([, ids]) => ids[program])
70
+ .map(([name]) => name);
71
+ return (`No canonical ${programNames[program]} deployment for Solana network '${network}'. ` +
72
+ `Deployed networks: ${deployed.join(', ')}.`);
73
+ }
74
+ function getProgram({ provider, idl, programId, network, }) {
75
+ const baseIdl = idl ?? constants_1.vaultIdl;
76
+ // The withdrawal queue IDL resolves through `programIds.withdrawalQueue`;
77
+ // anything else is treated as the vault. Recognised by name, so the queue IDL
78
+ // never has to be imported here (and pulled into every bundle).
79
+ const program = baseIdl?.metadata?.name === programNames.withdrawalQueue
80
+ ? 'withdrawalQueue'
81
+ : 'vault';
82
+ // Precedence: explicit `programId` → a custom IDL's `address` → the network
83
+ // default → the bundled IDL's embedded `address`.
84
+ //
85
+ // The custom-address check compares by VALUE, not reference. Keying off
86
+ // `idl === vaultIdl` broke for a structurally-identical-but-not-reference-equal
87
+ // copy (second bundle instance, or JSON round-tripped), silently retargeting
88
+ // devnet callers at mainnet. Every copy carries the same build stamp, so it
89
+ // still defers to the network default — but a genuinely custom IDL is honoured.
90
+ // A build stamp is the program's canonical id, which some network maps.
91
+ const isBuildStamp = Object.values(constants_1.programIds).some((ids) => ids[program] === baseIdl?.address);
92
+ const suppliedAddress = typeof baseIdl?.address === 'string' && !isBuildStamp
93
+ ? baseIdl.address
94
+ : undefined;
95
+ const explicitId = programId ?? suppliedAddress;
96
+ if (explicitId) {
97
+ return new anchor_1.Program({ ...baseIdl, address: explicitId }, provider);
98
+ }
99
+ if (network) {
100
+ const networkDefault = (0, constants_1.getDeployedProgramIds)(network)?.[program];
101
+ if (!networkDefault) {
102
+ throw new core_1.UpshiftValidationError('INVALID_INPUT', `${undeployedProgramMessage(program, network)} ` +
103
+ `Pass an explicit \`programId\` (or an IDL carrying the target \`address\`) to target a program on this network.`);
104
+ }
105
+ return new anchor_1.Program({ ...baseIdl, address: networkDefault }, provider);
106
+ }
107
+ return new anchor_1.Program(baseIdl, provider);
108
+ }
109
+ // ============================================================================
110
+ // SOLANA PROVIDERS
111
+ // ============================================================================
112
+ async function testRpcEndpoint({ connection }) {
113
+ try {
114
+ const blockHeight = await connection.getBlockHeight();
115
+ return { success: true, blockHeight };
116
+ }
117
+ catch (error) {
118
+ return { success: false, error };
119
+ }
120
+ }
121
+ // Function to get the best available RPC endpoint
122
+ async function getBestRpcEndpoint({ endpoint, network = constants_1.fallbackNetwork, connection, }) {
123
+ const primaryEndpoint = endpoint;
124
+ const fallbackEndpoint = constants_1.fallbackRpcEndpoints[network];
125
+ // Test primary endpoint first
126
+ const primaryTest = await testRpcEndpoint({ connection });
127
+ if (primaryTest.success) {
128
+ return primaryEndpoint;
129
+ }
130
+ // Fall back to public endpoint
131
+ core_1.Logger.log.warn('getBestRpcEndpoint', '⚠️ Primary RPC endpoint failed, using fallback:', fallbackEndpoint);
132
+ return fallbackEndpoint;
133
+ }
134
+ function getProvider({ connection, publicKey, signTransaction, }) {
135
+ if (!publicKey || !signTransaction) {
136
+ throw new core_1.UpshiftValidationError('INVALID_INPUT', 'Wallet not connected: publicKey and signTransaction are required for write operations');
137
+ }
138
+ // Anchor's own confirmation misreports landed txs as timed out; see confirm.ts.
139
+ return new confirm_1.BlockhashConfirmingProvider(connection, {
140
+ publicKey,
141
+ signTransaction,
142
+ signAllTransactions: async (txs) => {
143
+ // Use Promise.all instead of await in loop
144
+ const signedTransactions = await Promise.all(txs.map(async (tx) => signTransaction(tx)));
145
+ return signedTransactions;
146
+ },
147
+ },
148
+ // Inherited from the connection, not hard-coded: a caller who configured
149
+ // the adapter for 'finalized' must not have writes issued through
150
+ // `getProgram(...).methods…rpc()` confirm at something weaker.
151
+ { commitment: connection.commitment ?? 'finalized' });
152
+ }
153
+ // Read-only provider for data fetching without wallet connection
154
+ function getReadOnlyProvider({ connection }) {
155
+ // Create a dummy wallet object for read-only operations
156
+ const dummyWallet = {
157
+ publicKey: web3_js_1.PublicKey.default, // Use default public key
158
+ signTransaction: async (_tx) => {
159
+ throw new core_1.UpshiftValidationError('INVALID_INPUT', 'Cannot sign transactions with read-only provider');
160
+ },
161
+ signAllTransactions: async (_txs) => {
162
+ throw new core_1.UpshiftValidationError('INVALID_INPUT', 'Cannot sign transactions with read-only provider');
163
+ },
164
+ };
165
+ // See `getProvider` — the connection is the single source of truth for
166
+ // commitment, so reads through this provider match reads made directly.
167
+ return new anchor_1.AnchorProvider(connection, dummyWallet, {
168
+ commitment: connection.commitment ?? 'finalized',
169
+ });
170
+ }
171
+ // ============================================================================
172
+ // SOLANA DERIVATIONS
173
+ // ============================================================================
174
+ function deriveVaultStatePda(vaultProgramId) {
175
+ if (!vaultProgramId)
176
+ throw new core_1.UpshiftValidationError('INVALID_INPUT', 'Vault program ID missing');
177
+ const _vaultProgramId = new web3_js_1.PublicKey(vaultProgramId);
178
+ const [pda] = web3_js_1.PublicKey.findProgramAddressSync([new TextEncoder().encode('VAULT_STATE')], _vaultProgramId);
179
+ return pda;
180
+ }
181
+ function deriveShareMintPda(vaultProgramId) {
182
+ if (!vaultProgramId)
183
+ throw new core_1.UpshiftValidationError('INVALID_INPUT', 'Vault program ID missing');
184
+ const _vaultProgramId = new web3_js_1.PublicKey(vaultProgramId);
185
+ const [pda] = web3_js_1.PublicKey.findProgramAddressSync([new TextEncoder().encode('mint')], _vaultProgramId);
186
+ return pda;
187
+ }
188
+ function deriveVaultTokenAtaPda(vaultProgramId, depositMint, vaultVersion) {
189
+ if (!(vaultProgramId && depositMint))
190
+ throw new core_1.UpshiftValidationError('INVALID_INPUT', 'Vault program ID or deposit mint missing');
191
+ const _vaultProgramId = new web3_js_1.PublicKey(vaultProgramId);
192
+ const seeds = [
193
+ Buffer.from('token_vault'),
194
+ depositMint.toBuffer(),
195
+ ];
196
+ if (vaultVersion !== undefined) {
197
+ if (!Number.isInteger(vaultVersion) ||
198
+ vaultVersion < 0 ||
199
+ vaultVersion > 255) {
200
+ throw new core_1.UpshiftValidationError('INVALID_INPUT', `Invalid vault version ${vaultVersion}: must be an integer between 0 and 255`);
201
+ }
202
+ seeds.push(Buffer.from([vaultVersion]));
203
+ }
204
+ const [pda] = web3_js_1.PublicKey.findProgramAddressSync(seeds, _vaultProgramId);
205
+ return pda;
206
+ }
207
+ // ============================================================================
208
+ // SOLANA VAULTS
209
+ // ============================================================================
210
+ /**
211
+ * How long a decoded vault state stays in the process cache, in milliseconds.
212
+ *
213
+ * `vaultState-*` entries carry live balances (`localAum`, `deployedAum`, fee
214
+ * settings), so they must expire quickly: the shared `CACHE` defaults to 24 h,
215
+ * which froze TVL and share price for the life of the process. 60 s bounds
216
+ * the staleness to one block of polling while still collapsing the burst of
217
+ * reads a single page render makes. Mint addresses (`vaultMints-*`) are
218
+ * immutable and keep the default TTL.
219
+ */
220
+ const VAULT_STATE_CACHE_TTL_MS = 60_000;
221
+ /**
222
+ * Cache a decoded vault state under `cacheKey` with the short
223
+ * {@link VAULT_STATE_CACHE_TTL_MS} TTL. Only called after a successful decode:
224
+ * a failed read is never cached, so the next caller retries the RPC instead
225
+ * of inheriting a `null` state for the TTL.
226
+ */
227
+ function cacheVaultState(cacheKey, value) {
228
+ cache_1.CACHE.set(cacheKey, value, { ttl: VAULT_STATE_CACHE_TTL_MS });
229
+ }
230
+ async function getVaultState({ provider, connection, vaultProgramId, vaultAddress, idl, }) {
231
+ const returnObj = {
232
+ vaultState: null,
233
+ depositMintDecimals: null,
234
+ };
235
+ try {
236
+ const cacheKey = `vaultState-${vaultAddress || vaultProgramId}`;
237
+ const cachedData = await (0, core_1.getSafeCache)(cacheKey);
238
+ if (cachedData)
239
+ return cachedData;
240
+ if (!vaultProgramId) {
241
+ throw new core_1.UpshiftValidationError('INVALID_INPUT', 'Please enter a vault program ID');
242
+ }
243
+ const vaultStatePda = vaultAddress
244
+ ? new web3_js_1.PublicKey(vaultAddress)
245
+ : deriveVaultStatePda(vaultProgramId);
246
+ const _vaultProgramId = new web3_js_1.PublicKey(vaultProgramId);
247
+ const program = getProgram({
248
+ provider,
249
+ idl,
250
+ programId: _vaultProgramId.toBase58(),
251
+ });
252
+ const state = await program.account.vaultState.fetch(vaultStatePda);
253
+ returnObj.vaultState = state;
254
+ if (state.depositMint) {
255
+ try {
256
+ const mintInfo = await connection.getParsedAccountInfo(state.depositMint);
257
+ if (mintInfo.value) {
258
+ const parsedData = mintInfo.value.data;
259
+ returnObj.depositMintDecimals = parsedData.parsed.info.decimals;
260
+ }
261
+ }
262
+ catch (mintError) {
263
+ core_1.Logger.log.error('getVaultState', mintError, {
264
+ message: 'Error fetching deposit mint decimals',
265
+ });
266
+ }
267
+ }
268
+ cacheVaultState(cacheKey, returnObj);
269
+ return returnObj;
270
+ }
271
+ catch (e) {
272
+ const error = e;
273
+ core_1.Logger.log.error('getVaultState', error, {
274
+ message: 'Error reading vault state',
275
+ });
276
+ return returnObj;
277
+ }
278
+ }
279
+ /**
280
+ * Read-only version of `getVaultState` that works without a wallet connection.
281
+ *
282
+ * Makes one `getAccountInfo` for the vault state PDA and decodes the bytes
283
+ * with the program's account coder (no second fetch through
284
+ * `program.account.vaultState.fetch`), plus one `getParsedAccountInfo` for the
285
+ * deposit mint's decimals. Worst case: 2 RPC calls per cache miss; a hit costs
286
+ * none. The decoded state is cached for {@link VAULT_STATE_CACHE_TTL_MS}.
287
+ *
288
+ * Resolves `{ vaultState: null, depositMintDecimals: null }` — and caches
289
+ * nothing — when the account is missing, the RPC fails, or the bytes do not
290
+ * decode. Callers (`getSolanaVault`) treat a `null` state as "on-chain data
291
+ * unavailable" and fall back to backend data.
292
+ *
293
+ * Served from the cache unless `fresh` is set. A fresh read skips the cached
294
+ * value and refreshes it, for callers comparing the vault's AUM with live data
295
+ * such as an operator's current portfolio.
296
+ */
297
+ async function getVaultStateReadOnly({ vaultProgramId, vaultAddress, connection, idl, fresh = false, }) {
298
+ const returnObj = {
299
+ vaultState: null,
300
+ depositMintDecimals: null,
301
+ };
302
+ try {
303
+ const cacheKey = `vaultState-${vaultAddress || vaultProgramId}`;
304
+ const cachedData = fresh ? undefined : await (0, core_1.getSafeCache)(cacheKey);
305
+ if (cachedData)
306
+ return cachedData;
307
+ if (!vaultProgramId) {
308
+ throw new core_1.UpshiftValidationError('INVALID_INPUT', 'Please enter a vault program ID');
309
+ }
310
+ const _vaultProgramId = new web3_js_1.PublicKey(vaultProgramId);
311
+ const vaultStatePda = vaultAddress
312
+ ? new web3_js_1.PublicKey(vaultAddress)
313
+ : deriveVaultStatePda(_vaultProgramId);
314
+ // One account read; the bytes are decoded locally below rather than
315
+ // re-fetched through `program.account.vaultState.fetch`.
316
+ const accountInfo = await connection.getAccountInfo(vaultStatePda);
317
+ if (!accountInfo) {
318
+ core_1.Logger.log.warn('getVaultStateReadOnly', 'Vault state account not found');
319
+ return returnObj;
320
+ }
321
+ // Decode with the program's account coder (same pattern as
322
+ // `readPricingSnapshot`); the read-only provider never signs.
323
+ try {
324
+ const readOnlyProvider = getReadOnlyProvider({ connection });
325
+ const program = getProgram({
326
+ provider: readOnlyProvider,
327
+ idl,
328
+ programId: _vaultProgramId.toBase58(),
329
+ });
330
+ const state = program.coder.accounts.decode('vaultState', accountInfo.data);
331
+ returnObj.vaultState = state;
332
+ if (state.depositMint) {
333
+ try {
334
+ const mintInfo = await connection.getParsedAccountInfo(state.depositMint);
335
+ if (mintInfo.value) {
336
+ const parsedData = mintInfo.value.data;
337
+ returnObj.depositMintDecimals = parsedData.parsed.info.decimals;
338
+ }
339
+ }
340
+ catch (mintError) {
341
+ core_1.Logger.log.error('getVaultStateReadOnly', mintError, {
342
+ message: 'Error fetching deposit mint decimals',
343
+ });
344
+ }
345
+ }
346
+ }
347
+ catch (programError) {
348
+ core_1.Logger.log.error('getVaultStateReadOnly', programError, {
349
+ message: 'Error decoding vault state with read-only provider',
350
+ });
351
+ // Decode failed: the state is unavailable and must not be cached, or
352
+ // every caller for the next TTL would inherit the failure.
353
+ returnObj.vaultState = null;
354
+ return returnObj;
355
+ }
356
+ cacheVaultState(cacheKey, returnObj);
357
+ return returnObj;
358
+ }
359
+ catch (e) {
360
+ const error = e;
361
+ core_1.Logger.log.error('getVaultStateReadOnly', error, {
362
+ message: 'Error reading vault state',
363
+ });
364
+ return returnObj;
365
+ }
366
+ }
367
+ // Fetch deposit and share mint addresses from on-chain vault state (read-only, no wallet required)
368
+ async function getVaultMints({ vaultProgramId, vaultAddress, connection, idl, }) {
369
+ try {
370
+ const cacheKey = `vaultMints-${vaultAddress || vaultProgramId}`;
371
+ const cachedData = await (0, core_1.getSafeCache)(cacheKey);
372
+ if (cachedData)
373
+ return cachedData;
374
+ if (!vaultProgramId) {
375
+ throw new core_1.UpshiftValidationError('INVALID_INPUT', 'Please enter a vault program ID');
376
+ }
377
+ const _vaultProgramId = new web3_js_1.PublicKey(vaultProgramId);
378
+ const vaultStatePda = vaultAddress
379
+ ? new web3_js_1.PublicKey(vaultAddress)
380
+ : deriveVaultStatePda(_vaultProgramId);
381
+ const readOnlyProvider = getReadOnlyProvider({ connection });
382
+ const program = getProgram({
383
+ provider: readOnlyProvider,
384
+ idl,
385
+ programId: _vaultProgramId.toBase58(),
386
+ });
387
+ const state = await program.account.vaultState.fetch(vaultStatePda);
388
+ const returnObj = {
389
+ depositMint: state.depositMint.toString(),
390
+ shareMint: state.shareMint.toString(),
391
+ // Empty arrays yield undefined, falling back to legacy PDA seeds (no version byte)
392
+ vaultVersion: Array.isArray(state.vaultVersion)
393
+ ? state.vaultVersion[0]
394
+ : undefined,
395
+ };
396
+ await (0, core_1.setSafeCache)(cacheKey, returnObj);
397
+ return returnObj;
398
+ }
399
+ catch (e) {
400
+ const error = e;
401
+ const cause = error?.message || String(error);
402
+ core_1.Logger.log.error('getVaultMints', error, {
403
+ message: 'Error reading vault mints',
404
+ vaultProgramId: String(vaultProgramId),
405
+ vaultAddress: vaultAddress ? String(vaultAddress) : undefined,
406
+ });
407
+ throw new core_1.UpshiftSDKError('UNKNOWN', `Failed to read vault mints from on-chain state: ${cause}`, {
408
+ cause: error,
409
+ context: {
410
+ vaultProgramId: String(vaultProgramId),
411
+ vaultAddress: vaultAddress ? String(vaultAddress) : undefined,
412
+ },
413
+ });
414
+ }
415
+ }
416
+ async function getToken({ mintAddress, endpoint, connection, }) {
417
+ // `endpoint` is optional on ISolanaConnectionOptions, so a caller with no
418
+ // Solana RPC configured reaches `fetch(undefined, ...)`, which throws
419
+ // "Cannot read properties of undefined (reading 'toString')" from inside the
420
+ // runtime's fetch wrapper — an unactionable error masquerading as a token
421
+ // failure. Bail before the request instead.
422
+ if (!endpoint) {
423
+ core_1.Logger.log.warn('getToken', 'No Solana RPC endpoint configured', {
424
+ mintAddress: String(mintAddress),
425
+ });
426
+ return null;
427
+ }
428
+ try {
429
+ const cacheKey = `solana_token-${mintAddress}`;
430
+ const cachedData = await (0, core_1.getSafeCache)(cacheKey);
431
+ if (cachedData)
432
+ return cachedData;
433
+ // First, try to get token metadata via Metaplex DAS API
434
+ const response = await fetch(endpoint, {
435
+ method: 'POST',
436
+ headers: {
437
+ 'Content-Type': 'application/json',
438
+ },
439
+ body: JSON.stringify({
440
+ jsonrpc: '2.0',
441
+ id: 'text',
442
+ method: 'getAsset',
443
+ params: { id: mintAddress.toString() },
444
+ }),
445
+ });
446
+ const data = (await response.json()); // @todo: add interface
447
+ // If we got valid token metadata, return it
448
+ if (data.result?.token_info?.decimals !== undefined) {
449
+ return {
450
+ address: data?.result?.id,
451
+ symbol: data.result?.content?.metadata?.symbol || 'N/A',
452
+ decimals: data.result?.token_info?.decimals,
453
+ name: data.result?.content?.metadata?.name || 'Unknown',
454
+ image: data.result?.content.metadata?.image,
455
+ program: data.result?.token_info?.token_program,
456
+ mintAuthority: data.result?.token_info?.mint_authority,
457
+ freezeAuthority: data.result?.token_info?.freeze_authority,
458
+ supply: data.result?.token_info?.supply,
459
+ };
460
+ }
461
+ // If Metaplex metadata didn't work, check if this is a vault program address
462
+ // In that case, we should query the share mint PDA instead
463
+ if (connection) {
464
+ try {
465
+ const vaultProgramId = new web3_js_1.PublicKey(mintAddress);
466
+ // Try to get vault state to see if this is a vault
467
+ const vaultState = await getVaultStateReadOnly({
468
+ vaultProgramId,
469
+ connection,
470
+ idl: constants_1.vaultIdl,
471
+ });
472
+ // If we successfully got vault state, derive the share mint and query that
473
+ if (vaultState.vaultState) {
474
+ const shareMintPda = deriveShareMintPda(vaultProgramId);
475
+ // Get share mint metadata from blockchain
476
+ const shareMintInfo = await connection.getParsedAccountInfo(shareMintPda);
477
+ if (shareMintInfo.value) {
478
+ const parsedData = shareMintInfo.value.data;
479
+ // Try to get Metaplex metadata for the share mint
480
+ const shareMintMetadata = await fetch(endpoint, {
481
+ method: 'POST',
482
+ headers: {
483
+ 'Content-Type': 'application/json',
484
+ },
485
+ body: JSON.stringify({
486
+ jsonrpc: '2.0',
487
+ id: 'text',
488
+ method: 'getAsset',
489
+ params: { id: shareMintPda.toString() },
490
+ }),
491
+ });
492
+ const shareMintData = (await shareMintMetadata.json());
493
+ const returnObj = {
494
+ address: mintAddress.toString(), // Return original vault address
495
+ symbol: shareMintData.result?.content?.metadata?.symbol || 'N/A',
496
+ decimals: parsedData.parsed.info.decimals,
497
+ name: shareMintData.result?.content?.metadata?.name ||
498
+ 'Vault Share Token',
499
+ image: shareMintData.result?.content?.metadata?.image,
500
+ program: shareMintData.result?.token_info?.token_program,
501
+ mintAuthority: shareMintData.result?.token_info?.mint_authority,
502
+ freezeAuthority: shareMintData.result?.token_info?.freeze_authority,
503
+ supply: parsedData.parsed.info.supply,
504
+ shareMintAddress: shareMintPda.toString(), // Include share mint address
505
+ };
506
+ await (0, core_1.setSafeCache)(cacheKey, returnObj);
507
+ return returnObj;
508
+ }
509
+ }
510
+ }
511
+ catch (vaultError) {
512
+ // Not a vault or error checking vault state, continue to return null
513
+ core_1.Logger.log.info('getToken', 'Not a vault program or error querying vault:', vaultError);
514
+ }
515
+ }
516
+ // If all attempts failed, return null
517
+ return null;
518
+ }
519
+ catch (error) {
520
+ // Callers fall back to backend metadata when this returns null, so a failed
521
+ // lookup is degraded-but-handled — warn, don't raise it as an error.
522
+ core_1.Logger.log.warn('getToken', 'Error fetching token metadata', {
523
+ mintAddress: String(mintAddress),
524
+ error,
525
+ });
526
+ return null;
527
+ }
528
+ }
529
+ // Helper function to get just the token symbol
530
+ async function getTokenSymbol({ endpoint, mintAddress, }) {
531
+ try {
532
+ const tokenMetadata = await getToken({ endpoint, mintAddress });
533
+ if (tokenMetadata) {
534
+ return tokenMetadata.symbol;
535
+ }
536
+ return null;
537
+ }
538
+ catch (error) {
539
+ core_1.Logger.log.error('getTokenSymbol', error, {
540
+ message: 'Error fetching token symbol',
541
+ });
542
+ return null;
543
+ }
544
+ }
545
+ /**
546
+ * A wallet's token account of record for one mint: the account holding the
547
+ * largest balance.
548
+ *
549
+ * **This is the single selection rule for the whole Solana adapter.** Reads
550
+ * (balances shown in a UI) and writes (the account a transfer actually names)
551
+ * must agree on which account represents the user, or the two describe
552
+ * different money: a balance read from account A while a deposit mints into
553
+ * account B looks, to the user, like a successful transaction that never
554
+ * arrived. Every reader in this file and both vault handlers call this, so the
555
+ * rule cannot drift.
556
+ *
557
+ * Largest-balance rather than "the first account the RPC returned":
558
+ * `getParsedTokenAccountsByOwner` guarantees no ordering, so taking `[0]` can
559
+ * select an empty leftover while the user's funds sit in a sibling account —
560
+ * which fails on-chain as an insufficient-funds revert *after* they sign.
561
+ *
562
+ * **Spendable accounts win over frozen ones**, regardless of balance: a token
563
+ * issuer can freeze an account, and neither a transfer out of nor a transfer
564
+ * into a frozen account can succeed. Picking the richest account outright would
565
+ * hand a frozen one to the program and revert with SPL `0x11` after the user
566
+ * signs, while a perfectly usable sibling sat next to it. When *every* account
567
+ * is frozen the richest frozen one is still returned, flagged — a reader should
568
+ * show that balance, because the user does own it, and a writer should refuse
569
+ * before asking for a signature.
570
+ *
571
+ * Internal to the adapter: exported for `vault.actions.ts`, deliberately not
572
+ * re-exported on `SolanaUtils`. It takes a raw RPC response shape, which is not
573
+ * a contract worth freezing on the public surface.
574
+ *
575
+ * @param accounts - The `.value` array from `getParsedTokenAccountsByOwner`.
576
+ * @returns The selected account with its raw balance, decimals, the RPC's own
577
+ * `uiAmount`, and whether it is frozen — or `undefined` when the wallet owns
578
+ * no account for the mint.
579
+ * @throws UpshiftSDKError when an account's balance cannot be read. An
580
+ * unreadable balance is *unknown*, not zero — scoring it zero would silently
581
+ * demote a funded account below a dust one and reinstate the `[0]` behaviour
582
+ * this function exists to prevent.
583
+ */
584
+ function selectRichestTokenAccount(accounts) {
585
+ const parsed = accounts.map((entry) => {
586
+ const info = entry.account.data?.parsed?.info;
587
+ const tokenAmount = info?.tokenAmount;
588
+ const raw = tokenAmount?.amount;
589
+ // A u64 string is the only shape the RPC promises here. Anything else
590
+ // (a base64 `data` the node could not jsonParse, a reshaping proxy) means
591
+ // we do not know this balance.
592
+ if (typeof raw !== 'string' || !/^\d+$/.test(raw)) {
593
+ throw new core_1.UpshiftSDKError('UNKNOWN', `Could not read the balance of token account ${entry.pubkey.toBase58()}. ` +
594
+ 'The RPC returned an unrecognized response; please retry or switch RPC.', {
595
+ context: {
596
+ account: entry.pubkey.toBase58(),
597
+ rawAmount: String(raw),
598
+ },
599
+ });
600
+ }
601
+ return {
602
+ pubkey: entry.pubkey,
603
+ amount: BigInt(raw),
604
+ decimals: typeof tokenAmount?.decimals === 'number' ? tokenAmount.decimals : null,
605
+ // Passed through from the RPC rather than recomputed from `amount`, so
606
+ // the lossy float these legacy readers return is not made lossier.
607
+ uiAmount: typeof tokenAmount?.uiAmount === 'number' ? tokenAmount.uiAmount : null,
608
+ frozen: info?.state === 'frozen',
609
+ };
610
+ });
611
+ const richest = (candidates) => candidates.reduce((best, candidate) => {
612
+ if (!best)
613
+ return candidate;
614
+ if (candidate.amount !== best.amount)
615
+ return candidate.amount > best.amount ? candidate : best;
616
+ // Equal balances: break the tie on the address. Falling back to "whichever
617
+ // the RPC listed first" would leave exactly the ordering dependence this
618
+ // function exists to remove — harmless while the balances match, but it
619
+ // means two calls can name different accounts for the same wallet.
620
+ return candidate.pubkey.toBase58() < best.pubkey.toBase58()
621
+ ? candidate
622
+ : best;
623
+ }, undefined);
624
+ return richest(parsed.filter((a) => !a.frozen)) ?? richest(parsed);
625
+ }
626
+ async function fetchUserTokenBalance({ connection, publicKey, depositMint, }) {
627
+ if (!publicKey || !depositMint)
628
+ return '0';
629
+ try {
630
+ const _publicKey = new web3_js_1.PublicKey(publicKey);
631
+ const _depositMint = new web3_js_1.PublicKey(depositMint);
632
+ const tokenAccounts = await connection.getParsedTokenAccountsByOwner(_publicKey, {
633
+ mint: _depositMint,
634
+ });
635
+ // Same rule the write path uses — see `selectRichestTokenAccount`.
636
+ const richest = selectRichestTokenAccount(tokenAccounts.value);
637
+ return richest?.uiAmount?.toString() || '0';
638
+ }
639
+ catch (e) {
640
+ const error = e;
641
+ core_1.Logger.log.error('fetchUserTokenBalance', error, {
642
+ message: 'Error fetching user token balance',
643
+ });
644
+ return '0';
645
+ }
646
+ }
647
+ async function fetchUserShareBalance({ connection, publicKey, shareMint, }) {
648
+ if (!publicKey || !shareMint)
649
+ return 0;
650
+ try {
651
+ const _publicKey = new web3_js_1.PublicKey(publicKey);
652
+ const _shareMint = new web3_js_1.PublicKey(shareMint);
653
+ const shareAccounts = await connection.getParsedTokenAccountsByOwner(_publicKey, {
654
+ mint: _shareMint,
655
+ });
656
+ // Same rule the write path uses — see `selectRichestTokenAccount`.
657
+ const richest = selectRichestTokenAccount(shareAccounts.value);
658
+ return richest?.uiAmount ?? 0;
659
+ }
660
+ catch (e) {
661
+ const error = e;
662
+ core_1.Logger.log.error('fetchUserShareBalance', error, {
663
+ message: 'Error fetching user share balance',
664
+ });
665
+ return 0;
666
+ }
667
+ }
668
+ /**
669
+ * Same on-chain lookup as `fetchUserShareBalance`, but returns the raw u64
670
+ * `amount` string and the mint's `decimals` — or `null` when the scale can't
671
+ * be determined (see Return shape) — instead of the floating-point `uiAmount`.
672
+ * Callers that feed the result into BigInt math (positions, redemptions,
673
+ * allowances) must use this — `uiAmount` is lossy and silently encodes with
674
+ * the wrong scale when passed back through `toNormalizedBn` without an
675
+ * explicit decimals argument.
676
+ *
677
+ * Return shape:
678
+ * `{ amount: '<u64>', decimals: number }` — token account exists.
679
+ * `{ amount: '0', decimals: null }` — no token account, missing
680
+ * tokenAmount in the parsed response, missing args, or the RPC threw.
681
+ *
682
+ * `decimals === null` is the "scale unknown" signal — callers that need a
683
+ * normalized `INormalizedNumber` must substitute a known decimals value
684
+ * (typically the deposit mint's decimals from backend metadata) before
685
+ * normalizing. Never throws.
686
+ *
687
+ * RPC cost: 1 × `getParsedTokenAccountsByOwner`. Independent of how many
688
+ * other accounts the wallet owns (filter is mint-scoped).
689
+ */
690
+ async function fetchUserShareBalanceRaw({ connection, publicKey, shareMint, }) {
691
+ if (!publicKey || !shareMint)
692
+ return { amount: '0', decimals: null };
693
+ try {
694
+ const _publicKey = new web3_js_1.PublicKey(publicKey);
695
+ const _shareMint = new web3_js_1.PublicKey(shareMint);
696
+ const shareAccounts = await connection.getParsedTokenAccountsByOwner(_publicKey, {
697
+ mint: _shareMint,
698
+ });
699
+ // Same rule the write path uses — see `selectRichestTokenAccount`.
700
+ const richest = selectRichestTokenAccount(shareAccounts?.value ?? []);
701
+ if (!richest)
702
+ return { amount: '0', decimals: null };
703
+ return {
704
+ amount: richest.amount.toString(),
705
+ decimals: richest.decimals,
706
+ };
707
+ }
708
+ catch (e) {
709
+ const error = e;
710
+ core_1.Logger.log.error('fetchUserShareBalanceRaw', error, {
711
+ message: 'Error fetching raw user share balance',
712
+ });
713
+ return { amount: '0', decimals: null };
714
+ }
715
+ }
716
+ /**
717
+ * Resolve the on-chain program ID for a Solana vault.
718
+ * Prefers the explicit `program_id` from metadata; falls back to the vault address
719
+ * (for legacy vaults where address == program ID).
720
+ */
721
+ function resolveProgramId(vaultAddress, solanaMetadata) {
722
+ return solanaMetadata?.program_id || vaultAddress;
723
+ }
724
+ // String-arithmetic UI→raw conversion. Truncates past `decimals` like
725
+ // ethers.parseUnits; safe past Number.MAX_SAFE_INTEGER.
726
+ /** @internal */
727
+ function uiAmountToRawBn(uiAmount, decimals) {
728
+ if (!Number.isFinite(uiAmount)) {
729
+ throw new core_1.UpshiftValidationError('INVALID_INPUT', `uiAmountToRawBn: amount must be finite, got ${uiAmount}`);
730
+ }
731
+ if (uiAmount < 0) {
732
+ throw new core_1.UpshiftValidationError('INVALID_INPUT', `uiAmountToRawBn: amount must be non-negative, got ${uiAmount}`);
733
+ }
734
+ if (!Number.isInteger(decimals) || decimals < 0) {
735
+ throw new core_1.UpshiftValidationError('INVALID_INPUT', `uiAmountToRawBn: decimals must be a non-negative integer, got ${decimals}`);
736
+ }
737
+ // Build the fixed-decimal string manually — `.toFixed(decimals)` rounds
738
+ // the last digit, but parseUnits semantics require truncation.
739
+ const uiStr = uiAmount.toString();
740
+ const expansion = uiStr.includes('e') || uiStr.includes('E')
741
+ ? uiAmount.toFixed(Math.max(decimals, 20)).replace(/\.?0+$/, '')
742
+ : uiStr;
743
+ const [whole, fraction = ''] = expansion.split('.');
744
+ const truncated = fraction.slice(0, decimals);
745
+ const paddedFraction = truncated.padEnd(decimals, '0');
746
+ const raw = (whole + paddedFraction).replace(/^0+/, '') || '0';
747
+ return new anchor_1.BN(raw);
748
+ }
749
+ exports.SolanaUtils = {
750
+ getExplorerLink,
751
+ isSolanaAddress: chain_address_1.isSolanaAddress,
752
+ isSolana,
753
+ getProgram,
754
+ getProvider,
755
+ getReadOnlyProvider,
756
+ deriveShareMintPda,
757
+ deriveVaultStatePda,
758
+ deriveVaultTokenAtaPda,
759
+ getVaultState,
760
+ getVaultStateReadOnly,
761
+ getToken,
762
+ getTokenSymbol,
763
+ fetchUserTokenBalance,
764
+ fetchUserShareBalance,
765
+ fetchUserShareBalanceRaw,
766
+ getBestRpcEndpoint,
767
+ fallbackDecimals: constants_1.fallbackDecimals,
768
+ fallbackNetwork: constants_1.fallbackNetwork,
769
+ programIds: constants_1.programIds,
770
+ getVaultMints,
771
+ resolveProgramId,
772
+ };
773
+ //# sourceMappingURL=utils.js.map