upshift-finance 1.0.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/LICENSE +21 -0
- package/README.md +349 -0
- package/lib/abis/AddressResolver.d.ts +28 -0
- package/lib/abis/AddressResolver.js +23 -0
- package/lib/abis/ChainlinkV3.d.ts +87 -0
- package/lib/abis/ChainlinkV3.js +117 -0
- package/lib/abis/ERC20.d.ts +168 -0
- package/lib/abis/ERC20.js +226 -0
- package/lib/abis/ERC20_Bytes32.d.ts +139 -0
- package/lib/abis/ERC20_Bytes32.js +196 -0
- package/lib/abis/ERC4626.d.ts +364 -0
- package/lib/abis/ERC4626.js +507 -0
- package/lib/abis/ERC721.d.ts +231 -0
- package/lib/abis/ERC721.js +321 -0
- package/lib/abis/FeeOracle.d.ts +120 -0
- package/lib/abis/FeeOracle.js +162 -0
- package/lib/abis/LendingPool.d.ts +1393 -0
- package/lib/abis/LendingPool.js +1807 -0
- package/lib/abis/LendingPoolV2.d.ts +1413 -0
- package/lib/abis/LendingPoolV2.js +1833 -0
- package/lib/abis/LendingPoolV3.d.ts +1677 -0
- package/lib/abis/LendingPoolV3.js +1160 -0
- package/lib/abis/Loan.d.ts +837 -0
- package/lib/abis/Loan.js +1080 -0
- package/lib/abis/MultiAssetNativeDepositWrapper.d.ts +137 -0
- package/lib/abis/MultiAssetNativeDepositWrapper.js +125 -0
- package/lib/abis/Multicall3.d.ts +30 -0
- package/lib/abis/Multicall3.js +97 -0
- package/lib/abis/OFT.d.ts +116 -0
- package/lib/abis/OFT.js +85 -0
- package/lib/abis/PoolAdapter.d.ts +36 -0
- package/lib/abis/PoolAdapter.js +51 -0
- package/lib/abis/RewardDistributor.d.ts +267 -0
- package/lib/abis/RewardDistributor.js +352 -0
- package/lib/abis/RwaRedeemSubaccount.d.ts +747 -0
- package/lib/abis/RwaRedeemSubaccount.js +548 -0
- package/lib/abis/SmartAccount.d.ts +17 -0
- package/lib/abis/SmartAccount.js +19 -0
- package/lib/abis/SwapRouter.d.ts +1043 -0
- package/lib/abis/SwapRouter.js +740 -0
- package/lib/abis/TextResolver.d.ts +16 -0
- package/lib/abis/TextResolver.js +16 -0
- package/lib/abis/TokenizedVaultV2.d.ts +1364 -0
- package/lib/abis/TokenizedVaultV2.js +1041 -0
- package/lib/abis/TokenizedVaultV2DepositWithPermit.d.ts +1456 -0
- package/lib/abis/TokenizedVaultV2DepositWithPermit.js +1878 -0
- package/lib/abis/TokenizedVaultV2Receipt.d.ts +1568 -0
- package/lib/abis/TokenizedVaultV2Receipt.js +1061 -0
- package/lib/abis/TokenizedVaultV2SenderAllocationWhitelist.d.ts +454 -0
- package/lib/abis/TokenizedVaultV2SenderAllocationWhitelist.js +327 -0
- package/lib/abis/TokenizedVaultV2WhitelistedAllocation.d.ts +1466 -0
- package/lib/abis/TokenizedVaultV2WhitelistedAllocation.js +1092 -0
- package/lib/abis/TokenizedVaultV2WhitelistedAssets.d.ts +274 -0
- package/lib/abis/TokenizedVaultV2WhitelistedAssets.js +167 -0
- package/lib/abis/UniversalResolverResolve.d.ts +69 -0
- package/lib/abis/UniversalResolverResolve.js +35 -0
- package/lib/abis/UniversalSignatureValidator.d.ts +17 -0
- package/lib/abis/UniversalSignatureValidator.js +30 -0
- package/lib/abis/WrapperAdapter.d.ts +71 -0
- package/lib/abis/WrapperAdapter.js +77 -0
- package/lib/abis/index.d.ts +34 -0
- package/lib/abis/index.js +51 -0
- package/lib/adapters/evm/getters.d.ts +19 -0
- package/lib/adapters/evm/getters.js +209 -0
- package/lib/adapters/evm/index.d.ts +353 -0
- package/lib/adapters/evm/index.js +434 -0
- package/lib/adapters/evm/utils.d.ts +8 -0
- package/lib/adapters/evm/utils.js +51 -0
- package/lib/adapters/solana/constants.d.ts +33 -0
- package/lib/adapters/solana/constants.js +52 -0
- package/lib/adapters/solana/getters.d.ts +11 -0
- package/lib/adapters/solana/getters.js +165 -0
- package/lib/adapters/solana/idl/vault-idl.d.ts +272 -0
- package/lib/adapters/solana/idl/vault-idl.js +1084 -0
- package/lib/adapters/solana/index.d.ts +233 -0
- package/lib/adapters/solana/index.js +291 -0
- package/lib/adapters/solana/types.d.ts +67 -0
- package/lib/adapters/solana/types.js +3 -0
- package/lib/adapters/solana/utils.d.ts +141 -0
- package/lib/adapters/solana/utils.js +595 -0
- package/lib/adapters/solana/vault.actions.d.ts +57 -0
- package/lib/adapters/solana/vault.actions.js +379 -0
- package/lib/adapters/stellar/actions.d.ts +28 -0
- package/lib/adapters/stellar/actions.js +77 -0
- package/lib/adapters/stellar/constants.d.ts +43 -0
- package/lib/adapters/stellar/constants.js +53 -0
- package/lib/adapters/stellar/getters.d.ts +68 -0
- package/lib/adapters/stellar/getters.js +290 -0
- package/lib/adapters/stellar/index.d.ts +114 -0
- package/lib/adapters/stellar/index.js +175 -0
- package/lib/adapters/stellar/soroban.d.ts +123 -0
- package/lib/adapters/stellar/soroban.js +613 -0
- package/lib/adapters/stellar/submit.d.ts +34 -0
- package/lib/adapters/stellar/submit.js +149 -0
- package/lib/adapters/stellar/types.d.ts +58 -0
- package/lib/adapters/stellar/types.js +6 -0
- package/lib/adapters/stellar/utils.d.ts +24 -0
- package/lib/adapters/stellar/utils.js +34 -0
- package/lib/adapters/sui/constants.d.ts +14 -0
- package/lib/adapters/sui/constants.js +29 -0
- package/lib/adapters/sui/getters.d.ts +9 -0
- package/lib/adapters/sui/getters.js +60 -0
- package/lib/adapters/sui/index.d.ts +45 -0
- package/lib/adapters/sui/index.js +101 -0
- package/lib/adapters/sui/transformer.d.ts +10 -0
- package/lib/adapters/sui/transformer.js +107 -0
- package/lib/adapters/sui/types.d.ts +66 -0
- package/lib/adapters/sui/types.js +3 -0
- package/lib/adapters/sui/utils.d.ts +10 -0
- package/lib/adapters/sui/utils.js +29 -0
- package/lib/core/analytics/chain-name.d.ts +9 -0
- package/lib/core/analytics/chain-name.js +34 -0
- package/lib/core/analytics/constants.d.ts +5 -0
- package/lib/core/analytics/constants.js +9 -0
- package/lib/core/analytics/env.d.ts +29 -0
- package/lib/core/analytics/env.js +59 -0
- package/lib/core/analytics/index.d.ts +36 -0
- package/lib/core/analytics/index.js +79 -0
- package/lib/core/analytics/instrumentation.d.ts +29 -0
- package/lib/core/analytics/instrumentation.js +277 -0
- package/lib/core/analytics/method-taxonomy.d.ts +19 -0
- package/lib/core/analytics/method-taxonomy.js +128 -0
- package/lib/core/analytics/metrics.d.ts +33 -0
- package/lib/core/analytics/metrics.js +116 -0
- package/lib/core/analytics/sanitize.d.ts +44 -0
- package/lib/core/analytics/sanitize.js +260 -0
- package/lib/core/analytics/sentry-runtime.d.ts +15 -0
- package/lib/core/analytics/sentry-runtime.js +97 -0
- package/lib/core/analytics/sentry.d.ts +67 -0
- package/lib/core/analytics/sentry.js +613 -0
- package/lib/core/analytics/types.d.ts +48 -0
- package/lib/core/analytics/types.js +3 -0
- package/lib/core/analytics/user-identity.d.ts +41 -0
- package/lib/core/analytics/user-identity.js +141 -0
- package/lib/core/analytics/version.d.ts +6 -0
- package/lib/core/analytics/version.js +10 -0
- package/lib/core/attribution.d.ts +111 -0
- package/lib/core/attribution.js +142 -0
- package/lib/core/auth/index.d.ts +1 -0
- package/lib/core/auth/index.js +18 -0
- package/lib/core/auth/verify.d.ts +2 -0
- package/lib/core/auth/verify.js +31 -0
- package/lib/core/base.class.d.ts +152 -0
- package/lib/core/base.class.js +172 -0
- package/lib/core/cache.d.ts +9 -0
- package/lib/core/cache.js +31 -0
- package/lib/core/constants/adapters.d.ts +103 -0
- package/lib/core/constants/adapters.js +180 -0
- package/lib/core/constants/core.d.ts +133 -0
- package/lib/core/constants/core.js +209 -0
- package/lib/core/constants/swap-router.d.ts +150 -0
- package/lib/core/constants/swap-router.js +169 -0
- package/lib/core/constants/vaults.d.ts +93 -0
- package/lib/core/constants/vaults.js +273 -0
- package/lib/core/constants/web3.d.ts +91 -0
- package/lib/core/constants/web3.js +229 -0
- package/lib/core/errors/index.d.ts +114 -0
- package/lib/core/errors/index.js +183 -0
- package/lib/core/fetcher.d.ts +198 -0
- package/lib/core/fetcher.js +903 -0
- package/lib/core/helpers/adapters.d.ts +13 -0
- package/lib/core/helpers/adapters.js +39 -0
- package/lib/core/helpers/chain-address.d.ts +13 -0
- package/lib/core/helpers/chain-address.js +47 -0
- package/lib/core/helpers/chain-error.d.ts +207 -0
- package/lib/core/helpers/chain-error.js +682 -0
- package/lib/core/helpers/chain-support.d.ts +80 -0
- package/lib/core/helpers/chain-support.js +115 -0
- package/lib/core/helpers/core.d.ts +68 -0
- package/lib/core/helpers/core.js +285 -0
- package/lib/core/helpers/explorer-link.d.ts +16 -0
- package/lib/core/helpers/explorer-link.js +26 -0
- package/lib/core/helpers/multicall.d.ts +68 -0
- package/lib/core/helpers/multicall.js +103 -0
- package/lib/core/helpers/revert-decode.d.ts +248 -0
- package/lib/core/helpers/revert-decode.js +515 -0
- package/lib/core/helpers/signer.d.ts +52 -0
- package/lib/core/helpers/signer.js +145 -0
- package/lib/core/helpers/swap-router.d.ts +211 -0
- package/lib/core/helpers/swap-router.js +480 -0
- package/lib/core/helpers/vault-version.d.ts +23 -0
- package/lib/core/helpers/vault-version.js +75 -0
- package/lib/core/helpers/vaults.d.ts +89 -0
- package/lib/core/helpers/vaults.js +235 -0
- package/lib/core/helpers/web3.d.ts +353 -0
- package/lib/core/helpers/web3.js +992 -0
- package/lib/core/index.d.ts +23 -0
- package/lib/core/index.js +40 -0
- package/lib/core/logger/index.d.ts +98 -0
- package/lib/core/logger/index.js +144 -0
- package/lib/core/logger/slack.d.ts +16 -0
- package/lib/core/logger/slack.js +57 -0
- package/lib/core/vault-metadata.d.ts +12 -0
- package/lib/core/vault-metadata.js +42 -0
- package/lib/core/version-check.d.ts +58 -0
- package/lib/core/version-check.js +182 -0
- package/lib/evm/index.d.ts +2 -0
- package/lib/evm/index.js +19 -0
- package/lib/evm/methods/crossChainVault.d.ts +128 -0
- package/lib/evm/methods/crossChainVault.js +853 -0
- package/lib/evm/methods/crossChainVaultRegistry.d.ts +93 -0
- package/lib/evm/methods/crossChainVaultRegistry.js +240 -0
- package/lib/evm/methods/index.d.ts +2 -0
- package/lib/evm/methods/index.js +19 -0
- package/lib/evm/types/crossChain.d.ts +363 -0
- package/lib/evm/types/crossChain.js +20 -0
- package/lib/evm/types/index.d.ts +1 -0
- package/lib/evm/types/index.js +18 -0
- package/lib/index.d.ts +30 -0
- package/lib/index.js +52 -0
- package/lib/main.d.ts +527 -0
- package/lib/main.js +601 -0
- package/lib/modules/api/fetcher.d.ts +82 -0
- package/lib/modules/api/fetcher.js +150 -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 +313 -0
- package/lib/modules/api/main.js +479 -0
- package/lib/modules/sub-accounts/fetcher.d.ts +53 -0
- package/lib/modules/sub-accounts/fetcher.js +120 -0
- package/lib/modules/sub-accounts/index.d.ts +2 -0
- package/lib/modules/sub-accounts/index.js +19 -0
- package/lib/modules/sub-accounts/main.d.ts +243 -0
- package/lib/modules/sub-accounts/main.js +205 -0
- package/lib/modules/sub-accounts/utils.d.ts +106 -0
- package/lib/modules/sub-accounts/utils.js +112 -0
- package/lib/modules/vaults/adapter.helpers.d.ts +64 -0
- package/lib/modules/vaults/adapter.helpers.js +184 -0
- package/lib/modules/vaults/fetcher.d.ts +147 -0
- package/lib/modules/vaults/fetcher.js +368 -0
- package/lib/modules/vaults/getters.d.ts +570 -0
- package/lib/modules/vaults/getters.js +3051 -0
- package/lib/modules/vaults/index.d.ts +20 -0
- package/lib/modules/vaults/index.js +44 -0
- package/lib/modules/vaults/main.d.ts +601 -0
- package/lib/modules/vaults/main.js +1623 -0
- package/lib/modules/vaults/prefetch.d.ts +65 -0
- package/lib/modules/vaults/prefetch.js +120 -0
- package/lib/modules/vaults/read.actions.d.ts +225 -0
- package/lib/modules/vaults/read.actions.js +596 -0
- package/lib/modules/vaults/types.d.ts +71 -0
- package/lib/modules/vaults/types.js +3 -0
- package/lib/modules/vaults/utils/call-data-decoder.d.ts +61 -0
- package/lib/modules/vaults/utils/call-data-decoder.js +194 -0
- package/lib/modules/vaults/utils/date-utils.d.ts +50 -0
- package/lib/modules/vaults/utils/date-utils.js +84 -0
- package/lib/modules/vaults/utils.d.ts +140 -0
- package/lib/modules/vaults/utils.js +799 -0
- package/lib/modules/vaults/write.actions.d.ts +529 -0
- package/lib/modules/vaults/write.actions.js +1749 -0
- package/lib/polyfills.d.ts +1 -0
- package/lib/polyfills.js +12 -0
- package/lib/sdk.d.ts +26721 -0
- package/lib/services/coingecko/fetcher.d.ts +15 -0
- package/lib/services/coingecko/fetcher.js +67 -0
- package/lib/services/coingecko/index.d.ts +2 -0
- package/lib/services/coingecko/index.js +19 -0
- package/lib/services/coingecko/utils.d.ts +1 -0
- package/lib/services/coingecko/utils.js +24 -0
- package/lib/services/debank/fetcher.d.ts +126 -0
- package/lib/services/debank/fetcher.js +47 -0
- package/lib/services/debank/index.d.ts +2 -0
- package/lib/services/debank/index.js +19 -0
- package/lib/services/debank/utils.d.ts +38 -0
- package/lib/services/debank/utils.js +297 -0
- package/lib/services/layerzero/deposits.d.ts +49 -0
- package/lib/services/layerzero/deposits.js +166 -0
- package/lib/services/layerzero/redeems.d.ts +20 -0
- package/lib/services/layerzero/redeems.js +92 -0
- package/lib/services/layerzero/utils.d.ts +9 -0
- package/lib/services/layerzero/utils.js +22 -0
- package/lib/services/octavfi/fetcher.d.ts +9 -0
- package/lib/services/octavfi/fetcher.js +103 -0
- package/lib/services/octavfi/index.d.ts +3 -0
- package/lib/services/octavfi/index.js +20 -0
- package/lib/services/octavfi/types.d.ts +34 -0
- package/lib/services/octavfi/types.js +3 -0
- package/lib/services/octavfi/utils.d.ts +16 -0
- package/lib/services/octavfi/utils.js +212 -0
- package/lib/services/subgraph/fetcher.d.ts +2 -0
- package/lib/services/subgraph/fetcher.js +61 -0
- package/lib/services/subgraph/index.d.ts +2 -0
- package/lib/services/subgraph/index.js +19 -0
- package/lib/services/subgraph/schema.d.ts +45 -0
- package/lib/services/subgraph/schema.js +75 -0
- package/lib/services/subgraph/vaults.d.ts +25 -0
- package/lib/services/subgraph/vaults.js +1106 -0
- package/lib/services/swap-quotes/index.d.ts +105 -0
- package/lib/services/swap-quotes/index.js +77 -0
- package/lib/services/swap-quotes/paraswap.d.ts +51 -0
- package/lib/services/swap-quotes/paraswap.js +138 -0
- package/lib/types/api.d.ts +280 -0
- package/lib/types/api.js +3 -0
- package/lib/types/index.d.ts +12 -0
- package/lib/types/index.js +28 -0
- package/lib/types/points.d.ts +28 -0
- package/lib/types/points.js +3 -0
- package/lib/types/pools.d.ts +144 -0
- package/lib/types/pools.js +3 -0
- package/lib/types/staking.d.ts +28 -0
- package/lib/types/staking.js +3 -0
- package/lib/types/sub-accounts.d.ts +140 -0
- package/lib/types/sub-accounts.js +3 -0
- package/lib/types/subgraph.d.ts +74 -0
- package/lib/types/subgraph.js +3 -0
- package/lib/types/typed-contract.d.ts +102 -0
- package/lib/types/typed-contract.js +3 -0
- package/lib/types/user.d.ts +1 -0
- package/lib/types/user.js +3 -0
- package/lib/types/vaults.d.ts +714 -0
- package/lib/types/vaults.js +24 -0
- package/lib/types/web3.d.ts +51 -0
- package/lib/types/web3.js +14 -0
- package/lib/types/webserver.d.ts +698 -0
- package/lib/types/webserver.js +3 -0
- package/package.json +78 -0
|
@@ -0,0 +1,595 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SolanaUtils = exports.isSolanaAddress = void 0;
|
|
4
|
+
exports.uiAmountToRawBn = uiAmountToRawBn;
|
|
5
|
+
const anchor_1 = require("@coral-xyz/anchor");
|
|
6
|
+
const web3_js_1 = require("@solana/web3.js");
|
|
7
|
+
const ethers_1 = require("ethers");
|
|
8
|
+
const constants_1 = require("./constants");
|
|
9
|
+
const core_1 = require("../../core");
|
|
10
|
+
// ============================================================================
|
|
11
|
+
// SOLANA UTILITIES
|
|
12
|
+
// ============================================================================
|
|
13
|
+
function getExplorerLink({ signature, type = 'tx', network = constants_1.fallbackNetwork, }) {
|
|
14
|
+
const baseUrl = 'https://solscan.io';
|
|
15
|
+
return `${baseUrl}/${type}/${signature}?cluster=${network}`;
|
|
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.
|
|
19
|
+
const chain_address_1 = require("../../core/helpers/chain-address");
|
|
20
|
+
Object.defineProperty(exports, "isSolanaAddress", { enumerable: true, get: function () { return chain_address_1.isSolanaAddress; } });
|
|
21
|
+
function isSolana(signature) {
|
|
22
|
+
if (!signature || typeof signature !== 'string')
|
|
23
|
+
return false;
|
|
24
|
+
// Check if it's an Ethereum address first
|
|
25
|
+
if ((0, ethers_1.isAddress)(signature))
|
|
26
|
+
return false;
|
|
27
|
+
// Check if it's a valid Solana address (including PDAs) — addresses are not signatures
|
|
28
|
+
if ((0, chain_address_1.isSolanaAddress)(signature))
|
|
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
|
|
32
|
+
const base58Chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
|
|
33
|
+
const isValidBase58 = signature
|
|
34
|
+
.split('')
|
|
35
|
+
.every((char) => base58Chars.includes(char));
|
|
36
|
+
if (!isValidBase58)
|
|
37
|
+
return false;
|
|
38
|
+
// Check length - Solana signatures are typically 88 characters
|
|
39
|
+
return (signature.length >= 80 && signature.length <= 100);
|
|
40
|
+
}
|
|
41
|
+
function getProgram({ provider, idl, programId, network, }) {
|
|
42
|
+
const baseIdl = idl ?? constants_1.vaultIdl;
|
|
43
|
+
// Precedence: explicit `programId` → a custom IDL's `address` → the network
|
|
44
|
+
// default → the bundled IDL's embedded `address`.
|
|
45
|
+
//
|
|
46
|
+
// The custom-address check compares by VALUE, not reference. Keying off
|
|
47
|
+
// `idl === vaultIdl` broke for a structurally-identical-but-not-reference-equal
|
|
48
|
+
// copy (second bundle instance, or JSON round-tripped), silently retargeting
|
|
49
|
+
// devnet callers at mainnet. Every copy carries the same build stamp, so it
|
|
50
|
+
// still defers to the network default — but a genuinely custom IDL is honoured.
|
|
51
|
+
const suppliedAddress = typeof baseIdl?.address === 'string' && baseIdl.address !== constants_1.vaultIdl.address
|
|
52
|
+
? baseIdl.address
|
|
53
|
+
: undefined;
|
|
54
|
+
const explicitId = programId ?? suppliedAddress;
|
|
55
|
+
if (explicitId) {
|
|
56
|
+
return new anchor_1.Program({ ...baseIdl, address: explicitId }, provider);
|
|
57
|
+
}
|
|
58
|
+
if (network) {
|
|
59
|
+
const networkDefault = (0, constants_1.getDeployedProgramIds)(network)?.vault;
|
|
60
|
+
if (!networkDefault) {
|
|
61
|
+
throw new core_1.AugustValidationError('INVALID_INPUT', `No canonical august_vault deployment for Solana network '${network}'. ` +
|
|
62
|
+
`Deployed networks: ${Object.keys(constants_1.programIds).join(', ')}. ` +
|
|
63
|
+
`Pass an explicit \`programId\` (or an IDL carrying the target \`address\`) to target a program on this network.`);
|
|
64
|
+
}
|
|
65
|
+
return new anchor_1.Program({ ...baseIdl, address: networkDefault }, provider);
|
|
66
|
+
}
|
|
67
|
+
return new anchor_1.Program(baseIdl, provider);
|
|
68
|
+
}
|
|
69
|
+
// ============================================================================
|
|
70
|
+
// SOLANA PROVIDERS
|
|
71
|
+
// ============================================================================
|
|
72
|
+
async function testRpcEndpoint({ connection }) {
|
|
73
|
+
try {
|
|
74
|
+
const blockHeight = await connection.getBlockHeight();
|
|
75
|
+
return { success: true, blockHeight };
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
return { success: false, error };
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
// Function to get the best available RPC endpoint
|
|
82
|
+
async function getBestRpcEndpoint({ endpoint, network = constants_1.fallbackNetwork, connection, }) {
|
|
83
|
+
const primaryEndpoint = endpoint;
|
|
84
|
+
const fallbackEndpoint = constants_1.fallbackRpcEndpoints[network];
|
|
85
|
+
// Test primary endpoint first
|
|
86
|
+
const primaryTest = await testRpcEndpoint({ connection });
|
|
87
|
+
if (primaryTest.success) {
|
|
88
|
+
return primaryEndpoint;
|
|
89
|
+
}
|
|
90
|
+
// Fall back to public endpoint
|
|
91
|
+
core_1.Logger.log.warn('getBestRpcEndpoint', '⚠️ Primary RPC endpoint failed, using fallback:', fallbackEndpoint);
|
|
92
|
+
return fallbackEndpoint;
|
|
93
|
+
}
|
|
94
|
+
function getProvider({ connection, publicKey, signTransaction, }) {
|
|
95
|
+
if (!publicKey || !signTransaction) {
|
|
96
|
+
throw new core_1.AugustValidationError('INVALID_INPUT', 'Wallet not connected: publicKey and signTransaction are required for write operations');
|
|
97
|
+
}
|
|
98
|
+
return new anchor_1.AnchorProvider(connection, {
|
|
99
|
+
publicKey,
|
|
100
|
+
signTransaction,
|
|
101
|
+
signAllTransactions: async (txs) => {
|
|
102
|
+
// Use Promise.all instead of await in loop
|
|
103
|
+
const signedTransactions = await Promise.all(txs.map(async (tx) => signTransaction(tx)));
|
|
104
|
+
return signedTransactions;
|
|
105
|
+
},
|
|
106
|
+
}, { commitment: 'confirmed' });
|
|
107
|
+
}
|
|
108
|
+
// Read-only provider for data fetching without wallet connection
|
|
109
|
+
function getReadOnlyProvider({ connection }) {
|
|
110
|
+
// Create a dummy wallet object for read-only operations
|
|
111
|
+
const dummyWallet = {
|
|
112
|
+
publicKey: web3_js_1.PublicKey.default, // Use default public key
|
|
113
|
+
signTransaction: async (_tx) => {
|
|
114
|
+
throw new core_1.AugustValidationError('INVALID_INPUT', 'Cannot sign transactions with read-only provider');
|
|
115
|
+
},
|
|
116
|
+
signAllTransactions: async (_txs) => {
|
|
117
|
+
throw new core_1.AugustValidationError('INVALID_INPUT', 'Cannot sign transactions with read-only provider');
|
|
118
|
+
},
|
|
119
|
+
};
|
|
120
|
+
return new anchor_1.AnchorProvider(connection, dummyWallet, {
|
|
121
|
+
commitment: 'confirmed',
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
// ============================================================================
|
|
125
|
+
// SOLANA DERIVATIONS
|
|
126
|
+
// ============================================================================
|
|
127
|
+
function deriveVaultStatePda(vaultProgramId) {
|
|
128
|
+
if (!vaultProgramId)
|
|
129
|
+
throw new core_1.AugustValidationError('INVALID_INPUT', 'Vault program ID missing');
|
|
130
|
+
const _vaultProgramId = new web3_js_1.PublicKey(vaultProgramId);
|
|
131
|
+
const [pda] = web3_js_1.PublicKey.findProgramAddressSync([new TextEncoder().encode('VAULT_STATE')], _vaultProgramId);
|
|
132
|
+
return pda;
|
|
133
|
+
}
|
|
134
|
+
function deriveShareMintPda(vaultProgramId) {
|
|
135
|
+
if (!vaultProgramId)
|
|
136
|
+
throw new core_1.AugustValidationError('INVALID_INPUT', 'Vault program ID missing');
|
|
137
|
+
const _vaultProgramId = new web3_js_1.PublicKey(vaultProgramId);
|
|
138
|
+
const [pda] = web3_js_1.PublicKey.findProgramAddressSync([new TextEncoder().encode('mint')], _vaultProgramId);
|
|
139
|
+
return pda;
|
|
140
|
+
}
|
|
141
|
+
function deriveVaultTokenAtaPda(vaultProgramId, depositMint, vaultVersion) {
|
|
142
|
+
if (!(vaultProgramId && depositMint))
|
|
143
|
+
throw new core_1.AugustValidationError('INVALID_INPUT', 'Vault program ID or deposit mint missing');
|
|
144
|
+
const _vaultProgramId = new web3_js_1.PublicKey(vaultProgramId);
|
|
145
|
+
const seeds = [
|
|
146
|
+
Buffer.from('token_vault'),
|
|
147
|
+
depositMint.toBuffer(),
|
|
148
|
+
];
|
|
149
|
+
if (vaultVersion !== undefined) {
|
|
150
|
+
if (!Number.isInteger(vaultVersion) ||
|
|
151
|
+
vaultVersion < 0 ||
|
|
152
|
+
vaultVersion > 255) {
|
|
153
|
+
throw new core_1.AugustValidationError('INVALID_INPUT', `Invalid vault version ${vaultVersion}: must be an integer between 0 and 255`);
|
|
154
|
+
}
|
|
155
|
+
seeds.push(Buffer.from([vaultVersion]));
|
|
156
|
+
}
|
|
157
|
+
const [pda] = web3_js_1.PublicKey.findProgramAddressSync(seeds, _vaultProgramId);
|
|
158
|
+
return pda;
|
|
159
|
+
}
|
|
160
|
+
// ============================================================================
|
|
161
|
+
// SOLANA VAULTS
|
|
162
|
+
// ============================================================================
|
|
163
|
+
async function getVaultState({ provider, connection, vaultProgramId, vaultAddress, idl, }) {
|
|
164
|
+
const returnObj = {
|
|
165
|
+
vaultState: null,
|
|
166
|
+
depositMintDecimals: null,
|
|
167
|
+
};
|
|
168
|
+
try {
|
|
169
|
+
const cacheKey = `vaultState-${vaultAddress || vaultProgramId}`;
|
|
170
|
+
const cachedData = await (0, core_1.getSafeCache)(cacheKey);
|
|
171
|
+
if (cachedData)
|
|
172
|
+
return cachedData;
|
|
173
|
+
if (!vaultProgramId) {
|
|
174
|
+
throw new core_1.AugustValidationError('INVALID_INPUT', 'Please enter a vault program ID');
|
|
175
|
+
}
|
|
176
|
+
const vaultStatePda = vaultAddress
|
|
177
|
+
? new web3_js_1.PublicKey(vaultAddress)
|
|
178
|
+
: deriveVaultStatePda(vaultProgramId);
|
|
179
|
+
const _vaultProgramId = new web3_js_1.PublicKey(vaultProgramId);
|
|
180
|
+
const program = getProgram({
|
|
181
|
+
provider,
|
|
182
|
+
idl,
|
|
183
|
+
programId: _vaultProgramId.toBase58(),
|
|
184
|
+
});
|
|
185
|
+
const state = await program.account.vaultState.fetch(vaultStatePda);
|
|
186
|
+
returnObj.vaultState = state;
|
|
187
|
+
if (state.depositMint) {
|
|
188
|
+
try {
|
|
189
|
+
const mintInfo = await connection.getParsedAccountInfo(state.depositMint);
|
|
190
|
+
if (mintInfo.value) {
|
|
191
|
+
const parsedData = mintInfo.value.data;
|
|
192
|
+
returnObj.depositMintDecimals = parsedData.parsed.info.decimals;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
catch (mintError) {
|
|
196
|
+
core_1.Logger.log.error('getVaultState', mintError, {
|
|
197
|
+
message: 'Error fetching deposit mint decimals',
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
await (0, core_1.setSafeCache)(cacheKey, returnObj);
|
|
202
|
+
return returnObj;
|
|
203
|
+
}
|
|
204
|
+
catch (e) {
|
|
205
|
+
const error = e;
|
|
206
|
+
core_1.Logger.log.error('getVaultState', error, {
|
|
207
|
+
message: 'Error reading vault state',
|
|
208
|
+
});
|
|
209
|
+
return returnObj;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
// Read-only version of getVaultState that works without wallet connection
|
|
213
|
+
async function getVaultStateReadOnly({ vaultProgramId, vaultAddress, connection, idl, }) {
|
|
214
|
+
const returnObj = {
|
|
215
|
+
vaultState: null,
|
|
216
|
+
depositMintDecimals: null,
|
|
217
|
+
};
|
|
218
|
+
try {
|
|
219
|
+
const cacheKey = `vaultState-${vaultAddress || vaultProgramId}`;
|
|
220
|
+
const cachedData = await (0, core_1.getSafeCache)(cacheKey);
|
|
221
|
+
if (cachedData)
|
|
222
|
+
return cachedData;
|
|
223
|
+
if (!vaultProgramId) {
|
|
224
|
+
throw new core_1.AugustValidationError('INVALID_INPUT', 'Please enter a vault program ID');
|
|
225
|
+
}
|
|
226
|
+
const _vaultProgramId = new web3_js_1.PublicKey(vaultProgramId);
|
|
227
|
+
const vaultStatePda = vaultAddress
|
|
228
|
+
? new web3_js_1.PublicKey(vaultAddress)
|
|
229
|
+
: deriveVaultStatePda(_vaultProgramId);
|
|
230
|
+
// Use connection directly to fetch account data
|
|
231
|
+
const accountInfo = await connection.getAccountInfo(vaultStatePda);
|
|
232
|
+
if (!accountInfo) {
|
|
233
|
+
core_1.Logger.log.warn('getVaultStateReadOnly', 'Vault state account not found');
|
|
234
|
+
return returnObj;
|
|
235
|
+
}
|
|
236
|
+
// Try to create a program with read-only provider for parsing
|
|
237
|
+
try {
|
|
238
|
+
const readOnlyProvider = getReadOnlyProvider({ connection });
|
|
239
|
+
const program = getProgram({
|
|
240
|
+
provider: readOnlyProvider,
|
|
241
|
+
idl,
|
|
242
|
+
programId: _vaultProgramId.toBase58(),
|
|
243
|
+
});
|
|
244
|
+
const state = await program.account.vaultState.fetch(vaultStatePda);
|
|
245
|
+
returnObj.vaultState = state;
|
|
246
|
+
if (state.depositMint) {
|
|
247
|
+
try {
|
|
248
|
+
const mintInfo = await connection.getParsedAccountInfo(state.depositMint);
|
|
249
|
+
if (mintInfo.value) {
|
|
250
|
+
const parsedData = mintInfo.value.data;
|
|
251
|
+
returnObj.depositMintDecimals = parsedData.parsed.info.decimals;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
catch (mintError) {
|
|
255
|
+
core_1.Logger.log.error('getVaultStateReadOnly', mintError, {
|
|
256
|
+
message: 'Error fetching deposit mint decimals',
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
catch (programError) {
|
|
262
|
+
core_1.Logger.log.error('getVaultStateReadOnly', programError, {
|
|
263
|
+
message: 'Error creating program with read-only provider',
|
|
264
|
+
});
|
|
265
|
+
// Fallback: program parsing failed, vault state is unavailable
|
|
266
|
+
returnObj.vaultState = null;
|
|
267
|
+
}
|
|
268
|
+
await (0, core_1.setSafeCache)(cacheKey, returnObj);
|
|
269
|
+
return returnObj;
|
|
270
|
+
}
|
|
271
|
+
catch (e) {
|
|
272
|
+
const error = e;
|
|
273
|
+
core_1.Logger.log.error('getVaultStateReadOnly', error, {
|
|
274
|
+
message: 'Error reading vault state',
|
|
275
|
+
});
|
|
276
|
+
return returnObj;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
// Fetch deposit and share mint addresses from on-chain vault state (read-only, no wallet required)
|
|
280
|
+
async function getVaultMints({ vaultProgramId, vaultAddress, connection, idl, }) {
|
|
281
|
+
try {
|
|
282
|
+
const cacheKey = `vaultMints-${vaultAddress || vaultProgramId}`;
|
|
283
|
+
const cachedData = await (0, core_1.getSafeCache)(cacheKey);
|
|
284
|
+
if (cachedData)
|
|
285
|
+
return cachedData;
|
|
286
|
+
if (!vaultProgramId) {
|
|
287
|
+
throw new core_1.AugustValidationError('INVALID_INPUT', 'Please enter a vault program ID');
|
|
288
|
+
}
|
|
289
|
+
const _vaultProgramId = new web3_js_1.PublicKey(vaultProgramId);
|
|
290
|
+
const vaultStatePda = vaultAddress
|
|
291
|
+
? new web3_js_1.PublicKey(vaultAddress)
|
|
292
|
+
: deriveVaultStatePda(_vaultProgramId);
|
|
293
|
+
const readOnlyProvider = getReadOnlyProvider({ connection });
|
|
294
|
+
const program = getProgram({
|
|
295
|
+
provider: readOnlyProvider,
|
|
296
|
+
idl,
|
|
297
|
+
programId: _vaultProgramId.toBase58(),
|
|
298
|
+
});
|
|
299
|
+
const state = await program.account.vaultState.fetch(vaultStatePda);
|
|
300
|
+
const returnObj = {
|
|
301
|
+
depositMint: state.depositMint.toString(),
|
|
302
|
+
shareMint: state.shareMint.toString(),
|
|
303
|
+
// Empty arrays yield undefined, falling back to legacy PDA seeds (no version byte)
|
|
304
|
+
vaultVersion: Array.isArray(state.vaultVersion)
|
|
305
|
+
? state.vaultVersion[0]
|
|
306
|
+
: undefined,
|
|
307
|
+
};
|
|
308
|
+
await (0, core_1.setSafeCache)(cacheKey, returnObj);
|
|
309
|
+
return returnObj;
|
|
310
|
+
}
|
|
311
|
+
catch (e) {
|
|
312
|
+
const error = e;
|
|
313
|
+
const cause = error?.message || String(error);
|
|
314
|
+
core_1.Logger.log.error('getVaultMints', error, {
|
|
315
|
+
message: 'Error reading vault mints',
|
|
316
|
+
vaultProgramId: String(vaultProgramId),
|
|
317
|
+
vaultAddress: vaultAddress ? String(vaultAddress) : undefined,
|
|
318
|
+
});
|
|
319
|
+
throw new core_1.AugustSDKError('UNKNOWN', `Failed to read vault mints from on-chain state: ${cause}`, {
|
|
320
|
+
cause: error,
|
|
321
|
+
context: {
|
|
322
|
+
vaultProgramId: String(vaultProgramId),
|
|
323
|
+
vaultAddress: vaultAddress ? String(vaultAddress) : undefined,
|
|
324
|
+
},
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
async function getToken({ mintAddress, endpoint, connection, }) {
|
|
329
|
+
try {
|
|
330
|
+
const cacheKey = `solana_token-${mintAddress}`;
|
|
331
|
+
const cachedData = await (0, core_1.getSafeCache)(cacheKey);
|
|
332
|
+
if (cachedData)
|
|
333
|
+
return cachedData;
|
|
334
|
+
// First, try to get token metadata via Metaplex DAS API
|
|
335
|
+
const response = await fetch(endpoint, {
|
|
336
|
+
method: 'POST',
|
|
337
|
+
headers: {
|
|
338
|
+
'Content-Type': 'application/json',
|
|
339
|
+
},
|
|
340
|
+
body: JSON.stringify({
|
|
341
|
+
jsonrpc: '2.0',
|
|
342
|
+
id: 'text',
|
|
343
|
+
method: 'getAsset',
|
|
344
|
+
params: { id: mintAddress.toString() },
|
|
345
|
+
}),
|
|
346
|
+
});
|
|
347
|
+
const data = (await response.json()); // @todo: add interface
|
|
348
|
+
// If we got valid token metadata, return it
|
|
349
|
+
if (data.result?.token_info?.decimals !== undefined) {
|
|
350
|
+
return {
|
|
351
|
+
address: data?.result?.id,
|
|
352
|
+
symbol: data.result?.content?.metadata?.symbol || 'N/A',
|
|
353
|
+
decimals: data.result?.token_info?.decimals,
|
|
354
|
+
name: data.result?.content?.metadata?.name || 'Unknown',
|
|
355
|
+
image: data.result?.content.metadata?.image,
|
|
356
|
+
program: data.result?.token_info?.token_program,
|
|
357
|
+
mintAuthority: data.result?.token_info?.mint_authority,
|
|
358
|
+
freezeAuthority: data.result?.token_info?.freeze_authority,
|
|
359
|
+
supply: data.result?.token_info?.supply,
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
// If Metaplex metadata didn't work, check if this is a vault program address
|
|
363
|
+
// In that case, we should query the share mint PDA instead
|
|
364
|
+
if (connection) {
|
|
365
|
+
try {
|
|
366
|
+
const vaultProgramId = new web3_js_1.PublicKey(mintAddress);
|
|
367
|
+
// Try to get vault state to see if this is a vault
|
|
368
|
+
const vaultState = await getVaultStateReadOnly({
|
|
369
|
+
vaultProgramId,
|
|
370
|
+
connection,
|
|
371
|
+
idl: constants_1.vaultIdl,
|
|
372
|
+
});
|
|
373
|
+
// If we successfully got vault state, derive the share mint and query that
|
|
374
|
+
if (vaultState.vaultState) {
|
|
375
|
+
const shareMintPda = deriveShareMintPda(vaultProgramId);
|
|
376
|
+
// Get share mint metadata from blockchain
|
|
377
|
+
const shareMintInfo = await connection.getParsedAccountInfo(shareMintPda);
|
|
378
|
+
if (shareMintInfo.value) {
|
|
379
|
+
const parsedData = shareMintInfo.value.data;
|
|
380
|
+
// Try to get Metaplex metadata for the share mint
|
|
381
|
+
const shareMintMetadata = await fetch(endpoint, {
|
|
382
|
+
method: 'POST',
|
|
383
|
+
headers: {
|
|
384
|
+
'Content-Type': 'application/json',
|
|
385
|
+
},
|
|
386
|
+
body: JSON.stringify({
|
|
387
|
+
jsonrpc: '2.0',
|
|
388
|
+
id: 'text',
|
|
389
|
+
method: 'getAsset',
|
|
390
|
+
params: { id: shareMintPda.toString() },
|
|
391
|
+
}),
|
|
392
|
+
});
|
|
393
|
+
const shareMintData = (await shareMintMetadata.json());
|
|
394
|
+
const returnObj = {
|
|
395
|
+
address: mintAddress.toString(), // Return original vault address
|
|
396
|
+
symbol: shareMintData.result?.content?.metadata?.symbol || 'N/A',
|
|
397
|
+
decimals: parsedData.parsed.info.decimals,
|
|
398
|
+
name: shareMintData.result?.content?.metadata?.name ||
|
|
399
|
+
'Vault Share Token',
|
|
400
|
+
image: shareMintData.result?.content?.metadata?.image,
|
|
401
|
+
program: shareMintData.result?.token_info?.token_program,
|
|
402
|
+
mintAuthority: shareMintData.result?.token_info?.mint_authority,
|
|
403
|
+
freezeAuthority: shareMintData.result?.token_info?.freeze_authority,
|
|
404
|
+
supply: parsedData.parsed.info.supply,
|
|
405
|
+
shareMintAddress: shareMintPda.toString(), // Include share mint address
|
|
406
|
+
};
|
|
407
|
+
await (0, core_1.setSafeCache)(cacheKey, returnObj);
|
|
408
|
+
return returnObj;
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
catch (vaultError) {
|
|
413
|
+
// Not a vault or error checking vault state, continue to return null
|
|
414
|
+
core_1.Logger.log.info('getToken', 'Not a vault program or error querying vault:', vaultError);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
// If all attempts failed, return null
|
|
418
|
+
return null;
|
|
419
|
+
}
|
|
420
|
+
catch (error) {
|
|
421
|
+
core_1.Logger.log.error('getToken', error, {
|
|
422
|
+
message: 'Error fetching token metadata',
|
|
423
|
+
});
|
|
424
|
+
return null;
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
// Helper function to get just the token symbol
|
|
428
|
+
async function getTokenSymbol({ endpoint, mintAddress, }) {
|
|
429
|
+
try {
|
|
430
|
+
const tokenMetadata = await getToken({ endpoint, mintAddress });
|
|
431
|
+
if (tokenMetadata) {
|
|
432
|
+
return tokenMetadata.symbol;
|
|
433
|
+
}
|
|
434
|
+
return null;
|
|
435
|
+
}
|
|
436
|
+
catch (error) {
|
|
437
|
+
core_1.Logger.log.error('getTokenSymbol', error, {
|
|
438
|
+
message: 'Error fetching token symbol',
|
|
439
|
+
});
|
|
440
|
+
return null;
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
async function fetchUserTokenBalance({ connection, publicKey, depositMint, }) {
|
|
444
|
+
if (!publicKey || !depositMint)
|
|
445
|
+
return '0';
|
|
446
|
+
try {
|
|
447
|
+
const _publicKey = new web3_js_1.PublicKey(publicKey);
|
|
448
|
+
const _depositMint = new web3_js_1.PublicKey(depositMint);
|
|
449
|
+
const tokenAccounts = await connection.getParsedTokenAccountsByOwner(_publicKey, {
|
|
450
|
+
mint: _depositMint,
|
|
451
|
+
});
|
|
452
|
+
if (tokenAccounts.value.length > 0) {
|
|
453
|
+
const balance = tokenAccounts?.value?.[0]?.account.data.parsed.info.tokenAmount
|
|
454
|
+
.uiAmount;
|
|
455
|
+
return balance?.toString() || '0';
|
|
456
|
+
}
|
|
457
|
+
return '0';
|
|
458
|
+
}
|
|
459
|
+
catch (e) {
|
|
460
|
+
const error = e;
|
|
461
|
+
core_1.Logger.log.error('fetchUserTokenBalance', error, {
|
|
462
|
+
message: 'Error fetching user token balance',
|
|
463
|
+
});
|
|
464
|
+
return '0';
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
async function fetchUserShareBalance({ connection, publicKey, shareMint, }) {
|
|
468
|
+
if (!publicKey || !shareMint)
|
|
469
|
+
return 0;
|
|
470
|
+
try {
|
|
471
|
+
const _publicKey = new web3_js_1.PublicKey(publicKey);
|
|
472
|
+
const _shareMint = new web3_js_1.PublicKey(shareMint);
|
|
473
|
+
const shareAccounts = await connection.getParsedTokenAccountsByOwner(_publicKey, {
|
|
474
|
+
mint: _shareMint,
|
|
475
|
+
});
|
|
476
|
+
if (shareAccounts.value.length > 0) {
|
|
477
|
+
const balance = shareAccounts?.value?.[0]?.account.data.parsed.info.tokenAmount
|
|
478
|
+
.uiAmount;
|
|
479
|
+
return balance ?? 0;
|
|
480
|
+
}
|
|
481
|
+
return 0;
|
|
482
|
+
}
|
|
483
|
+
catch (e) {
|
|
484
|
+
const error = e;
|
|
485
|
+
core_1.Logger.log.error('fetchUserShareBalance', error, {
|
|
486
|
+
message: 'Error fetching user share balance',
|
|
487
|
+
});
|
|
488
|
+
return 0;
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
/**
|
|
492
|
+
* Same on-chain lookup as `fetchUserShareBalance`, but returns the raw u64
|
|
493
|
+
* `amount` string and the mint's `decimals` — or `null` when the scale can't
|
|
494
|
+
* be determined (see Return shape) — instead of the floating-point `uiAmount`.
|
|
495
|
+
* Callers that feed the result into BigInt math (positions, redemptions,
|
|
496
|
+
* allowances) must use this — `uiAmount` is lossy and silently encodes with
|
|
497
|
+
* the wrong scale when passed back through `toNormalizedBn` without an
|
|
498
|
+
* explicit decimals argument.
|
|
499
|
+
*
|
|
500
|
+
* Return shape:
|
|
501
|
+
* `{ amount: '<u64>', decimals: number }` — token account exists.
|
|
502
|
+
* `{ amount: '0', decimals: null }` — no token account, missing
|
|
503
|
+
* tokenAmount in the parsed response, missing args, or the RPC threw.
|
|
504
|
+
*
|
|
505
|
+
* `decimals === null` is the "scale unknown" signal — callers that need a
|
|
506
|
+
* normalized `INormalizedNumber` must substitute a known decimals value
|
|
507
|
+
* (typically the deposit mint's decimals from backend metadata) before
|
|
508
|
+
* normalizing. Never throws.
|
|
509
|
+
*
|
|
510
|
+
* RPC cost: 1 × `getParsedTokenAccountsByOwner`. Independent of how many
|
|
511
|
+
* other accounts the wallet owns (filter is mint-scoped).
|
|
512
|
+
*/
|
|
513
|
+
async function fetchUserShareBalanceRaw({ connection, publicKey, shareMint, }) {
|
|
514
|
+
if (!publicKey || !shareMint)
|
|
515
|
+
return { amount: '0', decimals: null };
|
|
516
|
+
try {
|
|
517
|
+
const _publicKey = new web3_js_1.PublicKey(publicKey);
|
|
518
|
+
const _shareMint = new web3_js_1.PublicKey(shareMint);
|
|
519
|
+
const shareAccounts = await connection.getParsedTokenAccountsByOwner(_publicKey, {
|
|
520
|
+
mint: _shareMint,
|
|
521
|
+
});
|
|
522
|
+
const tokenAmount = shareAccounts?.value?.[0]?.account?.data?.parsed?.info?.tokenAmount;
|
|
523
|
+
if (!tokenAmount)
|
|
524
|
+
return { amount: '0', decimals: null };
|
|
525
|
+
return {
|
|
526
|
+
amount: String(tokenAmount.amount ?? '0'),
|
|
527
|
+
decimals: typeof tokenAmount.decimals === 'number' ? tokenAmount.decimals : null,
|
|
528
|
+
};
|
|
529
|
+
}
|
|
530
|
+
catch (e) {
|
|
531
|
+
const error = e;
|
|
532
|
+
core_1.Logger.log.error('fetchUserShareBalanceRaw', error, {
|
|
533
|
+
message: 'Error fetching raw user share balance',
|
|
534
|
+
});
|
|
535
|
+
return { amount: '0', decimals: null };
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
/**
|
|
539
|
+
* Resolve the on-chain program ID for a Solana vault.
|
|
540
|
+
* Prefers the explicit `program_id` from metadata; falls back to the vault address
|
|
541
|
+
* (for legacy vaults where address == program ID).
|
|
542
|
+
*/
|
|
543
|
+
function resolveProgramId(vaultAddress, solanaMetadata) {
|
|
544
|
+
return solanaMetadata?.program_id || vaultAddress;
|
|
545
|
+
}
|
|
546
|
+
// String-arithmetic UI→raw conversion. Truncates past `decimals` like
|
|
547
|
+
// ethers.parseUnits; safe past Number.MAX_SAFE_INTEGER.
|
|
548
|
+
/** @internal */
|
|
549
|
+
function uiAmountToRawBn(uiAmount, decimals) {
|
|
550
|
+
if (!Number.isFinite(uiAmount)) {
|
|
551
|
+
throw new core_1.AugustValidationError('INVALID_INPUT', `uiAmountToRawBn: amount must be finite, got ${uiAmount}`);
|
|
552
|
+
}
|
|
553
|
+
if (uiAmount < 0) {
|
|
554
|
+
throw new core_1.AugustValidationError('INVALID_INPUT', `uiAmountToRawBn: amount must be non-negative, got ${uiAmount}`);
|
|
555
|
+
}
|
|
556
|
+
if (!Number.isInteger(decimals) || decimals < 0) {
|
|
557
|
+
throw new core_1.AugustValidationError('INVALID_INPUT', `uiAmountToRawBn: decimals must be a non-negative integer, got ${decimals}`);
|
|
558
|
+
}
|
|
559
|
+
// Build the fixed-decimal string manually — `.toFixed(decimals)` rounds
|
|
560
|
+
// the last digit, but parseUnits semantics require truncation.
|
|
561
|
+
const uiStr = uiAmount.toString();
|
|
562
|
+
const expansion = uiStr.includes('e') || uiStr.includes('E')
|
|
563
|
+
? uiAmount.toFixed(Math.max(decimals, 20)).replace(/\.?0+$/, '')
|
|
564
|
+
: uiStr;
|
|
565
|
+
const [whole, fraction = ''] = expansion.split('.');
|
|
566
|
+
const truncated = fraction.slice(0, decimals);
|
|
567
|
+
const paddedFraction = truncated.padEnd(decimals, '0');
|
|
568
|
+
const raw = (whole + paddedFraction).replace(/^0+/, '') || '0';
|
|
569
|
+
return new anchor_1.BN(raw);
|
|
570
|
+
}
|
|
571
|
+
exports.SolanaUtils = {
|
|
572
|
+
getExplorerLink,
|
|
573
|
+
isSolanaAddress: chain_address_1.isSolanaAddress,
|
|
574
|
+
isSolana,
|
|
575
|
+
getProgram,
|
|
576
|
+
getProvider,
|
|
577
|
+
getReadOnlyProvider,
|
|
578
|
+
deriveShareMintPda,
|
|
579
|
+
deriveVaultStatePda,
|
|
580
|
+
deriveVaultTokenAtaPda,
|
|
581
|
+
getVaultState,
|
|
582
|
+
getVaultStateReadOnly,
|
|
583
|
+
getToken,
|
|
584
|
+
getTokenSymbol,
|
|
585
|
+
fetchUserTokenBalance,
|
|
586
|
+
fetchUserShareBalance,
|
|
587
|
+
fetchUserShareBalanceRaw,
|
|
588
|
+
getBestRpcEndpoint,
|
|
589
|
+
fallbackDecimals: constants_1.fallbackDecimals,
|
|
590
|
+
fallbackNetwork: constants_1.fallbackNetwork,
|
|
591
|
+
programIds: constants_1.programIds,
|
|
592
|
+
getVaultMints,
|
|
593
|
+
resolveProgramId,
|
|
594
|
+
};
|
|
595
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1,57 @@
|
|
|
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
|
+
* Extract a human- and machine-readable reason from a thrown Solana/Anchor
|
|
7
|
+
* error.
|
|
8
|
+
*
|
|
9
|
+
* Anchor's {@link https://github.com/coral-xyz/anchor `ProgramError`} calls
|
|
10
|
+
* `super()` with no argument, so its `.message` is the empty string by
|
|
11
|
+
* construction — the real reason lives on `.msg`/`.code` (and `.toString()`).
|
|
12
|
+
* `AnchorError` puts it on `.error.errorMessage` / `.error.errorCode.number`.
|
|
13
|
+
* Reading `.message` directly (as this file used to) therefore rendered
|
|
14
|
+
* `"Solana deposit failed: "` for every recognized on-chain revert — dropping
|
|
15
|
+
* the numeric code the team needs to tell "Vault is paused" from
|
|
16
|
+
* "Insufficient amount" from an account-constraint violation.
|
|
17
|
+
*
|
|
18
|
+
* When no reason can be extracted, returns an actionable, user-facing fallback
|
|
19
|
+
* rather than an "unknown error" admission — the raw throwable is still
|
|
20
|
+
* preserved on the wrapped error's `cause` and in telemetry for diagnosis.
|
|
21
|
+
*/
|
|
22
|
+
export declare function describeSolanaError(e: unknown): string;
|
|
23
|
+
/**
|
|
24
|
+
* Deposit funds into a Solana August vault and mint share tokens.
|
|
25
|
+
*
|
|
26
|
+
* @param depositAmount `bigint` is treated as raw on-chain units (preferred
|
|
27
|
+
* — no JS-float round-trip). `number` is treated as a UI amount and
|
|
28
|
+
* scaled by the deposit mint's decimals via {@link uiAmountToRawBn}.
|
|
29
|
+
* @throws AugustValidationError on missing wallet/programId or invalid amount.
|
|
30
|
+
* @remarks The on-chain `deposit` instruction has no `min_shares_out`
|
|
31
|
+
* parameter; slippage cannot be enforced on-chain until the program ships
|
|
32
|
+
* that argument.
|
|
33
|
+
*/
|
|
34
|
+
export declare function handleSolanaDeposit({ provider, connection, network, vaultProgramId, vaultAddress, depositAmount, publicKey, sendTransaction, idl, }: {
|
|
35
|
+
vaultProgramId: PublicKey | string;
|
|
36
|
+
vaultAddress?: PublicKey | string;
|
|
37
|
+
idl: any;
|
|
38
|
+
publicKey: PublicKey | string;
|
|
39
|
+
depositAmount: number | bigint;
|
|
40
|
+
sendTransaction: (transaction: Transaction | web3.VersionedTransaction, connection: Connection, options?: SendTransactionOptions) => Promise<web3.TransactionSignature>;
|
|
41
|
+
} & ISolanaConnectionOptions): Promise<any>;
|
|
42
|
+
/**
|
|
43
|
+
* Redeem vault shares back into the underlying mint on a Solana August vault.
|
|
44
|
+
*
|
|
45
|
+
* @param redeemShares `bigint` is treated as raw share-token units;
|
|
46
|
+
* `number` is treated as a UI amount. See {@link handleSolanaDeposit} for
|
|
47
|
+
* the same caveat about the missing on-chain slippage guard.
|
|
48
|
+
* @throws AugustValidationError on missing wallet/programId or invalid amount.
|
|
49
|
+
*/
|
|
50
|
+
export declare function handleSolanaRedeem({ provider, connection, vaultProgramId, vaultAddress, publicKey, redeemShares, sendTransaction, idl, }: {
|
|
51
|
+
idl: any;
|
|
52
|
+
vaultProgramId: PublicKey | string;
|
|
53
|
+
vaultAddress?: PublicKey | string;
|
|
54
|
+
publicKey: PublicKey | string;
|
|
55
|
+
redeemShares: number | bigint;
|
|
56
|
+
sendTransaction: (transaction: Transaction | web3.VersionedTransaction, connection: Connection, options?: SendTransactionOptions) => Promise<web3.TransactionSignature>;
|
|
57
|
+
} & ISolanaConnectionOptions): Promise<any>;
|