upshift-config 0.5.14
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,903 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.setSafeCache = exports.getSafeCache = exports.CACHE = void 0;
|
|
4
|
+
exports.setSdkRequestTimeout = setSdkRequestTimeout;
|
|
5
|
+
exports.getSdkRequestTimeout = getSdkRequestTimeout;
|
|
6
|
+
exports.setPublicApiBaseUrl = setPublicApiBaseUrl;
|
|
7
|
+
exports.getPublicApiBaseUrl = getPublicApiBaseUrl;
|
|
8
|
+
exports.fetchAugustWithKey = fetchAugustWithKey;
|
|
9
|
+
exports.fetchAugustPublic = fetchAugustPublic;
|
|
10
|
+
exports.fetchAugustWithBearer = fetchAugustWithBearer;
|
|
11
|
+
exports.isRetryableError = isRetryableError;
|
|
12
|
+
exports.withRetry = withRetry;
|
|
13
|
+
exports.fetchTokenizedVault = fetchTokenizedVault;
|
|
14
|
+
exports.fetchTokenizedVaults = fetchTokenizedVaults;
|
|
15
|
+
exports.fetchTokenPrice = fetchTokenPrice;
|
|
16
|
+
exports.fetchTokenPriceByAddress = fetchTokenPriceByAddress;
|
|
17
|
+
exports.fetchTokenizedVaultLoans = fetchTokenizedVaultLoans;
|
|
18
|
+
exports.fetchTokenizedVaultSubaccountLoans = fetchTokenizedVaultSubaccountLoans;
|
|
19
|
+
exports.fetchVaultHistoricalTimeseries = fetchVaultHistoricalTimeseries;
|
|
20
|
+
exports.promiseSettle = promiseSettle;
|
|
21
|
+
const core_1 = require("./helpers/core");
|
|
22
|
+
const ethers_1 = require("ethers");
|
|
23
|
+
const abis_1 = require("../abis");
|
|
24
|
+
const lru_cache_1 = require("lru-cache");
|
|
25
|
+
const chain_address_1 = require("./helpers/chain-address");
|
|
26
|
+
const chain_error_1 = require("./helpers/chain-error");
|
|
27
|
+
const fetcher_1 = require("../services/coingecko/fetcher");
|
|
28
|
+
const logger_1 = require("./logger");
|
|
29
|
+
const ethers_2 = require("ethers");
|
|
30
|
+
const web3_1 = require("./constants/web3");
|
|
31
|
+
const core_2 = require("./constants/core");
|
|
32
|
+
const vault_version_1 = require("./helpers/vault-version");
|
|
33
|
+
const analytics_1 = require("./analytics");
|
|
34
|
+
const sanitize_1 = require("./analytics/sanitize");
|
|
35
|
+
const errors_1 = require("./errors");
|
|
36
|
+
/** Map an HTTP status to the appropriate typed SDK error subclass. */
|
|
37
|
+
function errorFromResponseStatus(status, message, options) {
|
|
38
|
+
if (status === 401) {
|
|
39
|
+
return new errors_1.AugustAuthError('AUTH_UNAUTHORIZED', message, options);
|
|
40
|
+
}
|
|
41
|
+
if (status === 403) {
|
|
42
|
+
return new errors_1.AugustAuthError('AUTH_FORBIDDEN', message, options);
|
|
43
|
+
}
|
|
44
|
+
if (status === 429) {
|
|
45
|
+
return new errors_1.AugustRateLimitError(message, options);
|
|
46
|
+
}
|
|
47
|
+
return new errors_1.AugustServerError(status, message, options);
|
|
48
|
+
}
|
|
49
|
+
let SDK_REQUEST_TIMEOUT_OVERRIDE = null;
|
|
50
|
+
/**
|
|
51
|
+
* Override the default request timeout used by every August fetcher helper
|
|
52
|
+
* when the caller doesn't supply a per-call `timeoutMs`. Pass `null` (or
|
|
53
|
+
* call with no arguments) to clear the override and fall back to the
|
|
54
|
+
* compiled-in `REQUEST_TIMEOUT_MS`.
|
|
55
|
+
*
|
|
56
|
+
* @param ms - Positive number of milliseconds to wait before aborting, or
|
|
57
|
+
* `null` to clear.
|
|
58
|
+
*/
|
|
59
|
+
function setSdkRequestTimeout(ms = null) {
|
|
60
|
+
if (ms === null) {
|
|
61
|
+
SDK_REQUEST_TIMEOUT_OVERRIDE = null;
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
if (!Number.isFinite(ms) || ms <= 0) {
|
|
65
|
+
logger_1.Logger.log.warn('setSdkRequestTimeout', 'Ignoring non-positive timeout', {
|
|
66
|
+
ms,
|
|
67
|
+
});
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
SDK_REQUEST_TIMEOUT_OVERRIDE = ms;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Read the active default request timeout — the SDK-level override if set,
|
|
74
|
+
* otherwise the compiled-in `REQUEST_TIMEOUT_MS`.
|
|
75
|
+
*/
|
|
76
|
+
function getSdkRequestTimeout() {
|
|
77
|
+
return SDK_REQUEST_TIMEOUT_OVERRIDE ?? core_2.REQUEST_TIMEOUT_MS;
|
|
78
|
+
}
|
|
79
|
+
let PUBLIC_API_BASE_OVERRIDE = null;
|
|
80
|
+
/**
|
|
81
|
+
* Override the base URL used for `WEBSERVER_URL.public` requests — the
|
|
82
|
+
* unauthenticated vault-catalog API that `getVault` / `fetchTokenizedVault`
|
|
83
|
+
* (and the other `fetchAugustPublic` callers) read from. Defaults to the
|
|
84
|
+
* compiled-in prod base (`https://api.augustdigital.io/api/v1`); pass `null`
|
|
85
|
+
* (or call with no arguments) to clear.
|
|
86
|
+
*
|
|
87
|
+
* Intended for non-prod deployments that run against an ISOLATED backend
|
|
88
|
+
* (e.g. a staging API): set it once at construction via
|
|
89
|
+
* `IAugustBase.publicApiBaseUrl` so a staging-only vault resolves. Production
|
|
90
|
+
* leaves it unset, so behaviour is unchanged.
|
|
91
|
+
*
|
|
92
|
+
* This is a process-global override on the fetcher helpers. The SDK constructor
|
|
93
|
+
* calls it on EVERY instantiation (with `null` when `publicApiBaseUrl` is
|
|
94
|
+
* omitted), so the last `AugustSDK` instantiated is authoritative — a prod
|
|
95
|
+
* instance resets it to the default even after a prior staging instance set it.
|
|
96
|
+
* An invalid or non-http(s) URL is treated as "no override": it RESETS to the
|
|
97
|
+
* compiled-in default (warned) rather than retaining a prior value, so a bad env
|
|
98
|
+
* value can neither break fetches nor silently leave a previous instance's base
|
|
99
|
+
* in place.
|
|
100
|
+
*
|
|
101
|
+
* Whenever the effective base CHANGES, the shared public-response cache is
|
|
102
|
+
* cleared, so catalog data fetched from the previous backend is never served for
|
|
103
|
+
* the new one (e.g. a prod-cached vault leaking into a staging instance). Base
|
|
104
|
+
* changes happen at construction, when the cache is cold, so this is ~free.
|
|
105
|
+
*
|
|
106
|
+
* @param url - Absolute http(s) base URL (trailing slash is trimmed). `null`, or
|
|
107
|
+
* an invalid / non-http(s) value, resets to the compiled-in public base.
|
|
108
|
+
*/
|
|
109
|
+
function setPublicApiBaseUrl(url = null) {
|
|
110
|
+
const previous = PUBLIC_API_BASE_OVERRIDE;
|
|
111
|
+
if (url === null) {
|
|
112
|
+
PUBLIC_API_BASE_OVERRIDE = null;
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
let parsed = null;
|
|
116
|
+
try {
|
|
117
|
+
parsed = new URL(url);
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
parsed = null;
|
|
121
|
+
}
|
|
122
|
+
if (!parsed ||
|
|
123
|
+
(parsed.protocol !== 'https:' && parsed.protocol !== 'http:')) {
|
|
124
|
+
// Reset to the default rather than retaining a stale prior override, so
|
|
125
|
+
// each construction stays authoritative and a bad env value fails safe to
|
|
126
|
+
// prod instead of inheriting another instance's base.
|
|
127
|
+
logger_1.Logger.log.warn('setPublicApiBaseUrl', 'Ignoring invalid/non-http(s) URL; resetting to the default public base', { url });
|
|
128
|
+
PUBLIC_API_BASE_OVERRIDE = null;
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
// Store WITHOUT a trailing slash: buildAugustUrl concatenates
|
|
132
|
+
// `${base}${relativeUrl}` (relativeUrl starts with '/'), so a trailing
|
|
133
|
+
// slash on the base would produce a double slash.
|
|
134
|
+
PUBLIC_API_BASE_OVERRIDE = url.replace(/\/+$/, '');
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
if (PUBLIC_API_BASE_OVERRIDE !== previous) {
|
|
138
|
+
// The public base moved (or reset). Drop cached public-catalog responses
|
|
139
|
+
// keyed against the previous base (see fetchTokenizedVault(s) etc.) so they
|
|
140
|
+
// aren't served for the new backend.
|
|
141
|
+
cache_1.CACHE.clear();
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Read the active base for the `public` server — the SDK-level override if set,
|
|
146
|
+
* otherwise the compiled-in `WEBSERVER_URL.public`.
|
|
147
|
+
*/
|
|
148
|
+
function getPublicApiBaseUrl() {
|
|
149
|
+
return PUBLIC_API_BASE_OVERRIDE ?? core_2.WEBSERVER_URL.public;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Combine the per-request timeout signal with any caller-supplied signal.
|
|
153
|
+
* Uses `AbortSignal.any` (Node 22+) with a manual relay fallback.
|
|
154
|
+
*
|
|
155
|
+
* Returns `timedOut()` (a closure over an internal flag set when the timeout
|
|
156
|
+
* fires) so the caller can distinguish "we timed out" from "caller cancelled",
|
|
157
|
+
* and `cleanup()` to release the fallback-relay listener.
|
|
158
|
+
*/
|
|
159
|
+
function buildRequestAbortSignal(options) {
|
|
160
|
+
const timeoutMs = options?.timeoutMs ?? SDK_REQUEST_TIMEOUT_OVERRIDE ?? core_2.REQUEST_TIMEOUT_MS;
|
|
161
|
+
const timeoutController = new AbortController();
|
|
162
|
+
let didTimeout = false;
|
|
163
|
+
const timeoutId = setTimeout(() => {
|
|
164
|
+
didTimeout = true;
|
|
165
|
+
timeoutController.abort();
|
|
166
|
+
}, timeoutMs);
|
|
167
|
+
let signal = timeoutController.signal;
|
|
168
|
+
// No-op by default; replaced with a real listener-removal closure only when
|
|
169
|
+
// the manual relay fallback path below registers an 'abort' listener.
|
|
170
|
+
let relayCleanup = () => undefined;
|
|
171
|
+
if (options?.signal) {
|
|
172
|
+
// Capture in a local so the cleanup closure below keeps the non-nullable
|
|
173
|
+
// narrowing (a closure over `options.signal` would otherwise be re-widened).
|
|
174
|
+
const callerSignal = options.signal;
|
|
175
|
+
if (typeof AbortSignal.any === 'function') {
|
|
176
|
+
signal = AbortSignal.any([timeoutController.signal, callerSignal]);
|
|
177
|
+
}
|
|
178
|
+
else if (callerSignal.aborted) {
|
|
179
|
+
timeoutController.abort();
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
const relay = () => timeoutController.abort();
|
|
183
|
+
callerSignal.addEventListener('abort', relay, { once: true });
|
|
184
|
+
relayCleanup = () => callerSignal.removeEventListener('abort', relay);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return {
|
|
188
|
+
signal,
|
|
189
|
+
timeoutId,
|
|
190
|
+
timeoutMs,
|
|
191
|
+
timedOut: () => didTimeout,
|
|
192
|
+
cleanup: () => {
|
|
193
|
+
clearTimeout(timeoutId);
|
|
194
|
+
relayCleanup();
|
|
195
|
+
},
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
let _overrideDeprecationWarned = false;
|
|
199
|
+
function warnOverrideDeprecation(callerTag) {
|
|
200
|
+
if (_overrideDeprecationWarned)
|
|
201
|
+
return;
|
|
202
|
+
_overrideDeprecationWarned = true;
|
|
203
|
+
// Deliberately a direct console.warn, not Logger.log.warn: a deprecation
|
|
204
|
+
// notice must surface in the integrator's console in every environment.
|
|
205
|
+
// Logger.log.warn would downgrade it to a prod-silent Sentry breadcrumb.
|
|
206
|
+
// biome-ignore lint/suspicious/noConsole: integrator-facing deprecation notice must surface in every environment; Logger.log.warn would downgrade it to a prod-silent Sentry breadcrumb.
|
|
207
|
+
console.warn(`[@augustdigital/sdk] ${callerTag}: option "override" is deprecated and will be removed in a future major version. Pass a valid apiKey instead.`);
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* LRU cache for API responses and frequently accessed data.
|
|
211
|
+
* 24-hour TTL with 1000 item capacity.
|
|
212
|
+
*/
|
|
213
|
+
/**
|
|
214
|
+
* Read a response header tolerantly. Real `fetch` returns a `Headers` instance,
|
|
215
|
+
* but some test mocks supply a plain object; both shapes are supported here.
|
|
216
|
+
*/
|
|
217
|
+
function readResponseHeader(headers, name) {
|
|
218
|
+
if (!headers)
|
|
219
|
+
return undefined;
|
|
220
|
+
const h = headers;
|
|
221
|
+
if (typeof h.get === 'function') {
|
|
222
|
+
return h.get(name) ?? undefined;
|
|
223
|
+
}
|
|
224
|
+
const v = headers[name];
|
|
225
|
+
return typeof v === 'string' ? v : undefined;
|
|
226
|
+
}
|
|
227
|
+
const cache_1 = require("./cache");
|
|
228
|
+
Object.defineProperty(exports, "CACHE", { enumerable: true, get: function () { return cache_1.CACHE; } });
|
|
229
|
+
Object.defineProperty(exports, "getSafeCache", { enumerable: true, get: function () { return cache_1.getSafeCache; } });
|
|
230
|
+
Object.defineProperty(exports, "setSafeCache", { enumerable: true, get: function () { return cache_1.setSafeCache; } });
|
|
231
|
+
/**
|
|
232
|
+
* Dedicated cache for token prices with short TTL to prevent rate limiting.
|
|
233
|
+
* 30-second TTL with 500 item capacity.
|
|
234
|
+
*/
|
|
235
|
+
const PRICE_CACHE = new lru_cache_1.LRUCache({
|
|
236
|
+
max: 500,
|
|
237
|
+
ttl: 1000 * 30, // 30 seconds
|
|
238
|
+
allowStale: false,
|
|
239
|
+
});
|
|
240
|
+
/**
|
|
241
|
+
* Cache for failed price requests to prevent retry storms.
|
|
242
|
+
* 5-second TTL to allow quick retry after temporary failures.
|
|
243
|
+
*/
|
|
244
|
+
const PRICE_ERROR_CACHE = new lru_cache_1.LRUCache({
|
|
245
|
+
max: 100,
|
|
246
|
+
ttl: 1000 * 5, // 5 seconds
|
|
247
|
+
allowStale: false,
|
|
248
|
+
});
|
|
249
|
+
/**
|
|
250
|
+
* In-flight price requests to prevent duplicate simultaneous API calls.
|
|
251
|
+
*/
|
|
252
|
+
const PRICE_REQUESTS = new Map();
|
|
253
|
+
/**
|
|
254
|
+
* Build an August backend URL, rejecting unknown server keys and any
|
|
255
|
+
* `relativeUrl` that would escape the configured origin.
|
|
256
|
+
* Throws `AugustValidationError` with `code: 'INVALID_URL'`.
|
|
257
|
+
*/
|
|
258
|
+
function buildAugustUrl(server, relativeUrl) {
|
|
259
|
+
const serverKey = server;
|
|
260
|
+
// The `public` base is overridable (setPublicApiBaseUrl / IAugustBase
|
|
261
|
+
// .publicApiBaseUrl) so non-prod deployments can point vault-catalog reads at
|
|
262
|
+
// an isolated backend. Resolved once here via getPublicApiBaseUrl() (single
|
|
263
|
+
// source of truth), so the origin check below validates against the OVERRIDDEN
|
|
264
|
+
// origin.
|
|
265
|
+
const base = serverKey === 'public' ? getPublicApiBaseUrl() : core_2.WEBSERVER_URL[serverKey];
|
|
266
|
+
if (!base) {
|
|
267
|
+
throw new errors_1.AugustValidationError('INVALID_URL', `Unknown August server "${String(server)}". Expected one of: ${Object.keys(core_2.WEBSERVER_URL).join(', ')}`);
|
|
268
|
+
}
|
|
269
|
+
if (typeof relativeUrl !== 'string' || relativeUrl.length === 0) {
|
|
270
|
+
throw new errors_1.AugustValidationError('INVALID_URL', 'relativeUrl must be a non-empty string');
|
|
271
|
+
}
|
|
272
|
+
// Reject anything that looks like a scheme or protocol-relative authority.
|
|
273
|
+
if (/^\s*[a-z][a-z0-9+.-]*:|^\s*\/\//i.test(relativeUrl)) {
|
|
274
|
+
throw new errors_1.AugustValidationError('INVALID_URL', `relativeUrl must be a path, not an absolute or protocol-relative URL`);
|
|
275
|
+
}
|
|
276
|
+
// Concat (rather than `new URL(rel, base)`) preserves base paths like /api/v1
|
|
277
|
+
// when relativeUrl starts with `/`. Origin check below is a second line.
|
|
278
|
+
const candidate = `${base}${relativeUrl}`;
|
|
279
|
+
let url;
|
|
280
|
+
try {
|
|
281
|
+
url = new URL(candidate);
|
|
282
|
+
}
|
|
283
|
+
catch {
|
|
284
|
+
throw new errors_1.AugustValidationError('INVALID_URL', `Invalid URL path: ${(0, sanitize_1.sanitizeString)(relativeUrl)}`);
|
|
285
|
+
}
|
|
286
|
+
const baseOrigin = new URL(base).origin;
|
|
287
|
+
if (url.origin !== baseOrigin) {
|
|
288
|
+
throw new errors_1.AugustValidationError('INVALID_URL', `URL origin mismatch: refusing to fetch ${url.origin} from a "${serverKey}" request scoped to ${baseOrigin}`);
|
|
289
|
+
}
|
|
290
|
+
return url.toString();
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Make authenticated requests to August backend services using API key.
|
|
294
|
+
* Automatically logs errors with correlation IDs for debugging.
|
|
295
|
+
* @param apiKey - August API key for authentication
|
|
296
|
+
* @param relativeUrl - Endpoint path relative to base URL
|
|
297
|
+
* @param options - Request configuration including method and headers
|
|
298
|
+
* @returns Response object if successful
|
|
299
|
+
* @throws Error with correlation ID if request fails
|
|
300
|
+
*/
|
|
301
|
+
async function fetchAugustWithKey(apiKey, relativeUrl, options) {
|
|
302
|
+
if (options?.override) {
|
|
303
|
+
warnOverrideDeprecation('fetchAugustWithKey');
|
|
304
|
+
}
|
|
305
|
+
if (!apiKey && !options?.override) {
|
|
306
|
+
throw new errors_1.AugustAuthError('AUTH_MISSING_KEY', 'fetchAugustWithKey: apiKey is required (set keys.august on the SDK constructor, or pass an explicit apiKey).');
|
|
307
|
+
}
|
|
308
|
+
const defaultHeaders = {
|
|
309
|
+
'x-api-key': apiKey,
|
|
310
|
+
'content-type': 'application/json',
|
|
311
|
+
accept: 'application/json',
|
|
312
|
+
};
|
|
313
|
+
const { signal: requestSignal, timeoutMs: effectiveTimeoutMs, timedOut, cleanup, } = buildRequestAbortSignal(options);
|
|
314
|
+
const startTime = performance.now();
|
|
315
|
+
const server = options?.server || 'production';
|
|
316
|
+
try {
|
|
317
|
+
const safeUrl = buildAugustUrl(server, relativeUrl);
|
|
318
|
+
const res = await fetch(safeUrl, {
|
|
319
|
+
headers: {
|
|
320
|
+
...defaultHeaders,
|
|
321
|
+
...options?.headers,
|
|
322
|
+
},
|
|
323
|
+
method: options?.method ?? 'GET',
|
|
324
|
+
body: JSON.stringify(options?.data),
|
|
325
|
+
signal: requestSignal,
|
|
326
|
+
});
|
|
327
|
+
cleanup();
|
|
328
|
+
// Track API call
|
|
329
|
+
(0, analytics_1.trackApiCall)(relativeUrl, options?.method ?? 'GET', startTime, res.status, server);
|
|
330
|
+
const correlationId = readResponseHeader(res.headers, 'x-correlation-id');
|
|
331
|
+
const logger = logger_1.Logger.getLogger();
|
|
332
|
+
if (!res.ok || res.status !== 200) {
|
|
333
|
+
if (correlationId && logger) {
|
|
334
|
+
logger.setTag('correlation_id', correlationId);
|
|
335
|
+
}
|
|
336
|
+
const error = errorFromResponseStatus(res.status, `Request failed: ${res.status}`, { correlationId });
|
|
337
|
+
logger?.captureException(error, { correlationId, status: res.status });
|
|
338
|
+
throw error;
|
|
339
|
+
}
|
|
340
|
+
return res;
|
|
341
|
+
}
|
|
342
|
+
catch (error) {
|
|
343
|
+
cleanup();
|
|
344
|
+
(0, analytics_1.trackApiCall)(relativeUrl, options?.method ?? 'GET', startTime, 0, server);
|
|
345
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
346
|
+
if (err.name === 'AbortError') {
|
|
347
|
+
if (!timedOut()) {
|
|
348
|
+
throw err;
|
|
349
|
+
}
|
|
350
|
+
const timeoutError = new errors_1.AugustTimeoutError((0, sanitize_1.sanitizeString)(`Request timeout after ${effectiveTimeoutMs / 1000}s: ${relativeUrl}`), effectiveTimeoutMs);
|
|
351
|
+
logger_1.Logger.log.error('fetchAugustWithKey', timeoutError, { relativeUrl });
|
|
352
|
+
throw timeoutError;
|
|
353
|
+
}
|
|
354
|
+
throw err;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* Make unauthenticated requests to August public API endpoints.
|
|
359
|
+
* Used for fetching vault metadata and public market data.
|
|
360
|
+
* @param relativeUrl - Endpoint path relative to public API base URL
|
|
361
|
+
* @param options - Request configuration including method and headers
|
|
362
|
+
* @returns Response object if successful
|
|
363
|
+
* @throws Error with correlation ID if request fails
|
|
364
|
+
*/
|
|
365
|
+
async function fetchAugustPublic(relativeUrl, options) {
|
|
366
|
+
const defaultHeaders = {
|
|
367
|
+
'content-type': 'application/json',
|
|
368
|
+
accept: 'application/json',
|
|
369
|
+
};
|
|
370
|
+
const { signal: requestSignal, timeoutMs: effectiveTimeoutMs, timedOut, cleanup, } = buildRequestAbortSignal(options);
|
|
371
|
+
const startTime = performance.now();
|
|
372
|
+
try {
|
|
373
|
+
const safeUrl = buildAugustUrl('public', relativeUrl);
|
|
374
|
+
const res = await fetch(safeUrl, {
|
|
375
|
+
headers: {
|
|
376
|
+
...defaultHeaders,
|
|
377
|
+
...options?.headers,
|
|
378
|
+
},
|
|
379
|
+
method: options?.method ?? 'GET',
|
|
380
|
+
body: JSON.stringify(options?.data),
|
|
381
|
+
signal: requestSignal,
|
|
382
|
+
});
|
|
383
|
+
cleanup();
|
|
384
|
+
(0, analytics_1.trackApiCall)(relativeUrl, options?.method ?? 'GET', startTime, res.status, 'public');
|
|
385
|
+
const correlationId = readResponseHeader(res.headers, 'x-correlation-id');
|
|
386
|
+
const logger = logger_1.Logger.getLogger();
|
|
387
|
+
if (!res.ok || res.status !== 200) {
|
|
388
|
+
if (correlationId && logger) {
|
|
389
|
+
logger.setTag('correlation_id', correlationId);
|
|
390
|
+
}
|
|
391
|
+
const error = errorFromResponseStatus(res.status, `Request failed: ${res.status}`, { correlationId });
|
|
392
|
+
logger?.captureException(error, { correlationId, status: res.status });
|
|
393
|
+
throw error;
|
|
394
|
+
}
|
|
395
|
+
return res;
|
|
396
|
+
}
|
|
397
|
+
catch (error) {
|
|
398
|
+
cleanup();
|
|
399
|
+
(0, analytics_1.trackApiCall)(relativeUrl, options?.method ?? 'GET', startTime, 0, 'public');
|
|
400
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
401
|
+
if (err.name === 'AbortError') {
|
|
402
|
+
if (!timedOut()) {
|
|
403
|
+
throw err;
|
|
404
|
+
}
|
|
405
|
+
const timeoutError = new errors_1.AugustTimeoutError((0, sanitize_1.sanitizeString)(`Request timeout after ${effectiveTimeoutMs / 1000}s: ${relativeUrl}`), effectiveTimeoutMs);
|
|
406
|
+
logger_1.Logger.log.error('fetchAugustPublic', timeoutError, { relativeUrl });
|
|
407
|
+
throw timeoutError;
|
|
408
|
+
}
|
|
409
|
+
throw err;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
413
|
+
* Make authenticated requests using Bearer token authentication.
|
|
414
|
+
* Typically used for user-specific operations requiring OAuth tokens.
|
|
415
|
+
* @param bearerToken - OAuth bearer token
|
|
416
|
+
* @param relativeUrl - Endpoint path relative to base URL
|
|
417
|
+
* @param options - Request configuration including method and headers
|
|
418
|
+
* @returns Response object if successful
|
|
419
|
+
* @throws Error with correlation ID if request fails
|
|
420
|
+
*/
|
|
421
|
+
async function fetchAugustWithBearer(bearerToken, relativeUrl, options) {
|
|
422
|
+
const defaultHeaders = {
|
|
423
|
+
authorization: `Bearer ${bearerToken}`,
|
|
424
|
+
'content-type': 'application/json',
|
|
425
|
+
accept: 'application/json',
|
|
426
|
+
};
|
|
427
|
+
const { signal: requestSignal, timeoutMs: effectiveTimeoutMs, timedOut, cleanup, } = buildRequestAbortSignal(options);
|
|
428
|
+
const startTime = performance.now();
|
|
429
|
+
const server = options?.server ?? 'production';
|
|
430
|
+
try {
|
|
431
|
+
const safeUrl = buildAugustUrl(server, relativeUrl);
|
|
432
|
+
const res = await fetch(safeUrl, {
|
|
433
|
+
headers: {
|
|
434
|
+
...defaultHeaders,
|
|
435
|
+
...options?.headers,
|
|
436
|
+
},
|
|
437
|
+
method: options?.method ?? 'GET',
|
|
438
|
+
body: JSON.stringify(options?.data),
|
|
439
|
+
signal: requestSignal,
|
|
440
|
+
});
|
|
441
|
+
cleanup();
|
|
442
|
+
(0, analytics_1.trackApiCall)(relativeUrl, options?.method ?? 'GET', startTime, res.status, server);
|
|
443
|
+
const correlationId = readResponseHeader(res.headers, 'x-correlation-id');
|
|
444
|
+
const logger = logger_1.Logger.getLogger();
|
|
445
|
+
if (!res.ok || res.status !== 200) {
|
|
446
|
+
if (correlationId && logger) {
|
|
447
|
+
logger.setTag('correlation_id', correlationId);
|
|
448
|
+
}
|
|
449
|
+
const error = errorFromResponseStatus(res.status, `Request failed: ${res.status}`, { correlationId });
|
|
450
|
+
logger?.captureException(error, { correlationId, status: res.status });
|
|
451
|
+
throw error;
|
|
452
|
+
}
|
|
453
|
+
return res;
|
|
454
|
+
}
|
|
455
|
+
catch (error) {
|
|
456
|
+
cleanup();
|
|
457
|
+
(0, analytics_1.trackApiCall)(relativeUrl, options?.method ?? 'GET', startTime, 0, server);
|
|
458
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
459
|
+
if (err.name === 'AbortError') {
|
|
460
|
+
if (!timedOut()) {
|
|
461
|
+
throw err;
|
|
462
|
+
}
|
|
463
|
+
const timeoutError = new errors_1.AugustTimeoutError((0, sanitize_1.sanitizeString)(`Request timeout after ${effectiveTimeoutMs / 1000}s: ${relativeUrl}`), effectiveTimeoutMs);
|
|
464
|
+
logger_1.Logger.log.error('fetchAugustWithBearer', timeoutError, { relativeUrl });
|
|
465
|
+
throw timeoutError;
|
|
466
|
+
}
|
|
467
|
+
throw err;
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
/**
|
|
471
|
+
* Check if an error is network-related and suitable for retry.
|
|
472
|
+
* Identifies timeouts, connection resets, and fetch failures.
|
|
473
|
+
*/
|
|
474
|
+
function isRetryableError(error) {
|
|
475
|
+
return ((error instanceof TypeError && error.message.includes('fetch failed')) ||
|
|
476
|
+
error.name === 'AbortError' ||
|
|
477
|
+
error.message.includes('ETIMEDOUT') ||
|
|
478
|
+
error.message.includes('timeout') ||
|
|
479
|
+
error.message.includes('ECONNRESET') ||
|
|
480
|
+
error.message.includes('ENOTFOUND') ||
|
|
481
|
+
error.message.includes('ECONNREFUSED'));
|
|
482
|
+
}
|
|
483
|
+
/**
|
|
484
|
+
* Wrap async operations with exponential backoff retry logic.
|
|
485
|
+
* Retries on network errors with increasing delays between attempts.
|
|
486
|
+
* @param fn - Async function to execute with retry logic
|
|
487
|
+
* @param maxRetries - Maximum number of retry attempts
|
|
488
|
+
* @param baseDelay - Initial delay in milliseconds (doubles each retry)
|
|
489
|
+
* @param shouldRetry - Custom function to determine if error is retryable
|
|
490
|
+
* @returns Result of successful function execution
|
|
491
|
+
* @throws Last error if all retries exhausted
|
|
492
|
+
*/
|
|
493
|
+
async function withRetry(fn, maxRetries = 3, baseDelay = 1000, shouldRetry = isRetryableError) {
|
|
494
|
+
let lastError;
|
|
495
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
496
|
+
try {
|
|
497
|
+
return await fn();
|
|
498
|
+
}
|
|
499
|
+
catch (error) {
|
|
500
|
+
lastError = error;
|
|
501
|
+
if (attempt < maxRetries && shouldRetry(error)) {
|
|
502
|
+
const delay = baseDelay * 2 ** attempt;
|
|
503
|
+
logger_1.Logger.log.warn('withRetry', `Attempt ${attempt + 1} failed, retrying in ${delay}ms: ${error.message}`);
|
|
504
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
505
|
+
continue;
|
|
506
|
+
}
|
|
507
|
+
throw error;
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
// Unreachable in practice: the final attempt re-throws inside the loop. This
|
|
511
|
+
// satisfies the compiler's control-flow analysis without a non-null assertion.
|
|
512
|
+
throw lastError ?? new Error('withRetry exhausted retries without an error');
|
|
513
|
+
}
|
|
514
|
+
/**
|
|
515
|
+
* Fetch tokenized vault configurations from backend API.
|
|
516
|
+
* Results are cached to reduce API calls. Optionally filter by specific vault address.
|
|
517
|
+
* @param pool - Optional vault address to filter results
|
|
518
|
+
* @param headers - Monitoring headers for request tracking
|
|
519
|
+
* @returns Array of tokenized vault configurations
|
|
520
|
+
*/
|
|
521
|
+
async function fetchTokenizedVault(pool, headers, loadSubaccounts, loadSnapshots) {
|
|
522
|
+
if (!pool) {
|
|
523
|
+
return [];
|
|
524
|
+
}
|
|
525
|
+
// Build cache key based on loading options
|
|
526
|
+
const keyParts = [`tokenized-vault-${pool}`];
|
|
527
|
+
if (loadSubaccounts === false)
|
|
528
|
+
keyParts.push('no-subaccounts');
|
|
529
|
+
if (loadSnapshots === false)
|
|
530
|
+
keyParts.push('no-snapshots');
|
|
531
|
+
const key = keyParts.join('-');
|
|
532
|
+
let tokenizedVault;
|
|
533
|
+
const cachedResponse = await (0, cache_1.getSafeCache)(key);
|
|
534
|
+
if (cachedResponse) {
|
|
535
|
+
tokenizedVault = cachedResponse;
|
|
536
|
+
}
|
|
537
|
+
if (!tokenizedVault) {
|
|
538
|
+
// Build endpoint URL with optional query parameters
|
|
539
|
+
let endpoint = core_2.WEBSERVER_ENDPOINTS.public.tokenizedVault.byVaultAddress(pool);
|
|
540
|
+
const params = new URLSearchParams();
|
|
541
|
+
if (loadSubaccounts === false) {
|
|
542
|
+
params.set('load_subaccounts', 'false');
|
|
543
|
+
}
|
|
544
|
+
if (loadSnapshots === false) {
|
|
545
|
+
params.set('load_snapshots', 'false');
|
|
546
|
+
}
|
|
547
|
+
const queryString = params.toString();
|
|
548
|
+
if (queryString) {
|
|
549
|
+
endpoint += `?${queryString}`;
|
|
550
|
+
}
|
|
551
|
+
const tokenizedVaultsResponse = await fetchAugustPublic(endpoint, {
|
|
552
|
+
headers: headers,
|
|
553
|
+
});
|
|
554
|
+
tokenizedVault = (await tokenizedVaultsResponse.json());
|
|
555
|
+
cache_1.CACHE.set(key, tokenizedVault, { ttl: 1000 * 60 * 10 }); // Cache for 10 minutes
|
|
556
|
+
}
|
|
557
|
+
// Filter by specific vault if address provided
|
|
558
|
+
if (pool &&
|
|
559
|
+
((0, ethers_1.isAddress)(pool) || (0, chain_address_1.isSolanaAddress)(pool) || (0, chain_address_1.isStellarAddress)(pool))) {
|
|
560
|
+
return tokenizedVault ? [tokenizedVault] : [];
|
|
561
|
+
}
|
|
562
|
+
return [tokenizedVault];
|
|
563
|
+
}
|
|
564
|
+
/**
|
|
565
|
+
* Fetch tokenized vault configurations from backend API.
|
|
566
|
+
* Results are cached to reduce API calls. Optionally filter by specific vault address.
|
|
567
|
+
* @param pool - Optional vault address to filter results
|
|
568
|
+
* @param headers - Monitoring headers for request tracking
|
|
569
|
+
* @param loadSubaccounts - Optional flag to load subaccounts and EOA operators (defaults to true on API)
|
|
570
|
+
* @returns Array of tokenized vault configurations
|
|
571
|
+
*/
|
|
572
|
+
async function fetchTokenizedVaults(pool, headers, loadSubaccounts, loadSnapshots) {
|
|
573
|
+
// Build cache key based on loading options
|
|
574
|
+
const keyParts = ['tokenized-vaults'];
|
|
575
|
+
if (pool)
|
|
576
|
+
keyParts.push(pool);
|
|
577
|
+
if (loadSubaccounts === false)
|
|
578
|
+
keyParts.push('no-subaccounts');
|
|
579
|
+
if (loadSnapshots === false)
|
|
580
|
+
keyParts.push('no-snapshots');
|
|
581
|
+
const key = keyParts.join('-');
|
|
582
|
+
let tokenizedVaults;
|
|
583
|
+
const cachedResponse = await (0, cache_1.getSafeCache)(key);
|
|
584
|
+
if (cachedResponse) {
|
|
585
|
+
tokenizedVaults = cachedResponse;
|
|
586
|
+
}
|
|
587
|
+
if (!tokenizedVaults) {
|
|
588
|
+
// Build endpoint URL with optional query parameters
|
|
589
|
+
let endpoint = core_2.WEBSERVER_ENDPOINTS.public.tokenizedVault.list;
|
|
590
|
+
const params = new URLSearchParams();
|
|
591
|
+
if (loadSubaccounts === false) {
|
|
592
|
+
params.set('load_subaccounts', 'false');
|
|
593
|
+
}
|
|
594
|
+
if (loadSnapshots === false) {
|
|
595
|
+
params.set('load_snapshots', 'false');
|
|
596
|
+
}
|
|
597
|
+
const queryString = params.toString();
|
|
598
|
+
if (queryString) {
|
|
599
|
+
endpoint += `?${queryString}`;
|
|
600
|
+
}
|
|
601
|
+
const tokenizedVaultsResponse = await fetchAugustPublic(endpoint, {
|
|
602
|
+
headers: headers,
|
|
603
|
+
});
|
|
604
|
+
tokenizedVaults =
|
|
605
|
+
(await tokenizedVaultsResponse.json());
|
|
606
|
+
const ttl = 1000 * 60 * 15; // 15 minute cache
|
|
607
|
+
cache_1.CACHE.set(key, tokenizedVaults, { ttl });
|
|
608
|
+
}
|
|
609
|
+
// Filter by specific vault if address provided
|
|
610
|
+
if (pool &&
|
|
611
|
+
((0, ethers_1.isAddress)(pool) || (0, chain_address_1.isSolanaAddress)(pool) || (0, chain_address_1.isStellarAddress)(pool))) {
|
|
612
|
+
const foundObj = tokenizedVaults.find((t) => t.address.toLowerCase() === pool.toLowerCase());
|
|
613
|
+
return foundObj ? [foundObj] : [];
|
|
614
|
+
}
|
|
615
|
+
return tokenizedVaults;
|
|
616
|
+
}
|
|
617
|
+
/**
|
|
618
|
+
* Fetch current USD price for a token symbol or vault LP token.
|
|
619
|
+
* For vault LP tokens, calculates share price using totalAssets/totalSupply ratio.
|
|
620
|
+
* Falls back to CoinGecko if primary source fails.
|
|
621
|
+
* @param symbol - Token symbol or contract address
|
|
622
|
+
* @param provider - Optional web3 provider for on-chain price calculations
|
|
623
|
+
* @param coinGeckoKey - Optional CoinGecko API key for fallback pricing
|
|
624
|
+
* @param headers - Monitoring headers for request tracking
|
|
625
|
+
* @returns Token price in USD
|
|
626
|
+
*/
|
|
627
|
+
async function fetchTokenPrice(symbol, provider, coinGeckoKey, headers) {
|
|
628
|
+
if (!symbol) {
|
|
629
|
+
logger_1.Logger.log.error('fetchTokenPrice', 'symbol parameter is undefined');
|
|
630
|
+
return 0;
|
|
631
|
+
}
|
|
632
|
+
// Normalize symbol and apply aliases BEFORE generating cache key
|
|
633
|
+
let normalizedSymbol = symbol.toLowerCase();
|
|
634
|
+
normalizedSymbol = normalizedSymbol === 'xbtc' ? 'btc' : normalizedSymbol;
|
|
635
|
+
normalizedSymbol = normalizedSymbol === 'strbtc' ? 'btc' : normalizedSymbol;
|
|
636
|
+
// Generate cache key based on normalized symbol and provider presence
|
|
637
|
+
const cacheKey = `price:${normalizedSymbol}:${provider ? 'with-provider' : 'no-provider'}`;
|
|
638
|
+
// Check error cache to prevent retry storms after failures
|
|
639
|
+
const cachedError = PRICE_ERROR_CACHE.get(cacheKey);
|
|
640
|
+
if (cachedError) {
|
|
641
|
+
logger_1.Logger.log.info('fetchTokenPrice', `Error cache HIT for ${normalizedSymbol} - throwing cached error`);
|
|
642
|
+
throw cachedError;
|
|
643
|
+
}
|
|
644
|
+
// Check price cache first to avoid rate limiting
|
|
645
|
+
const cachedPrice = PRICE_CACHE.get(cacheKey);
|
|
646
|
+
if (cachedPrice !== undefined) {
|
|
647
|
+
logger_1.Logger.log.info('fetchTokenPrice', `Cache HIT for ${normalizedSymbol}: $${cachedPrice}`);
|
|
648
|
+
return cachedPrice;
|
|
649
|
+
}
|
|
650
|
+
// Check for in-flight request to deduplicate simultaneous calls
|
|
651
|
+
const inflightRequest = PRICE_REQUESTS.get(cacheKey);
|
|
652
|
+
if (inflightRequest) {
|
|
653
|
+
logger_1.Logger.log.info('fetchTokenPrice', `In-flight request deduplication for ${normalizedSymbol}`);
|
|
654
|
+
return inflightRequest;
|
|
655
|
+
}
|
|
656
|
+
// Create the price fetching promise
|
|
657
|
+
const pricePromise = (async () => {
|
|
658
|
+
try {
|
|
659
|
+
const price = await _fetchTokenPriceInternal(symbol, provider, coinGeckoKey, headers);
|
|
660
|
+
// Cache the successful result
|
|
661
|
+
PRICE_CACHE.set(cacheKey, price);
|
|
662
|
+
// Clear any previous error cache on success
|
|
663
|
+
PRICE_ERROR_CACHE.delete(cacheKey);
|
|
664
|
+
return price;
|
|
665
|
+
}
|
|
666
|
+
catch (error) {
|
|
667
|
+
// Cache the error temporarily to prevent retry storms
|
|
668
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
669
|
+
PRICE_ERROR_CACHE.set(cacheKey, err);
|
|
670
|
+
logger_1.Logger.log.info('fetchTokenPrice', `Cached error for ${normalizedSymbol}: ${err.message}`);
|
|
671
|
+
throw err;
|
|
672
|
+
}
|
|
673
|
+
finally {
|
|
674
|
+
// Clean up in-flight request tracking
|
|
675
|
+
PRICE_REQUESTS.delete(cacheKey);
|
|
676
|
+
}
|
|
677
|
+
})();
|
|
678
|
+
// Track this request to prevent duplicates
|
|
679
|
+
PRICE_REQUESTS.set(cacheKey, pricePromise);
|
|
680
|
+
return pricePromise;
|
|
681
|
+
}
|
|
682
|
+
// Normalize both raw integers to the same decimal scale BEFORE dividing —
|
|
683
|
+
// dividing the raw bigints first floors the ratio to ~1 and loses all
|
|
684
|
+
// fractional precision. Returns 1 for an empty vault (priced 1:1).
|
|
685
|
+
function normalizedSharePrice(totalAssets, totalSupply, decimals) {
|
|
686
|
+
const supply = Number((0, core_1.toNormalizedBn)(totalSupply, decimals).normalized);
|
|
687
|
+
if (!supply)
|
|
688
|
+
return 1;
|
|
689
|
+
return Number((0, core_1.toNormalizedBn)(totalAssets, decimals).normalized) / supply;
|
|
690
|
+
}
|
|
691
|
+
/**
|
|
692
|
+
* Internal price fetching implementation.
|
|
693
|
+
* This is separated to allow caching and request deduplication in the public function.
|
|
694
|
+
*/
|
|
695
|
+
async function _fetchTokenPriceInternal(symbol, provider, coinGeckoKey, headers) {
|
|
696
|
+
// Fetch vault metadata to check if symbol is a vault LP token
|
|
697
|
+
const tokenizedVaults = await fetchTokenizedVaults(undefined, headers, false, false);
|
|
698
|
+
const vaultArray = tokenizedVaults.map((vault) => ({
|
|
699
|
+
vault: vault.address,
|
|
700
|
+
symbol: vault.receipt_token_symbol,
|
|
701
|
+
}));
|
|
702
|
+
const foundVaultLpAsset = vaultArray.find((v) => v.symbol?.toLowerCase() === symbol?.toLowerCase());
|
|
703
|
+
// @todo: handle multi-asset vaults
|
|
704
|
+
const tokenizedVault = tokenizedVaults.find((vault) => vault.address === foundVaultLpAsset?.vault);
|
|
705
|
+
const version = (0, vault_version_1.getVaultVersionV2)(tokenizedVault);
|
|
706
|
+
if (foundVaultLpAsset?.vault && provider && version === 'evm-2') {
|
|
707
|
+
try {
|
|
708
|
+
const vaultContract = new ethers_2.Contract((0, ethers_1.getAddress)(foundVaultLpAsset?.vault), abis_1.ABI_TOKENIZED_VAULT_V2, provider);
|
|
709
|
+
// Same bounded, no-fallback retry the write paths use for this selector
|
|
710
|
+
// (`getReceiptTokenAddressOrThrow` in `core/helpers/web3`). It cannot be
|
|
711
|
+
// reused here: `helpers/web3` imports `fetchTokenizedVault` from this
|
|
712
|
+
// module, so importing it back would be a circular dependency (CLAUDE.md
|
|
713
|
+
// §9). A transient empty `eth_call` response is absorbed; a vault that
|
|
714
|
+
// genuinely lacks `lpTokenAddress()` still falls into the catch below
|
|
715
|
+
// after the attempts are spent.
|
|
716
|
+
const receiptAddress = await (0, chain_error_1.retryOnTransientRpc)('fetchTokenPrice:receiptToken', () => vaultContract.lpTokenAddress(), { vault: foundVaultLpAsset.vault }, (error) => (0, chain_error_1.isRetryableRpcError)(error) ||
|
|
717
|
+
(0, chain_error_1.isEmptyViewResponse)(error, chain_error_1.LP_TOKEN_ADDRESS_SELECTOR));
|
|
718
|
+
const receiptContract = new ethers_2.Contract(receiptAddress, [web3_1.MIN_ABIS.decimals], provider);
|
|
719
|
+
const decimals = Number(await receiptContract.decimals());
|
|
720
|
+
const sharePrice = await vaultContract.getSharePrice();
|
|
721
|
+
return Number((0, core_1.toNormalizedBn)(sharePrice, decimals).normalized);
|
|
722
|
+
}
|
|
723
|
+
catch {
|
|
724
|
+
throw new Error('failed to fetch token price for evm-2 vault');
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
// Apply symbol normalization and aliases for API calls
|
|
728
|
+
let _symbol = symbol?.toLowerCase();
|
|
729
|
+
_symbol = _symbol === 'xbtc' ? 'btc' : _symbol;
|
|
730
|
+
_symbol = _symbol === 'strbtc' ? 'btc' : _symbol;
|
|
731
|
+
try {
|
|
732
|
+
// Fetch base token price from August backend
|
|
733
|
+
const res = await fetch(`https://prices.augustdigital.io/price/${_symbol}`, { headers: headers });
|
|
734
|
+
if (res.status !== 200) {
|
|
735
|
+
throw new Error(`fetching ${_symbol} price: ${res?.statusText}`);
|
|
736
|
+
}
|
|
737
|
+
const json = (await res.json());
|
|
738
|
+
// For vault LP tokens, calculate share price using on-chain ratio
|
|
739
|
+
if (foundVaultLpAsset && provider) {
|
|
740
|
+
const vaultContract = new ethers_2.Contract((0, ethers_1.getAddress)(foundVaultLpAsset.vault), abis_1.ABI_LENDING_POOL_V2, provider);
|
|
741
|
+
const [totalAssets, totalSupply, rawDecimals] = await Promise.all([
|
|
742
|
+
vaultContract.totalAssets(),
|
|
743
|
+
vaultContract.totalSupply(),
|
|
744
|
+
vaultContract.decimals(),
|
|
745
|
+
]);
|
|
746
|
+
const decimals = Number(rawDecimals);
|
|
747
|
+
const sharePrice = normalizedSharePrice(totalAssets, totalSupply, decimals);
|
|
748
|
+
return json.price * sharePrice;
|
|
749
|
+
}
|
|
750
|
+
return json.price;
|
|
751
|
+
}
|
|
752
|
+
catch {
|
|
753
|
+
// Fallback to CoinGecko if primary source fails
|
|
754
|
+
const fallbackPrice = await (0, fetcher_1.fetchTokenPricesFromCoinGecko)(symbol, coinGeckoKey);
|
|
755
|
+
if (foundVaultLpAsset && provider) {
|
|
756
|
+
const vaultContract = new ethers_2.Contract((0, ethers_1.getAddress)(foundVaultLpAsset.vault), abis_1.ABI_LENDING_POOL_V2, provider);
|
|
757
|
+
const [totalAssets, totalSupply, rawDecimals] = await Promise.all([
|
|
758
|
+
vaultContract.totalAssets(),
|
|
759
|
+
vaultContract.totalSupply(),
|
|
760
|
+
vaultContract.decimals(),
|
|
761
|
+
]);
|
|
762
|
+
const decimals = Number(rawDecimals);
|
|
763
|
+
const sharePrice = normalizedSharePrice(totalAssets, totalSupply, decimals);
|
|
764
|
+
return fallbackPrice * sharePrice;
|
|
765
|
+
}
|
|
766
|
+
if (fallbackPrice) {
|
|
767
|
+
return fallbackPrice;
|
|
768
|
+
}
|
|
769
|
+
else {
|
|
770
|
+
throw new Error('failed to fetch token price');
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
/**
|
|
775
|
+
* Fetch token price by contract address and chain ID from August price server.
|
|
776
|
+
* @param address - Token contract address
|
|
777
|
+
* @param chainId - Network chain ID
|
|
778
|
+
* @param headers - Optional monitoring headers for request tracking
|
|
779
|
+
* @returns Token price in USD, or 0 if not found
|
|
780
|
+
*/
|
|
781
|
+
async function fetchTokenPriceByAddress(address, chainId, headers) {
|
|
782
|
+
if (!address || !chainId) {
|
|
783
|
+
return 0;
|
|
784
|
+
}
|
|
785
|
+
try {
|
|
786
|
+
const url = new URL(`${core_2.PRICE_SERVER_URL}/price_by_address_chain`);
|
|
787
|
+
url.searchParams.set('address', address);
|
|
788
|
+
url.searchParams.set('chain', chainId.toString());
|
|
789
|
+
url.searchParams.set('method', 'contract');
|
|
790
|
+
const res = await fetch(url.toString(), {
|
|
791
|
+
headers: {
|
|
792
|
+
accept: 'application/json',
|
|
793
|
+
...headers,
|
|
794
|
+
},
|
|
795
|
+
});
|
|
796
|
+
if (res.status !== 200) {
|
|
797
|
+
throw new Error(`Failed to fetch price for ${address} on chain ${chainId}: ${res.statusText}`);
|
|
798
|
+
}
|
|
799
|
+
const json = (await res.json());
|
|
800
|
+
return json.price || 0;
|
|
801
|
+
}
|
|
802
|
+
catch (e) {
|
|
803
|
+
logger_1.Logger.log.warn('fetchTokenPriceByAddress', `Failed to fetch price for ${address} on chain ${chainId}: ${e}`);
|
|
804
|
+
return 0;
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
/**
|
|
808
|
+
* Fetch active loans for a specific vault from backend API.
|
|
809
|
+
* Results are cached per vault and chain to reduce API calls.
|
|
810
|
+
* @param pool - Vault address
|
|
811
|
+
* @param chainId - Network chain ID
|
|
812
|
+
* @param headers - Monitoring headers for request tracking
|
|
813
|
+
* @returns Array of active loan objects
|
|
814
|
+
*/
|
|
815
|
+
async function fetchTokenizedVaultLoans(pool, chainId, headers) {
|
|
816
|
+
const key = `loans-${chainId}-${pool}`;
|
|
817
|
+
let loans;
|
|
818
|
+
const cached = await (0, cache_1.getSafeCache)(key);
|
|
819
|
+
if (cached) {
|
|
820
|
+
loans = cached;
|
|
821
|
+
}
|
|
822
|
+
else {
|
|
823
|
+
const tokenizedVaultsResponse = await fetchAugustPublic(core_2.WEBSERVER_ENDPOINTS.public.tokenizedVault.loans(pool, chainId, true), { headers: headers });
|
|
824
|
+
loans = (await tokenizedVaultsResponse.json()).loans;
|
|
825
|
+
await (0, cache_1.setSafeCache)(key, loans);
|
|
826
|
+
}
|
|
827
|
+
return loans?.filter((l) => l.state.toLowerCase() === 'active');
|
|
828
|
+
}
|
|
829
|
+
/**
|
|
830
|
+
* Fetch subaccount loans for a specific tokenized vault (lending pool).
|
|
831
|
+
* Retrieves all active subaccount loan data from the backend.
|
|
832
|
+
* @param pool - Vault address
|
|
833
|
+
* @param chainId - Network chain ID
|
|
834
|
+
* @param headers - Monitoring headers for request tracking
|
|
835
|
+
* @returns Array of active subaccount loan objects
|
|
836
|
+
*/
|
|
837
|
+
async function fetchTokenizedVaultSubaccountLoans(pool, chainId, headers) {
|
|
838
|
+
const key = `subaccount-loans-${chainId}-${pool}`;
|
|
839
|
+
let loans;
|
|
840
|
+
const cached = await (0, cache_1.getSafeCache)(key);
|
|
841
|
+
if (cached) {
|
|
842
|
+
loans = cached;
|
|
843
|
+
}
|
|
844
|
+
else {
|
|
845
|
+
const tokenizedVaultsResponse = await fetchAugustPublic(core_2.WEBSERVER_ENDPOINTS.public.tokenizedVault.subaccountLoans(pool, chainId, true), { headers: headers });
|
|
846
|
+
loans = (await tokenizedVaultsResponse.json()).loans;
|
|
847
|
+
await (0, cache_1.setSafeCache)(key, loans);
|
|
848
|
+
}
|
|
849
|
+
return loans?.filter((l) => l.state.toLowerCase() === 'active');
|
|
850
|
+
}
|
|
851
|
+
/**
|
|
852
|
+
* Fetch historical timeseries data for a specific vault.
|
|
853
|
+
* Returns TVL, APY, PnL, and share price data over time.
|
|
854
|
+
* @param vaultAddress - Vault contract address
|
|
855
|
+
* @param nDays - Number of days of historical data to fetch (default 30, min 1)
|
|
856
|
+
* @param headers - Monitoring headers for request tracking
|
|
857
|
+
* @returns Historical timeseries data with date keys
|
|
858
|
+
*/
|
|
859
|
+
async function fetchVaultHistoricalTimeseries(vaultAddress, nDays, headers) {
|
|
860
|
+
const key = `vault-historical-timeseries-${vaultAddress}-${nDays}`;
|
|
861
|
+
const cachedResponse = await (0, cache_1.getSafeCache)(key);
|
|
862
|
+
if (cachedResponse) {
|
|
863
|
+
return cachedResponse;
|
|
864
|
+
}
|
|
865
|
+
const response = await fetchAugustPublic(core_2.WEBSERVER_ENDPOINTS.public.tokenizedVault.historicalTimeseries(vaultAddress, nDays), { headers: headers });
|
|
866
|
+
if (!response.ok) {
|
|
867
|
+
throw new Error(`Failed to fetch historical timeseries data: ${response.statusText}`);
|
|
868
|
+
}
|
|
869
|
+
const json = (await response.json());
|
|
870
|
+
cache_1.CACHE.set(key, json, { ttl: 1000 * 60 * 10 }); // Cache for 10 minutes
|
|
871
|
+
return json;
|
|
872
|
+
}
|
|
873
|
+
/**
|
|
874
|
+
* Execute multiple promises with retry logic and allow partial failures.
|
|
875
|
+
* Unlike Promise.all, continues execution if some promises fail.
|
|
876
|
+
* Failed promises return null to maintain array index alignment.
|
|
877
|
+
* @param promises - Array of promises to execute
|
|
878
|
+
* @param maxRetries - Maximum retry attempts per promise
|
|
879
|
+
* @param baseDelay - Initial delay for exponential backoff
|
|
880
|
+
* @returns Array of results with null for failed promises
|
|
881
|
+
*/
|
|
882
|
+
async function promiseSettle(promises, maxRetries = 3, baseDelay = 1000) {
|
|
883
|
+
const promisesWithRetry = promises.map((promise, index) => withRetry(async () => {
|
|
884
|
+
try {
|
|
885
|
+
return await promise;
|
|
886
|
+
}
|
|
887
|
+
catch (error) {
|
|
888
|
+
logger_1.Logger.log.warn('promiseSettle', `Promise at index ${index} failed`, error);
|
|
889
|
+
throw error;
|
|
890
|
+
}
|
|
891
|
+
}, maxRetries, baseDelay));
|
|
892
|
+
const results = await Promise.allSettled(promisesWithRetry);
|
|
893
|
+
return results.map((result, index) => {
|
|
894
|
+
if (result.status === 'fulfilled') {
|
|
895
|
+
return result.value;
|
|
896
|
+
}
|
|
897
|
+
else {
|
|
898
|
+
logger_1.Logger.log.warn('promiseSettle', `Promise at index ${index} failed after retries`, result.reason);
|
|
899
|
+
return null;
|
|
900
|
+
}
|
|
901
|
+
});
|
|
902
|
+
}
|
|
903
|
+
//# sourceMappingURL=fetcher.js.map
|