@augustdigital/sdk 8.3.2 → 8.6.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 (213) hide show
  1. package/README.md +207 -117
  2. package/lib/abis/ERC20_Bytes32.d.ts +4 -0
  3. package/lib/abis/ERC20_Bytes32.js +4 -0
  4. package/lib/abis/ERC4626.d.ts +1 -0
  5. package/lib/abis/ERC4626.js +1 -0
  6. package/lib/abis/ERC721.d.ts +1 -0
  7. package/lib/abis/ERC721.js +1 -0
  8. package/lib/abis/FeeOracle.js +1 -0
  9. package/lib/abis/LendingPool.js +1 -0
  10. package/lib/abis/LendingPoolV2.js +1 -0
  11. package/lib/abis/Multicall3.js +3 -0
  12. package/lib/abis/OFT.d.ts +20 -0
  13. package/lib/abis/OFT.js +20 -0
  14. package/lib/abis/SmartAccount.d.ts +1 -0
  15. package/lib/abis/SmartAccount.js +3 -0
  16. package/lib/abis/SwapRouter.d.ts +1 -0
  17. package/lib/abis/SwapRouter.js +1 -0
  18. package/lib/abis/UniversalSignatureValidator.js +3 -0
  19. package/lib/abis/index.d.ts +5 -0
  20. package/lib/abis/index.js +5 -0
  21. package/lib/adapters/evm/getters.d.ts +17 -2
  22. package/lib/adapters/evm/getters.js +35 -3
  23. package/lib/adapters/evm/index.d.ts +266 -4
  24. package/lib/adapters/evm/index.js +270 -1
  25. package/lib/adapters/evm/utils.d.ts +6 -0
  26. package/lib/adapters/evm/utils.js +7 -0
  27. package/lib/adapters/solana/constants.d.ts +1 -1
  28. package/lib/adapters/solana/constants.js +4 -1
  29. package/lib/adapters/solana/getters.d.ts +9 -1
  30. package/lib/adapters/solana/getters.js +21 -0
  31. package/lib/adapters/solana/idl/vault-idl.js +9 -0
  32. package/lib/adapters/solana/index.d.ts +59 -4
  33. package/lib/adapters/solana/index.js +61 -0
  34. package/lib/adapters/solana/types.d.ts +1 -1
  35. package/lib/adapters/solana/utils.d.ts +31 -3
  36. package/lib/adapters/solana/utils.js +79 -4
  37. package/lib/adapters/solana/vault.actions.d.ts +23 -4
  38. package/lib/adapters/solana/vault.actions.js +47 -3
  39. package/lib/adapters/stellar/actions.d.ts +26 -1
  40. package/lib/adapters/stellar/actions.js +33 -0
  41. package/lib/adapters/stellar/constants.d.ts +26 -0
  42. package/lib/adapters/stellar/constants.js +29 -0
  43. package/lib/adapters/stellar/getters.d.ts +56 -0
  44. package/lib/adapters/stellar/getters.js +81 -0
  45. package/lib/adapters/stellar/index.d.ts +70 -0
  46. package/lib/adapters/stellar/index.js +71 -0
  47. package/lib/adapters/stellar/soroban.d.ts +21 -1
  48. package/lib/adapters/stellar/soroban.js +47 -1
  49. package/lib/adapters/stellar/submit.d.ts +29 -0
  50. package/lib/adapters/stellar/submit.js +90 -5
  51. package/lib/adapters/stellar/types.d.ts +27 -0
  52. package/lib/adapters/stellar/types.js +3 -0
  53. package/lib/adapters/stellar/utils.d.ts +10 -0
  54. package/lib/adapters/stellar/utils.js +10 -0
  55. package/lib/adapters/sui/getters.d.ts +7 -1
  56. package/lib/adapters/sui/getters.js +6 -0
  57. package/lib/adapters/sui/index.d.ts +16 -1
  58. package/lib/adapters/sui/index.js +17 -0
  59. package/lib/adapters/sui/transformer.d.ts +8 -2
  60. package/lib/adapters/sui/transformer.js +7 -0
  61. package/lib/adapters/sui/types.d.ts +1 -1
  62. package/lib/adapters/sui/utils.d.ts +6 -0
  63. package/lib/adapters/sui/utils.js +6 -0
  64. package/lib/core/analytics/chain-name.d.ts +8 -0
  65. package/lib/core/analytics/chain-name.js +8 -0
  66. package/lib/core/analytics/constants.d.ts +4 -0
  67. package/lib/core/analytics/constants.js +4 -0
  68. package/lib/core/analytics/env.d.ts +25 -0
  69. package/lib/core/analytics/env.js +26 -0
  70. package/lib/core/analytics/index.d.ts +26 -0
  71. package/lib/core/analytics/index.js +35 -0
  72. package/lib/core/analytics/instrumentation.d.ts +26 -0
  73. package/lib/core/analytics/instrumentation.js +66 -2
  74. package/lib/core/analytics/method-taxonomy.d.ts +16 -0
  75. package/lib/core/analytics/method-taxonomy.js +18 -0
  76. package/lib/core/analytics/metrics.d.ts +23 -0
  77. package/lib/core/analytics/metrics.js +40 -0
  78. package/lib/core/analytics/sanitize.d.ts +38 -0
  79. package/lib/core/analytics/sanitize.js +46 -0
  80. package/lib/core/analytics/sentry-runtime.d.ts +11 -0
  81. package/lib/core/analytics/sentry-runtime.js +20 -1
  82. package/lib/core/analytics/sentry.d.ts +47 -2
  83. package/lib/core/analytics/sentry.js +115 -2
  84. package/lib/core/analytics/types.d.ts +28 -1
  85. package/lib/core/analytics/user-identity.d.ts +36 -2
  86. package/lib/core/analytics/user-identity.js +43 -1
  87. package/lib/core/analytics/version.d.ts +6 -1
  88. package/lib/core/analytics/version.js +6 -1
  89. package/lib/core/auth/verify.js +5 -0
  90. package/lib/core/base.class.d.ts +78 -3
  91. package/lib/core/base.class.js +66 -4
  92. package/lib/core/cache.d.ts +5 -0
  93. package/lib/core/cache.js +6 -0
  94. package/lib/core/constants/adapters.d.ts +16 -1
  95. package/lib/core/constants/adapters.js +28 -8
  96. package/lib/core/constants/core.d.ts +14 -1
  97. package/lib/core/constants/core.js +18 -0
  98. package/lib/core/constants/swap-router.d.ts +83 -1
  99. package/lib/core/constants/swap-router.js +91 -1
  100. package/lib/core/constants/vaults.d.ts +57 -1
  101. package/lib/core/constants/vaults.js +66 -1
  102. package/lib/core/constants/web3.d.ts +4 -1
  103. package/lib/core/constants/web3.js +15 -5
  104. package/lib/core/errors/index.d.ts +38 -2
  105. package/lib/core/errors/index.js +38 -0
  106. package/lib/core/fetcher.d.ts +136 -2
  107. package/lib/core/fetcher.js +229 -25
  108. package/lib/core/helpers/adapters.d.ts +10 -1
  109. package/lib/core/helpers/adapters.js +11 -0
  110. package/lib/core/helpers/chain-address.d.ts +10 -0
  111. package/lib/core/helpers/chain-address.js +11 -0
  112. package/lib/core/helpers/core.d.ts +49 -4
  113. package/lib/core/helpers/core.js +74 -7
  114. package/lib/core/helpers/explorer-link.d.ts +15 -1
  115. package/lib/core/helpers/explorer-link.js +14 -0
  116. package/lib/core/helpers/signer.d.ts +27 -1
  117. package/lib/core/helpers/signer.js +39 -0
  118. package/lib/core/helpers/swap-router.d.ts +33 -1
  119. package/lib/core/helpers/swap-router.js +32 -0
  120. package/lib/core/helpers/vault-version.d.ts +2 -1
  121. package/lib/core/helpers/vault-version.js +2 -0
  122. package/lib/core/helpers/vaults.d.ts +9 -1
  123. package/lib/core/helpers/vaults.js +22 -8
  124. package/lib/core/helpers/web3.d.ts +154 -2
  125. package/lib/core/helpers/web3.js +192 -15
  126. package/lib/core/logger/index.d.ts +55 -0
  127. package/lib/core/logger/index.js +19 -0
  128. package/lib/core/logger/slack.d.ts +3 -0
  129. package/lib/core/logger/slack.js +3 -0
  130. package/lib/core/vault-metadata.d.ts +7 -1
  131. package/lib/core/vault-metadata.js +6 -0
  132. package/lib/core/version-check.d.ts +52 -0
  133. package/lib/core/version-check.js +82 -1
  134. package/lib/evm/methods/crossChainVault.d.ts +90 -0
  135. package/lib/evm/methods/crossChainVault.js +187 -2
  136. package/lib/evm/methods/crossChainVaultRegistry.d.ts +93 -0
  137. package/lib/evm/methods/crossChainVaultRegistry.js +240 -0
  138. package/lib/evm/methods/index.d.ts +1 -0
  139. package/lib/evm/methods/index.js +1 -0
  140. package/lib/evm/types/crossChain.d.ts +202 -0
  141. package/lib/evm/types/crossChain.js +12 -1
  142. package/lib/index.d.ts +16 -0
  143. package/lib/index.js +19 -0
  144. package/lib/main.d.ts +289 -6
  145. package/lib/main.js +312 -0
  146. package/lib/modules/api/index.d.ts +1 -0
  147. package/lib/modules/api/index.js +6 -0
  148. package/lib/modules/api/main.d.ts +52 -0
  149. package/lib/modules/api/main.js +130 -0
  150. package/lib/modules/sub-accounts/fetcher.d.ts +17 -2
  151. package/lib/modules/sub-accounts/fetcher.js +15 -0
  152. package/lib/modules/sub-accounts/main.d.ts +35 -2
  153. package/lib/modules/sub-accounts/main.js +39 -1
  154. package/lib/modules/sub-accounts/utils.d.ts +4 -1
  155. package/lib/modules/sub-accounts/utils.js +3 -0
  156. package/lib/modules/vaults/adapter.helpers.d.ts +21 -3
  157. package/lib/modules/vaults/adapter.helpers.js +34 -0
  158. package/lib/modules/vaults/fetcher.d.ts +45 -0
  159. package/lib/modules/vaults/fetcher.js +91 -4
  160. package/lib/modules/vaults/getters.d.ts +295 -0
  161. package/lib/modules/vaults/getters.js +567 -26
  162. package/lib/modules/vaults/index.d.ts +12 -0
  163. package/lib/modules/vaults/index.js +12 -0
  164. package/lib/modules/vaults/main.d.ts +292 -4
  165. package/lib/modules/vaults/main.js +382 -8
  166. package/lib/modules/vaults/read.actions.d.ts +170 -2
  167. package/lib/modules/vaults/read.actions.js +143 -0
  168. package/lib/modules/vaults/types.d.ts +34 -0
  169. package/lib/modules/vaults/utils/call-data-decoder.d.ts +48 -1
  170. package/lib/modules/vaults/utils/call-data-decoder.js +56 -0
  171. package/lib/modules/vaults/utils/date-utils.d.ts +39 -0
  172. package/lib/modules/vaults/utils/date-utils.js +47 -1
  173. package/lib/modules/vaults/utils.d.ts +85 -0
  174. package/lib/modules/vaults/utils.js +139 -7
  175. package/lib/modules/vaults/write.actions.d.ts +363 -3
  176. package/lib/modules/vaults/write.actions.js +399 -3
  177. package/lib/polyfills.js +4 -2
  178. package/lib/sdk.d.ts +23847 -0
  179. package/lib/services/coingecko/fetcher.d.ts +15 -1
  180. package/lib/services/coingecko/fetcher.js +30 -9
  181. package/lib/services/debank/fetcher.d.ts +15 -1
  182. package/lib/services/debank/fetcher.js +12 -0
  183. package/lib/services/debank/utils.d.ts +1 -1
  184. package/lib/services/debank/utils.js +18 -1
  185. package/lib/services/layerzero/deposits.d.ts +12 -1
  186. package/lib/services/layerzero/deposits.js +34 -11
  187. package/lib/services/layerzero/redeems.d.ts +11 -1
  188. package/lib/services/layerzero/redeems.js +13 -0
  189. package/lib/services/layerzero/utils.d.ts +8 -0
  190. package/lib/services/layerzero/utils.js +11 -0
  191. package/lib/services/octavfi/fetcher.d.ts +8 -1
  192. package/lib/services/octavfi/fetcher.js +25 -0
  193. package/lib/services/octavfi/types.d.ts +1 -1
  194. package/lib/services/octavfi/utils.d.ts +14 -2
  195. package/lib/services/octavfi/utils.js +44 -10
  196. package/lib/services/subgraph/fetcher.js +4 -2
  197. package/lib/services/subgraph/vaults.d.ts +12 -0
  198. package/lib/services/subgraph/vaults.js +119 -2
  199. package/lib/services/swap-quotes/index.d.ts +80 -0
  200. package/lib/services/swap-quotes/index.js +27 -1
  201. package/lib/services/swap-quotes/paraswap.d.ts +25 -0
  202. package/lib/services/swap-quotes/paraswap.js +22 -0
  203. package/lib/types/pools.d.ts +5 -2
  204. package/lib/types/staking.d.ts +1 -1
  205. package/lib/types/sub-accounts.d.ts +1 -1
  206. package/lib/types/subgraph.d.ts +10 -1
  207. package/lib/types/typed-contract.d.ts +64 -0
  208. package/lib/types/vaults.d.ts +163 -2
  209. package/lib/types/vaults.js +10 -0
  210. package/lib/types/web3.d.ts +9 -1
  211. package/lib/types/web3.js +1 -0
  212. package/lib/types/webserver.d.ts +47 -2
  213. package/package.json +6 -5
@@ -34,6 +34,11 @@ var __importStar = (this && this.__importStar) || (function () {
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.Solana = void 0;
37
+ /**
38
+ * Solana Adapter for August SDK
39
+ *
40
+ * @module SolanaAdapter
41
+ */
37
42
  const SolanaConstants = __importStar(require("./constants"));
38
43
  const SolanaGetters = __importStar(require("./getters"));
39
44
  const SolanaActions = __importStar(require("./vault.actions"));
@@ -47,7 +52,21 @@ exports.Solana = {
47
52
  actions: SolanaActions,
48
53
  getters: SolanaGetters,
49
54
  };
55
+ /**
56
+ * Solana Adapter for August SDK
57
+ *
58
+ * @example
59
+ * To access the Solana adapter instance
60
+ * ```
61
+ * const sdk = new AugustSDK()
62
+ * sdk.solana.getVaultState()
63
+ * ```
64
+ */
50
65
  class SolanaAdapter {
66
+ _endpoint;
67
+ _network;
68
+ _connection;
69
+ _provider;
51
70
  constructor(endpoint, network = utils_1.SolanaUtils.fallbackNetwork) {
52
71
  this._endpoint = endpoint;
53
72
  this._network = network;
@@ -58,6 +77,7 @@ class SolanaAdapter {
58
77
  connection,
59
78
  });
60
79
  }
80
+ // Getters and setters for private properties
61
81
  get endpoint() {
62
82
  return this._endpoint;
63
83
  }
@@ -70,6 +90,7 @@ class SolanaAdapter {
70
90
  get provider() {
71
91
  return this._provider;
72
92
  }
93
+ // Method to set connection with wallet for authenticated operations
73
94
  setWalletProvider(_publicKey, signTransaction) {
74
95
  if (_publicKey && signTransaction) {
75
96
  const publicKey = typeof _publicKey === 'string' ? new web3_js_1.PublicKey(_publicKey) : _publicKey;
@@ -143,6 +164,38 @@ class SolanaAdapter {
143
164
  shareMint,
144
165
  });
145
166
  }
167
+ /**
168
+ * BigInt-safe variant of {@link fetchUserShareBalance}. Returns the raw u64
169
+ * `amount` (as a base-units string) plus the mint's `decimals` (or `null`
170
+ * when the scale can't be determined — see Returns), so the caller can
171
+ * produce a correct `INormalizedNumber` without losing precision.
172
+ *
173
+ * Prefer this anywhere the result feeds BigInt math — positions, max-
174
+ * actions, redemption sizing, allowance checks. `fetchUserShareBalance`
175
+ * returns a JS-number `uiAmount` which silently encodes against 18 decimals
176
+ * when passed through `toNormalizedBn(value)` without an explicit decimals
177
+ * argument; that's exactly how the jitoSOL "missing position" regression
178
+ * manifested.
179
+ *
180
+ * RPC cost: 1 `getParsedTokenAccountsByOwner` call. Worst case ~150ms on a
181
+ * healthy mainnet endpoint.
182
+ *
183
+ * @param publicKey Wallet owner (PublicKey or base58 string).
184
+ * @param shareMint The vault's share-token mint (PublicKey or base58).
185
+ * @returns
186
+ * `{ amount, decimals }`. Three observable shapes:
187
+ * - `{ amount: '<u64>', decimals: <number> }` — token account exists.
188
+ * - `{ amount: '0', decimals: null }` — no token account for this mint
189
+ * under this wallet, OR `tokenAmount` was missing from the response,
190
+ * OR `publicKey`/`shareMint` was not supplied. Distinguishable from a
191
+ * genuine zero-balance account (`decimals` would be set there).
192
+ * - `{ amount: '0', decimals: null }` — RPC threw (error is logged).
193
+ *
194
+ * `decimals === null` means "we could not determine the scale" — callers
195
+ * that need an `INormalizedNumber` must fall back to a known decimals
196
+ * value (typically the deposit mint's decimals from backend metadata)
197
+ * before normalizing. Never throws.
198
+ */
146
199
  async fetchUserShareBalanceRaw(publicKey, shareMint) {
147
200
  return await utils_1.SolanaUtils.fetchUserShareBalanceRaw({
148
201
  network: this._network,
@@ -151,6 +204,10 @@ class SolanaAdapter {
151
204
  shareMint,
152
205
  });
153
206
  }
207
+ /**
208
+ * Deposit funds into a Solana August vault.
209
+ * @param depositAmount `bigint` (raw on-chain units) or `number` (UI amount).
210
+ */
154
211
  async vaultDeposit(vaultProgramId, idl, publicKey, depositAmount, sendTransaction, vaultAddress) {
155
212
  return await (0, vault_actions_1.handleSolanaDeposit)({
156
213
  network: this._network,
@@ -164,6 +221,10 @@ class SolanaAdapter {
164
221
  sendTransaction,
165
222
  });
166
223
  }
224
+ /**
225
+ * Redeem vault shares from a Solana August vault.
226
+ * @param redeemShares `bigint` (raw share units) or `number` (UI amount).
227
+ */
167
228
  async vaultRedeem(vaultProgramId, idl, publicKey, redeemShares, sendTransaction, vaultAddress) {
168
229
  return await (0, vault_actions_1.handleSolanaRedeem)({
169
230
  network: this._network,
@@ -1,4 +1,4 @@
1
- import { AnchorProvider } from '@coral-xyz/anchor';
1
+ import type { AnchorProvider } from '@coral-xyz/anchor';
2
2
  import type { Connection, PublicKey } from '@solana/web3.js';
3
3
  export type ISolanaRpcEndpoint = `https://${string}`;
4
4
  export type ISolanaNetwork = 'devnet' | 'mainnet-beta' | 'testnet' | 'localnet';
@@ -1,6 +1,6 @@
1
- import { AnchorProvider, BN, Program, web3 } from '@coral-xyz/anchor';
2
- import { PublicKey, Transaction } from '@solana/web3.js';
3
- import { ISolanaConnectionOptions, ISolanaVaultState } from './types';
1
+ import { AnchorProvider, BN, Program, type web3 } from '@coral-xyz/anchor';
2
+ import { PublicKey, type Transaction } from '@solana/web3.js';
3
+ import type { ISolanaConnectionOptions, ISolanaVaultState } from './types';
4
4
  declare function getExplorerLink({ signature, type, network, }: {
5
5
  signature: string;
6
6
  type: 'tx' | 'address' | 'token';
@@ -66,6 +66,28 @@ declare function fetchUserShareBalance({ connection, publicKey, shareMint, }: {
66
66
  publicKey: PublicKey | string;
67
67
  shareMint?: PublicKey | string;
68
68
  } & ISolanaConnectionOptions): Promise<any>;
69
+ /**
70
+ * Same on-chain lookup as `fetchUserShareBalance`, but returns the raw u64
71
+ * `amount` string and the mint's `decimals` — or `null` when the scale can't
72
+ * be determined (see Return shape) — instead of the floating-point `uiAmount`.
73
+ * Callers that feed the result into BigInt math (positions, redemptions,
74
+ * allowances) must use this — `uiAmount` is lossy and silently encodes with
75
+ * the wrong scale when passed back through `toNormalizedBn` without an
76
+ * explicit decimals argument.
77
+ *
78
+ * Return shape:
79
+ * `{ amount: '<u64>', decimals: number }` — token account exists.
80
+ * `{ amount: '0', decimals: null }` — no token account, missing
81
+ * tokenAmount in the parsed response, missing args, or the RPC threw.
82
+ *
83
+ * `decimals === null` is the "scale unknown" signal — callers that need a
84
+ * normalized `INormalizedNumber` must substitute a known decimals value
85
+ * (typically the deposit mint's decimals from backend metadata) before
86
+ * normalizing. Never throws.
87
+ *
88
+ * RPC cost: 1 × `getParsedTokenAccountsByOwner`. Independent of how many
89
+ * other accounts the wallet owns (filter is mint-scoped).
90
+ */
69
91
  declare function fetchUserShareBalanceRaw({ connection, publicKey, shareMint, }: {
70
92
  publicKey: PublicKey | string;
71
93
  shareMint?: PublicKey | string;
@@ -73,9 +95,15 @@ declare function fetchUserShareBalanceRaw({ connection, publicKey, shareMint, }:
73
95
  amount: string;
74
96
  decimals: number | null;
75
97
  }>;
98
+ /**
99
+ * Resolve the on-chain program ID for a Solana vault.
100
+ * Prefers the explicit `program_id` from metadata; falls back to the vault address
101
+ * (for legacy vaults where address == program ID).
102
+ */
76
103
  declare function resolveProgramId(vaultAddress: string, solanaMetadata?: {
77
104
  program_id?: string;
78
105
  } | null): string;
106
+ /** @internal */
79
107
  export declare function uiAmountToRawBn(uiAmount: number, decimals: number): BN;
80
108
  export declare const SolanaUtils: {
81
109
  getExplorerLink: typeof getExplorerLink;
@@ -7,31 +7,42 @@ const web3_js_1 = require("@solana/web3.js");
7
7
  const ethers_1 = require("ethers");
8
8
  const constants_1 = require("./constants");
9
9
  const core_1 = require("../../core");
10
+ // ============================================================================
11
+ // SOLANA UTILITIES
12
+ // ============================================================================
10
13
  function getExplorerLink({ signature, type = 'tx', network = constants_1.fallbackNetwork, }) {
11
14
  const baseUrl = 'https://solscan.io';
12
15
  return `${baseUrl}/${type}/${signature}?cluster=${network}`;
13
16
  }
17
+ // Re-exported from the core leaf so consumers in the core layer can import it
18
+ // without taking a dependency on the Solana adapter.
14
19
  const chain_address_1 = require("../../core/helpers/chain-address");
15
20
  Object.defineProperty(exports, "isSolanaAddress", { enumerable: true, get: function () { return chain_address_1.isSolanaAddress; } });
16
21
  function isSolana(signature) {
17
22
  if (!signature || typeof signature !== 'string')
18
23
  return false;
24
+ // Check if it's an Ethereum address first
19
25
  if ((0, ethers_1.isAddress)(signature))
20
26
  return false;
27
+ // Check if it's a valid Solana address (including PDAs) — addresses are not signatures
21
28
  if ((0, chain_address_1.isSolanaAddress)(signature))
22
29
  return false;
30
+ // Check if it's a valid base58 string with correct length for Solana signatures
31
+ // Solana signatures are base58 encoded and typically 88 characters long
23
32
  const base58Chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
24
33
  const isValidBase58 = signature
25
34
  .split('')
26
35
  .every((char) => base58Chars.includes(char));
27
36
  if (!isValidBase58)
28
37
  return false;
38
+ // Check length - Solana signatures are typically 88 characters
29
39
  return (signature.length >= 80 && signature.length <= 100);
30
40
  }
31
41
  function getProgram({ provider, idl, programId, network, }) {
32
42
  if (!idl) {
33
43
  return new anchor_1.Program(constants_1.vaultIdl, provider);
34
44
  }
45
+ // If programId is provided, create a modified IDL with the correct address
35
46
  if (programId) {
36
47
  const modifiedIdl = {
37
48
  ...idl,
@@ -41,6 +52,9 @@ function getProgram({ provider, idl, programId, network, }) {
41
52
  }
42
53
  return new anchor_1.Program(idl, provider);
43
54
  }
55
+ // ============================================================================
56
+ // SOLANA PROVIDERS
57
+ // ============================================================================
44
58
  async function testRpcEndpoint({ connection }) {
45
59
  try {
46
60
  const blockHeight = await connection.getBlockHeight();
@@ -50,13 +64,16 @@ async function testRpcEndpoint({ connection }) {
50
64
  return { success: false, error };
51
65
  }
52
66
  }
67
+ // Function to get the best available RPC endpoint
53
68
  async function getBestRpcEndpoint({ endpoint, network = constants_1.fallbackNetwork, connection, }) {
54
69
  const primaryEndpoint = endpoint;
55
70
  const fallbackEndpoint = constants_1.fallbackRpcEndpoints[network];
71
+ // Test primary endpoint first
56
72
  const primaryTest = await testRpcEndpoint({ connection });
57
73
  if (primaryTest.success) {
58
74
  return primaryEndpoint;
59
75
  }
76
+ // Fall back to public endpoint
60
77
  core_1.Logger.log.warn('getBestRpcEndpoint', '⚠️ Primary RPC endpoint failed, using fallback:', fallbackEndpoint);
61
78
  return fallbackEndpoint;
62
79
  }
@@ -68,14 +85,17 @@ function getProvider({ connection, publicKey, signTransaction, }) {
68
85
  publicKey,
69
86
  signTransaction,
70
87
  signAllTransactions: async (txs) => {
88
+ // Use Promise.all instead of await in loop
71
89
  const signedTransactions = await Promise.all(txs.map(async (tx) => signTransaction(tx)));
72
90
  return signedTransactions;
73
91
  },
74
92
  }, { commitment: 'confirmed' });
75
93
  }
94
+ // Read-only provider for data fetching without wallet connection
76
95
  function getReadOnlyProvider({ connection }) {
96
+ // Create a dummy wallet object for read-only operations
77
97
  const dummyWallet = {
78
- publicKey: web3_js_1.PublicKey.default,
98
+ publicKey: web3_js_1.PublicKey.default, // Use default public key
79
99
  signTransaction: async (_tx) => {
80
100
  throw new core_1.AugustValidationError('INVALID_INPUT', 'Cannot sign transactions with read-only provider');
81
101
  },
@@ -87,6 +107,9 @@ function getReadOnlyProvider({ connection }) {
87
107
  commitment: 'confirmed',
88
108
  });
89
109
  }
110
+ // ============================================================================
111
+ // SOLANA DERIVATIONS
112
+ // ============================================================================
90
113
  function deriveVaultStatePda(vaultProgramId) {
91
114
  if (!vaultProgramId)
92
115
  throw new core_1.AugustValidationError('INVALID_INPUT', 'Vault program ID missing');
@@ -120,6 +143,9 @@ function deriveVaultTokenAtaPda(vaultProgramId, depositMint, vaultVersion) {
120
143
  const [pda] = web3_js_1.PublicKey.findProgramAddressSync(seeds, _vaultProgramId);
121
144
  return pda;
122
145
  }
146
+ // ============================================================================
147
+ // SOLANA VAULTS
148
+ // ============================================================================
123
149
  async function getVaultState({ provider, connection, vaultProgramId, vaultAddress, idl, }) {
124
150
  const returnObj = {
125
151
  vaultState: null,
@@ -169,6 +195,7 @@ async function getVaultState({ provider, connection, vaultProgramId, vaultAddres
169
195
  return returnObj;
170
196
  }
171
197
  }
198
+ // Read-only version of getVaultState that works without wallet connection
172
199
  async function getVaultStateReadOnly({ vaultProgramId, vaultAddress, connection, idl, }) {
173
200
  const returnObj = {
174
201
  vaultState: null,
@@ -186,11 +213,13 @@ async function getVaultStateReadOnly({ vaultProgramId, vaultAddress, connection,
186
213
  const vaultStatePda = vaultAddress
187
214
  ? new web3_js_1.PublicKey(vaultAddress)
188
215
  : deriveVaultStatePda(_vaultProgramId);
216
+ // Use connection directly to fetch account data
189
217
  const accountInfo = await connection.getAccountInfo(vaultStatePda);
190
218
  if (!accountInfo) {
191
219
  core_1.Logger.log.warn('getVaultStateReadOnly', 'Vault state account not found');
192
220
  return returnObj;
193
221
  }
222
+ // Try to create a program with read-only provider for parsing
194
223
  try {
195
224
  const readOnlyProvider = getReadOnlyProvider({ connection });
196
225
  const program = getProgram({
@@ -219,6 +248,7 @@ async function getVaultStateReadOnly({ vaultProgramId, vaultAddress, connection,
219
248
  core_1.Logger.log.error('getVaultStateReadOnly', programError, {
220
249
  message: 'Error creating program with read-only provider',
221
250
  });
251
+ // Fallback: program parsing failed, vault state is unavailable
222
252
  returnObj.vaultState = null;
223
253
  }
224
254
  await (0, core_1.setSafeCache)(cacheKey, returnObj);
@@ -232,6 +262,7 @@ async function getVaultStateReadOnly({ vaultProgramId, vaultAddress, connection,
232
262
  return returnObj;
233
263
  }
234
264
  }
265
+ // Fetch deposit and share mint addresses from on-chain vault state (read-only, no wallet required)
235
266
  async function getVaultMints({ vaultProgramId, vaultAddress, connection, idl, }) {
236
267
  try {
237
268
  const cacheKey = `vaultMints-${vaultAddress || vaultProgramId}`;
@@ -255,6 +286,7 @@ async function getVaultMints({ vaultProgramId, vaultAddress, connection, idl, })
255
286
  const returnObj = {
256
287
  depositMint: state.depositMint.toString(),
257
288
  shareMint: state.shareMint.toString(),
289
+ // Empty arrays yield undefined, falling back to legacy PDA seeds (no version byte)
258
290
  vaultVersion: Array.isArray(state.vaultVersion)
259
291
  ? state.vaultVersion[0]
260
292
  : undefined,
@@ -285,6 +317,7 @@ async function getToken({ mintAddress, endpoint, connection, }) {
285
317
  const cachedData = await (0, core_1.getSafeCache)(cacheKey);
286
318
  if (cachedData)
287
319
  return cachedData;
320
+ // First, try to get token metadata via Metaplex DAS API
288
321
  const response = await fetch(endpoint, {
289
322
  method: 'POST',
290
323
  headers: {
@@ -297,7 +330,8 @@ async function getToken({ mintAddress, endpoint, connection, }) {
297
330
  params: { id: mintAddress.toString() },
298
331
  }),
299
332
  });
300
- const data = (await response.json());
333
+ const data = (await response.json()); // @todo: add interface
334
+ // If we got valid token metadata, return it
301
335
  if (data.result?.token_info?.decimals !== undefined) {
302
336
  return {
303
337
  address: data?.result?.id,
@@ -311,19 +345,25 @@ async function getToken({ mintAddress, endpoint, connection, }) {
311
345
  supply: data.result?.token_info?.supply,
312
346
  };
313
347
  }
348
+ // If Metaplex metadata didn't work, check if this is a vault program address
349
+ // In that case, we should query the share mint PDA instead
314
350
  if (connection) {
315
351
  try {
316
352
  const vaultProgramId = new web3_js_1.PublicKey(mintAddress);
353
+ // Try to get vault state to see if this is a vault
317
354
  const vaultState = await getVaultStateReadOnly({
318
355
  vaultProgramId,
319
356
  connection,
320
357
  idl: constants_1.vaultIdl,
321
358
  });
359
+ // If we successfully got vault state, derive the share mint and query that
322
360
  if (vaultState.vaultState) {
323
361
  const shareMintPda = deriveShareMintPda(vaultProgramId);
362
+ // Get share mint metadata from blockchain
324
363
  const shareMintInfo = await connection.getParsedAccountInfo(shareMintPda);
325
364
  if (shareMintInfo.value) {
326
365
  const parsedData = shareMintInfo.value.data;
366
+ // Try to get Metaplex metadata for the share mint
327
367
  const shareMintMetadata = await fetch(endpoint, {
328
368
  method: 'POST',
329
369
  headers: {
@@ -338,7 +378,7 @@ async function getToken({ mintAddress, endpoint, connection, }) {
338
378
  });
339
379
  const shareMintData = (await shareMintMetadata.json());
340
380
  const returnObj = {
341
- address: mintAddress.toString(),
381
+ address: mintAddress.toString(), // Return original vault address
342
382
  symbol: shareMintData.result?.content?.metadata?.symbol || 'N/A',
343
383
  decimals: parsedData.parsed.info.decimals,
344
384
  name: shareMintData.result?.content?.metadata?.name ||
@@ -348,7 +388,7 @@ async function getToken({ mintAddress, endpoint, connection, }) {
348
388
  mintAuthority: shareMintData.result?.token_info?.mint_authority,
349
389
  freezeAuthority: shareMintData.result?.token_info?.freeze_authority,
350
390
  supply: parsedData.parsed.info.supply,
351
- shareMintAddress: shareMintPda.toString(),
391
+ shareMintAddress: shareMintPda.toString(), // Include share mint address
352
392
  };
353
393
  await (0, core_1.setSafeCache)(cacheKey, returnObj);
354
394
  return returnObj;
@@ -356,9 +396,11 @@ async function getToken({ mintAddress, endpoint, connection, }) {
356
396
  }
357
397
  }
358
398
  catch (vaultError) {
399
+ // Not a vault or error checking vault state, continue to return null
359
400
  core_1.Logger.log.info('getToken', 'Not a vault program or error querying vault:', vaultError);
360
401
  }
361
402
  }
403
+ // If all attempts failed, return null
362
404
  return null;
363
405
  }
364
406
  catch (error) {
@@ -368,6 +410,7 @@ async function getToken({ mintAddress, endpoint, connection, }) {
368
410
  return null;
369
411
  }
370
412
  }
413
+ // Helper function to get just the token symbol
371
414
  async function getTokenSymbol({ endpoint, mintAddress, }) {
372
415
  try {
373
416
  const tokenMetadata = await getToken({ endpoint, mintAddress });
@@ -431,6 +474,28 @@ async function fetchUserShareBalance({ connection, publicKey, shareMint, }) {
431
474
  return 0;
432
475
  }
433
476
  }
477
+ /**
478
+ * Same on-chain lookup as `fetchUserShareBalance`, but returns the raw u64
479
+ * `amount` string and the mint's `decimals` — or `null` when the scale can't
480
+ * be determined (see Return shape) — instead of the floating-point `uiAmount`.
481
+ * Callers that feed the result into BigInt math (positions, redemptions,
482
+ * allowances) must use this — `uiAmount` is lossy and silently encodes with
483
+ * the wrong scale when passed back through `toNormalizedBn` without an
484
+ * explicit decimals argument.
485
+ *
486
+ * Return shape:
487
+ * `{ amount: '<u64>', decimals: number }` — token account exists.
488
+ * `{ amount: '0', decimals: null }` — no token account, missing
489
+ * tokenAmount in the parsed response, missing args, or the RPC threw.
490
+ *
491
+ * `decimals === null` is the "scale unknown" signal — callers that need a
492
+ * normalized `INormalizedNumber` must substitute a known decimals value
493
+ * (typically the deposit mint's decimals from backend metadata) before
494
+ * normalizing. Never throws.
495
+ *
496
+ * RPC cost: 1 × `getParsedTokenAccountsByOwner`. Independent of how many
497
+ * other accounts the wallet owns (filter is mint-scoped).
498
+ */
434
499
  async function fetchUserShareBalanceRaw({ connection, publicKey, shareMint, }) {
435
500
  if (!publicKey || !shareMint)
436
501
  return { amount: '0', decimals: null };
@@ -456,9 +521,17 @@ async function fetchUserShareBalanceRaw({ connection, publicKey, shareMint, }) {
456
521
  return { amount: '0', decimals: null };
457
522
  }
458
523
  }
524
+ /**
525
+ * Resolve the on-chain program ID for a Solana vault.
526
+ * Prefers the explicit `program_id` from metadata; falls back to the vault address
527
+ * (for legacy vaults where address == program ID).
528
+ */
459
529
  function resolveProgramId(vaultAddress, solanaMetadata) {
460
530
  return solanaMetadata?.program_id || vaultAddress;
461
531
  }
532
+ // String-arithmetic UI→raw conversion. Truncates past `decimals` like
533
+ // ethers.parseUnits; safe past Number.MAX_SAFE_INTEGER.
534
+ /** @internal */
462
535
  function uiAmountToRawBn(uiAmount, decimals) {
463
536
  if (!Number.isFinite(uiAmount)) {
464
537
  throw new core_1.AugustValidationError('INVALID_INPUT', `uiAmountToRawBn: amount must be finite, got ${uiAmount}`);
@@ -469,6 +542,8 @@ function uiAmountToRawBn(uiAmount, decimals) {
469
542
  if (!Number.isInteger(decimals) || decimals < 0) {
470
543
  throw new core_1.AugustValidationError('INVALID_INPUT', `uiAmountToRawBn: decimals must be a non-negative integer, got ${decimals}`);
471
544
  }
545
+ // Build the fixed-decimal string manually — `.toFixed(decimals)` rounds
546
+ // the last digit, but parseUnits semantics require truncation.
472
547
  const uiStr = uiAmount.toString();
473
548
  const expansion = uiStr.includes('e') || uiStr.includes('E')
474
549
  ? uiAmount.toFixed(Math.max(decimals, 20)).replace(/\.?0+$/, '')
@@ -1,7 +1,18 @@
1
- import { web3 } from '@coral-xyz/anchor';
2
- import { Connection, PublicKey, Transaction } from '@solana/web3.js';
3
- import { ISolanaConnectionOptions } from './types';
4
- import { SendTransactionOptions } from '@solana/wallet-adapter-base';
1
+ import { type web3 } from '@coral-xyz/anchor';
2
+ import { type Connection, PublicKey, Transaction } from '@solana/web3.js';
3
+ import type { ISolanaConnectionOptions } from './types';
4
+ import type { SendTransactionOptions } from '@solana/wallet-adapter-base';
5
+ /**
6
+ * Deposit funds into a Solana August vault and mint share tokens.
7
+ *
8
+ * @param depositAmount `bigint` is treated as raw on-chain units (preferred
9
+ * — no JS-float round-trip). `number` is treated as a UI amount and
10
+ * scaled by the deposit mint's decimals via {@link uiAmountToRawBn}.
11
+ * @throws AugustValidationError on missing wallet/programId or invalid amount.
12
+ * @remarks The on-chain `deposit` instruction has no `min_shares_out`
13
+ * parameter; slippage cannot be enforced on-chain until the program ships
14
+ * that argument.
15
+ */
5
16
  export declare function handleSolanaDeposit({ provider, connection, network, vaultProgramId, vaultAddress, depositAmount, publicKey, sendTransaction, idl, }: {
6
17
  vaultProgramId: PublicKey | string;
7
18
  vaultAddress?: PublicKey | string;
@@ -10,6 +21,14 @@ export declare function handleSolanaDeposit({ provider, connection, network, vau
10
21
  depositAmount: number | bigint;
11
22
  sendTransaction: (transaction: Transaction | web3.VersionedTransaction, connection: Connection, options?: SendTransactionOptions) => Promise<web3.TransactionSignature>;
12
23
  } & ISolanaConnectionOptions): Promise<any>;
24
+ /**
25
+ * Redeem vault shares back into the underlying mint on a Solana August vault.
26
+ *
27
+ * @param redeemShares `bigint` is treated as raw share-token units;
28
+ * `number` is treated as a UI amount. See {@link handleSolanaDeposit} for
29
+ * the same caveat about the missing on-chain slippage guard.
30
+ * @throws AugustValidationError on missing wallet/programId or invalid amount.
31
+ */
13
32
  export declare function handleSolanaRedeem({ provider, connection, vaultProgramId, vaultAddress, publicKey, redeemShares, sendTransaction, idl, }: {
14
33
  idl: any;
15
34
  vaultProgramId: PublicKey | string;
@@ -8,6 +8,17 @@ const spl_token_1 = require("@solana/spl-token");
8
8
  const constants_1 = require("./constants");
9
9
  const utils_1 = require("./utils");
10
10
  const core_1 = require("../../core");
11
+ /**
12
+ * Deposit funds into a Solana August vault and mint share tokens.
13
+ *
14
+ * @param depositAmount `bigint` is treated as raw on-chain units (preferred
15
+ * — no JS-float round-trip). `number` is treated as a UI amount and
16
+ * scaled by the deposit mint's decimals via {@link uiAmountToRawBn}.
17
+ * @throws AugustValidationError on missing wallet/programId or invalid amount.
18
+ * @remarks The on-chain `deposit` instruction has no `min_shares_out`
19
+ * parameter; slippage cannot be enforced on-chain until the program ships
20
+ * that argument.
21
+ */
11
22
  async function handleSolanaDeposit({ provider, connection, network = constants_1.fallbackNetwork, vaultProgramId, vaultAddress, depositAmount, publicKey, sendTransaction, idl, }) {
12
23
  try {
13
24
  if (!publicKey)
@@ -44,8 +55,11 @@ async function handleSolanaDeposit({ provider, connection, network = constants_1
44
55
  core_1.Logger.log.info('handleSolanaDeposit', 'Vault state PDA', vaultStatePda.toBase58());
45
56
  const vaultTokenAtaPda = utils_1.SolanaUtils.deriveVaultTokenAtaPda(_vaultProgramId, _depositMint, vaultVersion);
46
57
  core_1.Logger.log.info('handleSolanaDeposit', 'Vault token ATA PDA', vaultTokenAtaPda.toBase58());
58
+ // Use on-chain share mint from vault state instead of deriving a PDA,
59
+ // since PDA derivation assumes one share mint per program (single-vault only).
47
60
  const shareMintAddr = new web3_js_1.PublicKey(shareMint);
48
61
  core_1.Logger.log.info('handleSolanaDeposit', 'Share mint', shareMintAddr.toBase58());
62
+ // Get mint info to handle decimals
49
63
  const mintInfo = await connection.getParsedAccountInfo(_depositMint);
50
64
  if (!mintInfo.value) {
51
65
  throw new Error('Could not fetch mint info');
@@ -64,6 +78,7 @@ async function handleSolanaDeposit({ provider, connection, network = constants_1
64
78
  }
65
79
  depositAmountRaw = (0, utils_1.uiAmountToRawBn)(depositAmount, decimals);
66
80
  }
81
+ // Find user's token accounts
67
82
  const userTokenAccounts = await connection.getParsedTokenAccountsByOwner(_publicKey, {
68
83
  mint: _depositMint,
69
84
  });
@@ -78,9 +93,14 @@ async function handleSolanaDeposit({ provider, connection, network = constants_1
78
93
  let senderShareAccount;
79
94
  if (userShareAccounts.value.length === 0) {
80
95
  core_1.Logger.log.info('handleSolanaDeposit', 'Creating share account');
96
+ // Create share account if it doesn't exist
81
97
  senderShareAccount = await (0, spl_token_1.getAssociatedTokenAddress)(shareMintAddr, _publicKey);
82
98
  core_1.Logger.log.info('handleSolanaDeposit', 'Sender share account', senderShareAccount.toBase58());
83
- const createAtaIx = (0, spl_token_1.createAssociatedTokenAccountInstruction)(_publicKey, senderShareAccount, _publicKey, shareMintAddr);
99
+ // Create the associated token account
100
+ const createAtaIx = (0, spl_token_1.createAssociatedTokenAccountInstruction)(_publicKey, // payer
101
+ senderShareAccount, // associated token account
102
+ _publicKey, // owner
103
+ shareMintAddr);
84
104
  core_1.Logger.log.info('handleSolanaDeposit', 'Create ATA Ix', createAtaIx.programId.toBase58());
85
105
  const transaction = new web3_js_1.Transaction().add(createAtaIx);
86
106
  const signature = await sendTransaction(transaction, connection);
@@ -100,7 +120,9 @@ async function handleSolanaDeposit({ provider, connection, network = constants_1
100
120
  core_1.Logger.log.info('handleSolanaDeposit', 'Share mint', shareMintAddr.toBase58());
101
121
  core_1.Logger.log.info('handleSolanaDeposit', 'Deposit mint', _depositMint?.toBase58());
102
122
  core_1.Logger.log.info('handleSolanaDeposit', 'Signer', _publicKey.toBase58());
123
+ // Get a fresh blockhash to avoid "Blockhash not found" errors
103
124
  const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash('confirmed');
125
+ // TODO(slippage): pass `min_shares_out` here when the program ships it.
104
126
  const tx = await program.methods
105
127
  .deposit(depositAmountRaw)
106
128
  .accounts({
@@ -118,6 +140,7 @@ async function handleSolanaDeposit({ provider, connection, network = constants_1
118
140
  preflightCommitment: 'confirmed',
119
141
  });
120
142
  core_1.Logger.log.info('handleSolanaDeposit', 'Deposit successful:', tx);
143
+ // Wait for confirmation with the blockhash we used
121
144
  await connection.confirmTransaction({
122
145
  signature: tx,
123
146
  blockhash,
@@ -146,6 +169,14 @@ async function handleSolanaDeposit({ provider, connection, network = constants_1
146
169
  });
147
170
  }
148
171
  }
172
+ /**
173
+ * Redeem vault shares back into the underlying mint on a Solana August vault.
174
+ *
175
+ * @param redeemShares `bigint` is treated as raw share-token units;
176
+ * `number` is treated as a UI amount. See {@link handleSolanaDeposit} for
177
+ * the same caveat about the missing on-chain slippage guard.
178
+ * @throws AugustValidationError on missing wallet/programId or invalid amount.
179
+ */
149
180
  async function handleSolanaRedeem({ provider, connection, vaultProgramId, vaultAddress, publicKey, redeemShares, sendTransaction, idl, }) {
150
181
  try {
151
182
  if (!publicKey)
@@ -181,7 +212,10 @@ async function handleSolanaRedeem({ provider, connection, vaultProgramId, vaultA
181
212
  ? new web3_js_1.PublicKey(vaultAddress)
182
213
  : utils_1.SolanaUtils.deriveVaultStatePda(_vaultProgramId);
183
214
  const vaultTokenAtaPda = utils_1.SolanaUtils.deriveVaultTokenAtaPda(_vaultProgramId, _depositMint, vaultVersion);
215
+ // Use on-chain share mint from vault state instead of deriving a PDA,
216
+ // since PDA derivation assumes one share mint per program (single-vault only).
184
217
  const shareMintAddr = new web3_js_1.PublicKey(shareMint);
218
+ // Get share mint info to handle decimals
185
219
  const shareMintInfo = await connection.getParsedAccountInfo(shareMintAddr);
186
220
  if (!shareMintInfo.value) {
187
221
  throw new Error('Could not fetch share mint info');
@@ -201,6 +235,7 @@ async function handleSolanaRedeem({ provider, connection, vaultProgramId, vaultA
201
235
  }
202
236
  redeemSharesRaw = (0, utils_1.uiAmountToRawBn)(redeemShares, shareDecimals);
203
237
  }
238
+ // Find user's token accounts
204
239
  const userTokenAccounts = await connection.getParsedTokenAccountsByOwner(_publicKey, {
205
240
  mint: _depositMint,
206
241
  });
@@ -215,6 +250,7 @@ async function handleSolanaRedeem({ provider, connection, vaultProgramId, vaultA
215
250
  }
216
251
  const senderTokenAccount = userTokenAccounts?.value[0]?.pubkey;
217
252
  const senderShareAccount = userShareAccounts?.value[0]?.pubkey;
253
+ // Get the fee recipient from vault state
218
254
  const readOnlyProvider = utils_1.SolanaUtils.getReadOnlyProvider({ connection });
219
255
  const readOnlyProgram = utils_1.SolanaUtils.getProgram({
220
256
  provider: readOnlyProvider,
@@ -222,13 +258,19 @@ async function handleSolanaRedeem({ provider, connection, vaultProgramId, vaultA
222
258
  programId: _vaultProgramId.toBase58(),
223
259
  });
224
260
  const vaultStateData = await readOnlyProgram.account.vaultState.fetch(vaultStatePda);
261
+ // Get the fee recipient's token account
225
262
  const feeRecipientTokenAccount = await (0, spl_token_1.getAssociatedTokenAddress)(_depositMint, vaultStateData.feeRecipient);
263
+ // Check if the fee recipient token account exists, if not create it
226
264
  const feeRecipientAccountInfo = await connection.getAccountInfo(feeRecipientTokenAccount);
227
265
  if (!feeRecipientAccountInfo) {
228
- const createFeeRecipientAtaIx = (0, spl_token_1.createAssociatedTokenAccountInstruction)(_publicKey, feeRecipientTokenAccount, vaultStateData.feeRecipient, _depositMint);
266
+ const createFeeRecipientAtaIx = (0, spl_token_1.createAssociatedTokenAccountInstruction)(_publicKey, // payer (user pays for the account creation)
267
+ feeRecipientTokenAccount, // associated token account
268
+ vaultStateData.feeRecipient, // owner (the actual fee recipient)
269
+ _depositMint);
229
270
  const createAccountTx = new web3_js_1.Transaction().add(createFeeRecipientAtaIx);
230
271
  const createAccountSignature = await sendTransaction(createAccountTx, connection);
231
272
  core_1.Logger.log.info('handleSolanaRedeem', 'Fee recipient token account created:', createAccountSignature);
273
+ // Wait a moment for the account to be created
232
274
  await new Promise((resolve) => setTimeout(resolve, 1000));
233
275
  }
234
276
  else {
@@ -246,6 +288,7 @@ async function handleSolanaRedeem({ provider, connection, vaultProgramId, vaultA
246
288
  core_1.Logger.log.info('handleSolanaRedeem', 'Share mint:', shareMintAddr.toBase58());
247
289
  core_1.Logger.log.info('handleSolanaRedeem', 'Deposit mint:', _depositMint?.toBase58());
248
290
  core_1.Logger.log.info('handleSolanaRedeem', 'Signer:', _publicKey.toBase58());
291
+ // Get a fresh blockhash to avoid "Blockhash not found" errors
249
292
  const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash('confirmed');
250
293
  const tx = await program.methods
251
294
  .redeem(redeemSharesRaw)
@@ -254,7 +297,7 @@ async function handleSolanaRedeem({ provider, connection, vaultProgramId, vaultA
254
297
  vaultDepositAta: vaultTokenAtaPda,
255
298
  senderTokenAccount,
256
299
  senderShareAccount,
257
- feeRecipientAccount: feeRecipientTokenAccount,
300
+ feeRecipientAccount: feeRecipientTokenAccount, // The actual fee recipient's token account
258
301
  shareMint: shareMintAddr,
259
302
  depositMint: _depositMint,
260
303
  signer: _publicKey,
@@ -265,6 +308,7 @@ async function handleSolanaRedeem({ provider, connection, vaultProgramId, vaultA
265
308
  preflightCommitment: 'confirmed',
266
309
  });
267
310
  core_1.Logger.log.info('handleSolanaRedeem', 'Redeem successful:', tx);
311
+ // Wait for confirmation with the blockhash we used
268
312
  await connection.confirmTransaction({
269
313
  signature: tx,
270
314
  blockhash,