@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.
- package/README.md +207 -117
- package/lib/abis/ERC20_Bytes32.d.ts +4 -0
- package/lib/abis/ERC20_Bytes32.js +4 -0
- package/lib/abis/ERC4626.d.ts +1 -0
- package/lib/abis/ERC4626.js +1 -0
- package/lib/abis/ERC721.d.ts +1 -0
- package/lib/abis/ERC721.js +1 -0
- package/lib/abis/FeeOracle.js +1 -0
- package/lib/abis/LendingPool.js +1 -0
- package/lib/abis/LendingPoolV2.js +1 -0
- package/lib/abis/Multicall3.js +3 -0
- package/lib/abis/OFT.d.ts +20 -0
- package/lib/abis/OFT.js +20 -0
- package/lib/abis/SmartAccount.d.ts +1 -0
- package/lib/abis/SmartAccount.js +3 -0
- package/lib/abis/SwapRouter.d.ts +1 -0
- package/lib/abis/SwapRouter.js +1 -0
- package/lib/abis/UniversalSignatureValidator.js +3 -0
- package/lib/abis/index.d.ts +5 -0
- package/lib/abis/index.js +5 -0
- package/lib/adapters/evm/getters.d.ts +17 -2
- package/lib/adapters/evm/getters.js +35 -3
- package/lib/adapters/evm/index.d.ts +266 -4
- package/lib/adapters/evm/index.js +270 -1
- package/lib/adapters/evm/utils.d.ts +6 -0
- package/lib/adapters/evm/utils.js +7 -0
- package/lib/adapters/solana/constants.d.ts +1 -1
- package/lib/adapters/solana/constants.js +4 -1
- package/lib/adapters/solana/getters.d.ts +9 -1
- package/lib/adapters/solana/getters.js +21 -0
- package/lib/adapters/solana/idl/vault-idl.js +9 -0
- package/lib/adapters/solana/index.d.ts +59 -4
- package/lib/adapters/solana/index.js +61 -0
- package/lib/adapters/solana/types.d.ts +1 -1
- package/lib/adapters/solana/utils.d.ts +31 -3
- package/lib/adapters/solana/utils.js +79 -4
- package/lib/adapters/solana/vault.actions.d.ts +23 -4
- package/lib/adapters/solana/vault.actions.js +47 -3
- package/lib/adapters/stellar/actions.d.ts +26 -1
- package/lib/adapters/stellar/actions.js +33 -0
- package/lib/adapters/stellar/constants.d.ts +26 -0
- package/lib/adapters/stellar/constants.js +29 -0
- package/lib/adapters/stellar/getters.d.ts +56 -0
- package/lib/adapters/stellar/getters.js +81 -0
- package/lib/adapters/stellar/index.d.ts +70 -0
- package/lib/adapters/stellar/index.js +71 -0
- package/lib/adapters/stellar/soroban.d.ts +21 -1
- package/lib/adapters/stellar/soroban.js +47 -1
- package/lib/adapters/stellar/submit.d.ts +29 -0
- package/lib/adapters/stellar/submit.js +90 -5
- package/lib/adapters/stellar/types.d.ts +27 -0
- package/lib/adapters/stellar/types.js +3 -0
- package/lib/adapters/stellar/utils.d.ts +10 -0
- package/lib/adapters/stellar/utils.js +10 -0
- package/lib/adapters/sui/getters.d.ts +7 -1
- package/lib/adapters/sui/getters.js +6 -0
- package/lib/adapters/sui/index.d.ts +16 -1
- package/lib/adapters/sui/index.js +17 -0
- package/lib/adapters/sui/transformer.d.ts +8 -2
- package/lib/adapters/sui/transformer.js +7 -0
- package/lib/adapters/sui/types.d.ts +1 -1
- package/lib/adapters/sui/utils.d.ts +6 -0
- package/lib/adapters/sui/utils.js +6 -0
- package/lib/core/analytics/chain-name.d.ts +8 -0
- package/lib/core/analytics/chain-name.js +8 -0
- package/lib/core/analytics/constants.d.ts +4 -0
- package/lib/core/analytics/constants.js +4 -0
- package/lib/core/analytics/env.d.ts +25 -0
- package/lib/core/analytics/env.js +26 -0
- package/lib/core/analytics/index.d.ts +26 -0
- package/lib/core/analytics/index.js +35 -0
- package/lib/core/analytics/instrumentation.d.ts +26 -0
- package/lib/core/analytics/instrumentation.js +66 -2
- package/lib/core/analytics/method-taxonomy.d.ts +16 -0
- package/lib/core/analytics/method-taxonomy.js +18 -0
- package/lib/core/analytics/metrics.d.ts +23 -0
- package/lib/core/analytics/metrics.js +40 -0
- package/lib/core/analytics/sanitize.d.ts +38 -0
- package/lib/core/analytics/sanitize.js +46 -0
- package/lib/core/analytics/sentry-runtime.d.ts +11 -0
- package/lib/core/analytics/sentry-runtime.js +20 -1
- package/lib/core/analytics/sentry.d.ts +47 -2
- package/lib/core/analytics/sentry.js +115 -2
- package/lib/core/analytics/types.d.ts +28 -1
- package/lib/core/analytics/user-identity.d.ts +36 -2
- package/lib/core/analytics/user-identity.js +43 -1
- package/lib/core/analytics/version.d.ts +6 -1
- package/lib/core/analytics/version.js +6 -1
- package/lib/core/auth/verify.js +5 -0
- package/lib/core/base.class.d.ts +78 -3
- package/lib/core/base.class.js +66 -4
- package/lib/core/cache.d.ts +5 -0
- package/lib/core/cache.js +6 -0
- package/lib/core/constants/adapters.d.ts +16 -1
- package/lib/core/constants/adapters.js +28 -8
- package/lib/core/constants/core.d.ts +14 -1
- package/lib/core/constants/core.js +18 -0
- package/lib/core/constants/swap-router.d.ts +83 -1
- package/lib/core/constants/swap-router.js +91 -1
- package/lib/core/constants/vaults.d.ts +57 -1
- package/lib/core/constants/vaults.js +66 -1
- package/lib/core/constants/web3.d.ts +4 -1
- package/lib/core/constants/web3.js +15 -5
- package/lib/core/errors/index.d.ts +38 -2
- package/lib/core/errors/index.js +38 -0
- package/lib/core/fetcher.d.ts +136 -2
- package/lib/core/fetcher.js +229 -25
- package/lib/core/helpers/adapters.d.ts +10 -1
- package/lib/core/helpers/adapters.js +11 -0
- package/lib/core/helpers/chain-address.d.ts +10 -0
- package/lib/core/helpers/chain-address.js +11 -0
- package/lib/core/helpers/core.d.ts +49 -4
- package/lib/core/helpers/core.js +74 -7
- package/lib/core/helpers/explorer-link.d.ts +15 -1
- package/lib/core/helpers/explorer-link.js +14 -0
- package/lib/core/helpers/signer.d.ts +27 -1
- package/lib/core/helpers/signer.js +39 -0
- package/lib/core/helpers/swap-router.d.ts +33 -1
- package/lib/core/helpers/swap-router.js +32 -0
- package/lib/core/helpers/vault-version.d.ts +2 -1
- package/lib/core/helpers/vault-version.js +2 -0
- package/lib/core/helpers/vaults.d.ts +9 -1
- package/lib/core/helpers/vaults.js +22 -8
- package/lib/core/helpers/web3.d.ts +154 -2
- package/lib/core/helpers/web3.js +192 -15
- package/lib/core/logger/index.d.ts +55 -0
- package/lib/core/logger/index.js +19 -0
- package/lib/core/logger/slack.d.ts +3 -0
- package/lib/core/logger/slack.js +3 -0
- package/lib/core/vault-metadata.d.ts +7 -1
- package/lib/core/vault-metadata.js +6 -0
- package/lib/core/version-check.d.ts +52 -0
- package/lib/core/version-check.js +82 -1
- package/lib/evm/methods/crossChainVault.d.ts +90 -0
- package/lib/evm/methods/crossChainVault.js +187 -2
- package/lib/evm/methods/crossChainVaultRegistry.d.ts +93 -0
- package/lib/evm/methods/crossChainVaultRegistry.js +240 -0
- package/lib/evm/methods/index.d.ts +1 -0
- package/lib/evm/methods/index.js +1 -0
- package/lib/evm/types/crossChain.d.ts +202 -0
- package/lib/evm/types/crossChain.js +12 -1
- package/lib/index.d.ts +16 -0
- package/lib/index.js +19 -0
- package/lib/main.d.ts +289 -6
- package/lib/main.js +312 -0
- package/lib/modules/api/index.d.ts +1 -0
- package/lib/modules/api/index.js +6 -0
- package/lib/modules/api/main.d.ts +52 -0
- package/lib/modules/api/main.js +130 -0
- package/lib/modules/sub-accounts/fetcher.d.ts +17 -2
- package/lib/modules/sub-accounts/fetcher.js +15 -0
- package/lib/modules/sub-accounts/main.d.ts +35 -2
- package/lib/modules/sub-accounts/main.js +39 -1
- package/lib/modules/sub-accounts/utils.d.ts +4 -1
- package/lib/modules/sub-accounts/utils.js +3 -0
- package/lib/modules/vaults/adapter.helpers.d.ts +21 -3
- package/lib/modules/vaults/adapter.helpers.js +34 -0
- package/lib/modules/vaults/fetcher.d.ts +45 -0
- package/lib/modules/vaults/fetcher.js +91 -4
- package/lib/modules/vaults/getters.d.ts +295 -0
- package/lib/modules/vaults/getters.js +567 -26
- package/lib/modules/vaults/index.d.ts +12 -0
- package/lib/modules/vaults/index.js +12 -0
- package/lib/modules/vaults/main.d.ts +292 -4
- package/lib/modules/vaults/main.js +382 -8
- package/lib/modules/vaults/read.actions.d.ts +170 -2
- package/lib/modules/vaults/read.actions.js +143 -0
- package/lib/modules/vaults/types.d.ts +34 -0
- package/lib/modules/vaults/utils/call-data-decoder.d.ts +48 -1
- package/lib/modules/vaults/utils/call-data-decoder.js +56 -0
- package/lib/modules/vaults/utils/date-utils.d.ts +39 -0
- package/lib/modules/vaults/utils/date-utils.js +47 -1
- package/lib/modules/vaults/utils.d.ts +85 -0
- package/lib/modules/vaults/utils.js +139 -7
- package/lib/modules/vaults/write.actions.d.ts +363 -3
- package/lib/modules/vaults/write.actions.js +399 -3
- package/lib/polyfills.js +4 -2
- package/lib/sdk.d.ts +23847 -0
- package/lib/services/coingecko/fetcher.d.ts +15 -1
- package/lib/services/coingecko/fetcher.js +30 -9
- package/lib/services/debank/fetcher.d.ts +15 -1
- package/lib/services/debank/fetcher.js +12 -0
- package/lib/services/debank/utils.d.ts +1 -1
- package/lib/services/debank/utils.js +18 -1
- package/lib/services/layerzero/deposits.d.ts +12 -1
- package/lib/services/layerzero/deposits.js +34 -11
- package/lib/services/layerzero/redeems.d.ts +11 -1
- package/lib/services/layerzero/redeems.js +13 -0
- package/lib/services/layerzero/utils.d.ts +8 -0
- package/lib/services/layerzero/utils.js +11 -0
- package/lib/services/octavfi/fetcher.d.ts +8 -1
- package/lib/services/octavfi/fetcher.js +25 -0
- package/lib/services/octavfi/types.d.ts +1 -1
- package/lib/services/octavfi/utils.d.ts +14 -2
- package/lib/services/octavfi/utils.js +44 -10
- package/lib/services/subgraph/fetcher.js +4 -2
- package/lib/services/subgraph/vaults.d.ts +12 -0
- package/lib/services/subgraph/vaults.js +119 -2
- package/lib/services/swap-quotes/index.d.ts +80 -0
- package/lib/services/swap-quotes/index.js +27 -1
- package/lib/services/swap-quotes/paraswap.d.ts +25 -0
- package/lib/services/swap-quotes/paraswap.js +22 -0
- package/lib/types/pools.d.ts +5 -2
- package/lib/types/staking.d.ts +1 -1
- package/lib/types/sub-accounts.d.ts +1 -1
- package/lib/types/subgraph.d.ts +10 -1
- package/lib/types/typed-contract.d.ts +64 -0
- package/lib/types/vaults.d.ts +163 -2
- package/lib/types/vaults.js +10 -0
- package/lib/types/web3.d.ts +9 -1
- package/lib/types/web3.js +1 -0
- package/lib/types/webserver.d.ts +47 -2
- 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
|
-
|
|
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,
|
|
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,
|