@upshiftfinance/sdk 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +408 -2
- 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 +953 -0
- package/lib/abis/SwapRouter.js +1228 -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 +249 -0
- package/lib/adapters/evm/index.d.ts +539 -0
- package/lib/adapters/evm/index.js +656 -0
- package/lib/adapters/evm/utils.d.ts +8 -0
- package/lib/adapters/evm/utils.js +51 -0
- package/lib/adapters/solana/confirm.d.ts +88 -0
- package/lib/adapters/solana/confirm.js +291 -0
- package/lib/adapters/solana/constants.d.ts +42 -0
- package/lib/adapters/solana/constants.js +59 -0
- package/lib/adapters/solana/getters.d.ts +42 -0
- package/lib/adapters/solana/getters.js +275 -0
- package/lib/adapters/solana/idl/vault-idl.d.ts +700 -0
- package/lib/adapters/solana/idl/vault-idl.js +2101 -0
- package/lib/adapters/solana/idl/withdrawal-queue-idl.d.ts +795 -0
- package/lib/adapters/solana/idl/withdrawal-queue-idl.js +1864 -0
- package/lib/adapters/solana/index.d.ts +372 -0
- package/lib/adapters/solana/index.js +459 -0
- package/lib/adapters/solana/pricing.d.ts +184 -0
- package/lib/adapters/solana/pricing.js +239 -0
- package/lib/adapters/solana/queue-hints.d.ts +29 -0
- package/lib/adapters/solana/queue-hints.js +59 -0
- package/lib/adapters/solana/queue.actions.d.ts +97 -0
- package/lib/adapters/solana/queue.actions.js +468 -0
- package/lib/adapters/solana/token-reads.d.ts +108 -0
- package/lib/adapters/solana/token-reads.js +145 -0
- package/lib/adapters/solana/types.d.ts +325 -0
- package/lib/adapters/solana/types.js +3 -0
- package/lib/adapters/solana/utils.d.ts +229 -0
- package/lib/adapters/solana/utils.js +773 -0
- package/lib/adapters/solana/vault.actions.d.ts +140 -0
- package/lib/adapters/solana/vault.actions.js +657 -0
- package/lib/adapters/solana/withdrawal-queue.d.ts +125 -0
- package/lib/adapters/solana/withdrawal-queue.js +301 -0
- package/lib/adapters/stellar/actions.d.ts +41 -0
- package/lib/adapters/stellar/actions.js +126 -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 +126 -0
- package/lib/adapters/stellar/index.js +187 -0
- package/lib/adapters/stellar/invocation.d.ts +55 -0
- package/lib/adapters/stellar/invocation.js +92 -0
- package/lib/adapters/stellar/soroban.d.ts +131 -0
- package/lib/adapters/stellar/soroban.js +617 -0
- package/lib/adapters/stellar/submit.d.ts +42 -0
- package/lib/adapters/stellar/submit.js +195 -0
- package/lib/adapters/stellar/types.d.ts +57 -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 +1 -0
- package/lib/adapters/sui/constants.js +9 -0
- package/lib/adapters/sui/getters.d.ts +24 -0
- package/lib/adapters/sui/getters.js +134 -0
- package/lib/adapters/sui/index.d.ts +53 -0
- package/lib/adapters/sui/index.js +96 -0
- package/lib/adapters/sui/transformer.d.ts +10 -0
- package/lib/adapters/sui/transformer.js +115 -0
- package/lib/adapters/sui/types.d.ts +70 -0
- package/lib/adapters/sui/types.js +3 -0
- package/lib/adapters/sui/utils.d.ts +8 -0
- package/lib/adapters/sui/utils.js +17 -0
- package/lib/core/analytics/app-name.d.ts +27 -0
- package/lib/core/analytics/app-name.js +48 -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 +15 -0
- package/lib/core/analytics/constants.js +28 -0
- package/lib/core/analytics/env.d.ts +46 -0
- package/lib/core/analytics/env.js +147 -0
- package/lib/core/analytics/index.d.ts +39 -0
- package/lib/core/analytics/index.js +83 -0
- package/lib/core/analytics/instrumentation.d.ts +29 -0
- package/lib/core/analytics/instrumentation.js +292 -0
- package/lib/core/analytics/method-taxonomy.d.ts +19 -0
- package/lib/core/analytics/method-taxonomy.js +156 -0
- package/lib/core/analytics/metrics.d.ts +48 -0
- package/lib/core/analytics/metrics.js +142 -0
- package/lib/core/analytics/sanitize.d.ts +57 -0
- package/lib/core/analytics/sanitize.js +272 -0
- package/lib/core/analytics/sentry-runtime.d.ts +15 -0
- package/lib/core/analytics/sentry-runtime.js +131 -0
- package/lib/core/analytics/sentry.d.ts +100 -0
- package/lib/core/analytics/sentry.js +696 -0
- package/lib/core/analytics/types.d.ts +55 -0
- package/lib/core/analytics/types.js +3 -0
- package/lib/core/analytics/user-identity.d.ts +55 -0
- package/lib/core/analytics/user-identity.js +218 -0
- package/lib/core/analytics/version.d.ts +6 -0
- package/lib/core/analytics/version.js +10 -0
- package/lib/core/attribution.d.ts +159 -0
- package/lib/core/attribution.js +194 -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 +35 -0
- package/lib/core/base.class.d.ts +193 -0
- package/lib/core/base.class.js +163 -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 +162 -0
- package/lib/core/constants/core.js +281 -0
- package/lib/core/constants/swap-router.d.ts +180 -0
- package/lib/core/constants/swap-router.js +203 -0
- package/lib/core/constants/vaults.d.ts +93 -0
- package/lib/core/constants/vaults.js +277 -0
- package/lib/core/constants/web3.d.ts +106 -0
- package/lib/core/constants/web3.js +251 -0
- package/lib/core/errors/index.d.ts +177 -0
- package/lib/core/errors/index.js +257 -0
- package/lib/core/fetcher.d.ts +237 -0
- package/lib/core/fetcher.js +1103 -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 +697 -0
- package/lib/core/helpers/chain-support.d.ts +98 -0
- package/lib/core/helpers/chain-support.js +139 -0
- package/lib/core/helpers/concurrency.d.ts +51 -0
- package/lib/core/helpers/concurrency.js +79 -0
- package/lib/core/helpers/core.d.ts +92 -0
- package/lib/core/helpers/core.js +368 -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 +61 -0
- package/lib/core/helpers/signer.js +184 -0
- package/lib/core/helpers/swap-router.d.ts +269 -0
- package/lib/core/helpers/swap-router.js +542 -0
- package/lib/core/helpers/vault-version.d.ts +24 -0
- package/lib/core/helpers/vault-version.js +83 -0
- package/lib/core/helpers/vaults.d.ts +89 -0
- package/lib/core/helpers/vaults.js +241 -0
- package/lib/core/helpers/web3.d.ts +366 -0
- package/lib/core/helpers/web3.js +1034 -0
- package/lib/core/index.d.ts +23 -0
- package/lib/core/index.js +40 -0
- package/lib/core/logger/curator-alert.d.ts +217 -0
- package/lib/core/logger/curator-alert.js +276 -0
- package/lib/core/logger/index.d.ts +99 -0
- package/lib/core/logger/index.js +163 -0
- package/lib/core/logger/slack.d.ts +49 -0
- package/lib/core/logger/slack.js +111 -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 +132 -0
- package/lib/evm/methods/crossChainVault.js +857 -0
- package/lib/evm/methods/crossChainVaultRegistry.d.ts +92 -0
- package/lib/evm/methods/crossChainVaultRegistry.js +239 -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 +596 -0
- package/lib/main.js +681 -0
- package/lib/modules/api/fetcher.d.ts +108 -0
- package/lib/modules/api/fetcher.js +187 -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 +587 -0
- package/lib/modules/api/main.js +911 -0
- package/lib/modules/sub-accounts/fetcher.d.ts +53 -0
- package/lib/modules/sub-accounts/fetcher.js +96 -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 +249 -0
- package/lib/modules/sub-accounts/main.js +211 -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 +84 -0
- package/lib/modules/vaults/adapter.helpers.js +202 -0
- package/lib/modules/vaults/fetcher.d.ts +147 -0
- package/lib/modules/vaults/fetcher.js +357 -0
- package/lib/modules/vaults/getters.d.ts +1060 -0
- package/lib/modules/vaults/getters.js +4079 -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 +607 -0
- package/lib/modules/vaults/main.js +1687 -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 +406 -0
- package/lib/modules/vaults/read.actions.js +891 -0
- package/lib/modules/vaults/types.d.ts +149 -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 +153 -0
- package/lib/modules/vaults/utils.js +818 -0
- package/lib/modules/vaults/write.actions.d.ts +812 -0
- package/lib/modules/vaults/write.actions.js +2377 -0
- package/lib/polyfills.d.ts +1 -0
- package/lib/polyfills.js +12 -0
- package/lib/sdk.d.ts +30154 -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 +50 -0
- package/lib/services/debank/utils.js +325 -0
- package/lib/services/layerzero/deposits.d.ts +55 -0
- package/lib/services/layerzero/deposits.js +174 -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 +33 -0
- package/lib/services/octavfi/fetcher.js +39 -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 +244 -0
- package/lib/services/subgraph/fetcher.d.ts +2 -0
- package/lib/services/subgraph/fetcher.js +66 -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 +48 -0
- package/lib/services/subgraph/schema.js +87 -0
- package/lib/services/subgraph/vaults.d.ts +83 -0
- package/lib/services/subgraph/vaults.js +1282 -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/services/untangled/fetcher.d.ts +40 -0
- package/lib/services/untangled/fetcher.js +110 -0
- package/lib/services/untangled/index.d.ts +3 -0
- package/lib/services/untangled/index.js +20 -0
- package/lib/services/untangled/types.d.ts +83 -0
- package/lib/services/untangled/types.js +10 -0
- package/lib/services/untangled/utils.d.ts +91 -0
- package/lib/services/untangled/utils.js +339 -0
- package/lib/types/api.d.ts +498 -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 +150 -0
- package/lib/types/sub-accounts.js +3 -0
- package/lib/types/subgraph.d.ts +84 -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 +886 -0
- package/lib/types/vaults.js +30 -0
- package/lib/types/web3.d.ts +81 -0
- package/lib/types/web3.js +14 -0
- package/lib/types/webserver.d.ts +730 -0
- package/lib/types/webserver.js +3 -0
- package/package.json +78 -3
|
@@ -0,0 +1,1282 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isOldSubgraphSchema = isOldSubgraphSchema;
|
|
4
|
+
exports.getSubgraphWithdrawRequests = getSubgraphWithdrawRequests;
|
|
5
|
+
exports.getSubgraphWithdrawProccessed = getSubgraphWithdrawProccessed;
|
|
6
|
+
exports.getSubgraphAllWithdrawals = getSubgraphAllWithdrawals;
|
|
7
|
+
exports.getSubgraphUserHistory = getSubgraphUserHistory;
|
|
8
|
+
exports.getSubgraphVaultHistory = getSubgraphVaultHistory;
|
|
9
|
+
exports.getSubgraphUserTransfers = getSubgraphUserTransfers;
|
|
10
|
+
exports.getSubgraphUserReserveDeposits = getSubgraphUserReserveDeposits;
|
|
11
|
+
const ethers_1 = require("ethers");
|
|
12
|
+
const slack_1 = require("../../core/logger/slack");
|
|
13
|
+
const fetcher_1 = require("./fetcher");
|
|
14
|
+
const schema_1 = require("./schema");
|
|
15
|
+
const core_1 = require("../../core");
|
|
16
|
+
const fetcher_2 = require("../../modules/vaults/fetcher");
|
|
17
|
+
/**
|
|
18
|
+
* Utils
|
|
19
|
+
*/
|
|
20
|
+
const GOLDSKY_API_KEY = '';
|
|
21
|
+
// Dedupe window for "Missing Subgraph" alerts (per pool).
|
|
22
|
+
const MISSING_SUBGRAPH_ALERT_TTL_MS = 60 * 60 * 1000; // 1 hour
|
|
23
|
+
/**
|
|
24
|
+
* Emit a "Missing Subgraph" Slack alert at most once per pool per TTL.
|
|
25
|
+
*
|
|
26
|
+
* `getDefaultSubgraphUrl` now returns `undefined` for vaults with no metadata or
|
|
27
|
+
* hardcoded subgraph URL, which makes the readers' `if (!goldskyUrl)` branches
|
|
28
|
+
* reachable (previously the fabricated URL was always truthy, so they were dead
|
|
29
|
+
* code). Portfolio/history flows loop over every vault, so alerting on each read
|
|
30
|
+
* would flood the webhook for every metadata-less vault. Deduping per pool
|
|
31
|
+
* surfaces a genuinely-missing subgraph without the flood.
|
|
32
|
+
*
|
|
33
|
+
* This is the durable signal for BOTH ways a vault's subgraph can be broken — no
|
|
34
|
+
* URL configured, and a URL that answers non-200 (a deleted subgraph 404s). The
|
|
35
|
+
* readers deliberately log those per-request at `warn` rather than `error`: at
|
|
36
|
+
* `error` each one became a billed Sentry issue on every portfolio read, which
|
|
37
|
+
* cost over 2M events in 30 days across a handful of vaults. The volume is
|
|
38
|
+
* per-request, but the condition is per-vault, so this alert is where it belongs.
|
|
39
|
+
*
|
|
40
|
+
* @param args.source - Reader function name, for the alert body.
|
|
41
|
+
* @param args.pool - Vault address (used as the dedupe key, lowercased).
|
|
42
|
+
* @param args.chainId - Chain id for the alert context, or a thunk resolving
|
|
43
|
+
* it. Every current caller has the id in scope and passes it directly. The
|
|
44
|
+
* thunk form exists for a caller that would otherwise have to resolve the id
|
|
45
|
+
* eagerly on every non-200 response — it is invoked only after the dedupe
|
|
46
|
+
* gate passes, so a suppressed alert costs nothing. No such caller exists
|
|
47
|
+
* today; if none appears, this union and the deferred branch below can go.
|
|
48
|
+
* @param args.reason - Why the subgraph is unusable. Defaults to the
|
|
49
|
+
* missing-URL case; pass the HTTP status for a URL that resolved but failed.
|
|
50
|
+
* @param args.slackWebookUrl - Optional override webhook URL.
|
|
51
|
+
*/
|
|
52
|
+
function alertMissingSubgraphOnce(args) {
|
|
53
|
+
const key = `missing-subgraph-alert-${args.pool.toLowerCase()}`;
|
|
54
|
+
if (core_1.CACHE.has(key))
|
|
55
|
+
return;
|
|
56
|
+
core_1.CACHE.set(key, true, { ttl: MISSING_SUBGRAPH_ALERT_TTL_MS });
|
|
57
|
+
const send = (chainId) => slack_1.SLACK.error({
|
|
58
|
+
title: 'Missing Subgraph',
|
|
59
|
+
error: `#${args.source}: ${args.reason ?? 'goldsky url is undefined'}`,
|
|
60
|
+
poolAddress: args.pool,
|
|
61
|
+
chainId,
|
|
62
|
+
slackWebookUrl: args.slackWebookUrl || '',
|
|
63
|
+
});
|
|
64
|
+
if (typeof args.chainId === 'number') {
|
|
65
|
+
send(args.chainId);
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
// Deferred id: the dedupe key is already set, so a rejection here would mute
|
|
69
|
+
// this pool for the full TTL without ever alerting. Release the key instead,
|
|
70
|
+
// leaving the next non-200 free to try again.
|
|
71
|
+
void args
|
|
72
|
+
.chainId()
|
|
73
|
+
.then(send, (e) => {
|
|
74
|
+
core_1.CACHE.delete(key);
|
|
75
|
+
core_1.Logger.log.warn('alertMissingSubgraphOnce', `chain id unresolved, alert skipped: ${e}`);
|
|
76
|
+
})
|
|
77
|
+
// `send` itself can reject (SLACK.error does its own fetch). Without this
|
|
78
|
+
// it escapes as an unhandled rejection instead of being contained here.
|
|
79
|
+
.catch((e) => {
|
|
80
|
+
core_1.Logger.log.warn('alertMissingSubgraphOnce', `alert send failed: ${e}`);
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* earnAUSD exists on both Ethereum and Monad, so it needs a _monad suffix
|
|
85
|
+
* to distinguish its Monad subgraph from the Ethereum one.
|
|
86
|
+
* Other Monad-native vaults (sausd, supermon, etc.) don't need this.
|
|
87
|
+
*/
|
|
88
|
+
function needsMonadSuffix(chainId, symbol) {
|
|
89
|
+
return chainId === 143 && symbol.toLowerCase() === 'earnausd';
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Read the decimals of every distinct deposit asset in a batch of deposit
|
|
93
|
+
* rows, keyed by lowercased token address.
|
|
94
|
+
*
|
|
95
|
+
* Pre-deposit / evm-2 vaults accept multiple deposit assets whose decimals can
|
|
96
|
+
* differ from the vault's own (e.g. RLUSD at 18 deposited into a 6-decimal
|
|
97
|
+
* sentUSD vault). `transformUserHistory` must normalize each deposit against
|
|
98
|
+
* its own asset's decimals rather than the vault's, or an 18-decimal amount
|
|
99
|
+
* normalized at 6 decimals renders ~1e12× too large (a 0.5 deposit shows as
|
|
100
|
+
* "500B"). `getDecimals` is cached and in-flight-deduped, and the distinct-asset
|
|
101
|
+
* set is tiny (typically 1-3), so this is at most a handful of RPC reads.
|
|
102
|
+
*
|
|
103
|
+
* Native-token deposits carry a sentinel `assetIn` — either the zero address or
|
|
104
|
+
* {@link NATIVE_ADDRESS} — that has no on-chain `decimals()`. These are mapped
|
|
105
|
+
* directly to {@link EVM_NATIVE_DECIMALS} (18 on every supported EVM chain)
|
|
106
|
+
* instead of being read. Without this guard `getDecimals(ZeroAddress)` returns
|
|
107
|
+
* `0`, which the caller's `?? decimals` fallback cannot override (0 is not
|
|
108
|
+
* nullish), overstating a native deposit ~1e18×; and `getDecimals(NATIVE_ADDRESS)`
|
|
109
|
+
* reverts, silently dropping to the vault's decimals which may differ.
|
|
110
|
+
*
|
|
111
|
+
* Only successfully-read decimals are entered in the map; a non-native asset
|
|
112
|
+
* whose `decimals()` read fails is omitted so the caller falls back to the
|
|
113
|
+
* vault's decimals. This also lets the vault-decimals read run in parallel with
|
|
114
|
+
* this one (no fallback value is needed up front).
|
|
115
|
+
*
|
|
116
|
+
* @param provider - EVM contract runner used to read `decimals()`.
|
|
117
|
+
* @param deposits - Deposit rows from the subgraph; `assetIn` may be absent.
|
|
118
|
+
* @returns Map of lowercased asset address to decimals (native sentinels and
|
|
119
|
+
* successful reads only).
|
|
120
|
+
*/
|
|
121
|
+
async function buildDepositAssetDecimals(provider, deposits) {
|
|
122
|
+
const map = new Map();
|
|
123
|
+
// Lowercased native-token sentinels: no ERC-20 `decimals()` exists to read.
|
|
124
|
+
const nativeSentinels = new Set([
|
|
125
|
+
ethers_1.ZeroAddress.toLowerCase(),
|
|
126
|
+
core_1.NATIVE_ADDRESS.toLowerCase(),
|
|
127
|
+
]);
|
|
128
|
+
const unique = new Set();
|
|
129
|
+
for (const d of deposits ?? []) {
|
|
130
|
+
if (d?.assetIn)
|
|
131
|
+
unique.add(d.assetIn.toLowerCase());
|
|
132
|
+
}
|
|
133
|
+
await Promise.all([...unique].map(async (addr) => {
|
|
134
|
+
if (nativeSentinels.has(addr)) {
|
|
135
|
+
map.set(addr, core_1.EVM_NATIVE_DECIMALS);
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
const dec = await (0, core_1.getDecimals)(provider, addr, false);
|
|
139
|
+
if (typeof dec === 'number')
|
|
140
|
+
map.set(addr, dec);
|
|
141
|
+
}));
|
|
142
|
+
return map;
|
|
143
|
+
}
|
|
144
|
+
function transformUserHistory(data, chainId, decimals, poolAddress, assetDecimals) {
|
|
145
|
+
//ok to return dupes even though withdraws will return dupe because we parse out duplicate txn hash on the FE
|
|
146
|
+
return [
|
|
147
|
+
...(data.withdraws?.map((item) => ({
|
|
148
|
+
...item,
|
|
149
|
+
contractId_: item.contractId_ || poolAddress,
|
|
150
|
+
address: item.receiver,
|
|
151
|
+
amount: item.assets,
|
|
152
|
+
chainId: chainId,
|
|
153
|
+
type: 'withdraw-processed',
|
|
154
|
+
transactionHash: item.transactionHash_,
|
|
155
|
+
timestamp: item.timestamp_,
|
|
156
|
+
decimals: decimals,
|
|
157
|
+
isInstant: true,
|
|
158
|
+
})) || []),
|
|
159
|
+
...(data.withdrawalRequesteds?.map((item) => ({
|
|
160
|
+
...item,
|
|
161
|
+
contractId_: item.contractId_ || poolAddress,
|
|
162
|
+
address: item.receiverAddr,
|
|
163
|
+
amount: item?.assets || item?.shares,
|
|
164
|
+
chainId: chainId,
|
|
165
|
+
type: 'withdraw-request',
|
|
166
|
+
transactionHash: item.transactionHash_,
|
|
167
|
+
timestamp: item.timestamp_,
|
|
168
|
+
decimals: decimals,
|
|
169
|
+
})) || []),
|
|
170
|
+
...(data.withdrawalProcesseds?.map((item) => ({
|
|
171
|
+
...item,
|
|
172
|
+
contractId_: item.contractId_ || poolAddress,
|
|
173
|
+
address: item.receiverAddr,
|
|
174
|
+
amount: item.assetsAmount,
|
|
175
|
+
chainId: chainId,
|
|
176
|
+
type: 'withdraw-processed',
|
|
177
|
+
transactionHash: item.transactionHash_,
|
|
178
|
+
timestamp: item.timestamp_,
|
|
179
|
+
decimals: decimals,
|
|
180
|
+
})) || []),
|
|
181
|
+
...(data.deposits?.map((item) => {
|
|
182
|
+
// Pair the decimals to the amount's denomination. `assets` (evm-1) is
|
|
183
|
+
// already in the vault's underlying, so it keeps the vault decimals.
|
|
184
|
+
// Only `amountIn` (evm-2 / pre-deposit) is denominated in `assetIn`,
|
|
185
|
+
// which may differ from the vault (e.g. RLUSD 18 → sentUSD 6) and would
|
|
186
|
+
// otherwise overstate the amount ~1e12×. Using the same source for both
|
|
187
|
+
// avoids a denomination/decimals mismatch, and the truthy `assetIn`
|
|
188
|
+
// guard drops empty-string addresses back to the vault decimals.
|
|
189
|
+
const assetKey = !item?.assets && item.assetIn ? item.assetIn.toLowerCase() : undefined;
|
|
190
|
+
return {
|
|
191
|
+
...item,
|
|
192
|
+
contractId_: item.contractId_ || poolAddress,
|
|
193
|
+
chainId: chainId,
|
|
194
|
+
type: 'deposit',
|
|
195
|
+
address: item?.sender || item?.senderAddr,
|
|
196
|
+
amount: item?.assets || item?.amountIn,
|
|
197
|
+
transactionHash: item.transactionHash_,
|
|
198
|
+
timestamp: item.timestamp_,
|
|
199
|
+
decimals: (assetKey ? assetDecimals?.get(assetKey) : undefined) ?? decimals,
|
|
200
|
+
};
|
|
201
|
+
}) || []),
|
|
202
|
+
];
|
|
203
|
+
}
|
|
204
|
+
function sortUserHistory(data, chainId, decimals, poolAddress, assetDecimals) {
|
|
205
|
+
if (!(data && chainId && decimals))
|
|
206
|
+
return [];
|
|
207
|
+
return transformUserHistory(data, chainId, decimals, poolAddress, assetDecimals).sort((a, b) => Number(a.timestamp_) - Number(b.timestamp_));
|
|
208
|
+
}
|
|
209
|
+
// queries
|
|
210
|
+
const WITHDRAWALS_REQUESTED_QUERY_PROPS = `
|
|
211
|
+
id
|
|
212
|
+
day
|
|
213
|
+
month
|
|
214
|
+
year
|
|
215
|
+
shares
|
|
216
|
+
assets
|
|
217
|
+
receiverAddr
|
|
218
|
+
ownerAddr
|
|
219
|
+
block_number
|
|
220
|
+
timestamp_
|
|
221
|
+
transactionHash_
|
|
222
|
+
contractId_
|
|
223
|
+
`;
|
|
224
|
+
const EVM_V2_WITHDRAWALS_REQUESTED_QUERY_PROPS = `
|
|
225
|
+
id
|
|
226
|
+
shares
|
|
227
|
+
receiverAddr
|
|
228
|
+
holderAddr
|
|
229
|
+
block_number
|
|
230
|
+
timestamp_
|
|
231
|
+
transactionHash_
|
|
232
|
+
contractId_
|
|
233
|
+
`;
|
|
234
|
+
const WITHDRAWALS_QUERY_PROPS = `
|
|
235
|
+
id
|
|
236
|
+
transactionHash_
|
|
237
|
+
timestamp_
|
|
238
|
+
block_number
|
|
239
|
+
contractId_
|
|
240
|
+
assets
|
|
241
|
+
receiver
|
|
242
|
+
sender
|
|
243
|
+
`;
|
|
244
|
+
const EVM_V2_WITHDRAWALS_QUERY_PROPS = `
|
|
245
|
+
id
|
|
246
|
+
transactionHash_
|
|
247
|
+
timestamp_
|
|
248
|
+
block_number
|
|
249
|
+
contractId_
|
|
250
|
+
assets
|
|
251
|
+
receiver
|
|
252
|
+
sender
|
|
253
|
+
shares
|
|
254
|
+
owner
|
|
255
|
+
`;
|
|
256
|
+
const WITHDRAWALS_PROCESSED_QUERY_PROPS = `
|
|
257
|
+
id
|
|
258
|
+
processedOn
|
|
259
|
+
requestedOn
|
|
260
|
+
receiverAddr
|
|
261
|
+
assetsAmount
|
|
262
|
+
block_number
|
|
263
|
+
timestamp_
|
|
264
|
+
contractId_
|
|
265
|
+
transactionHash_
|
|
266
|
+
`;
|
|
267
|
+
const EVM_V2_WITHDRAWALS_PROCESSED_QUERY_PROPS = `
|
|
268
|
+
id
|
|
269
|
+
receiverAddr
|
|
270
|
+
assetsAmount
|
|
271
|
+
block_number
|
|
272
|
+
timestamp_
|
|
273
|
+
contractId_
|
|
274
|
+
transactionHash_
|
|
275
|
+
`;
|
|
276
|
+
const DEPOSIT_QUERY_PROPS = `
|
|
277
|
+
id
|
|
278
|
+
assets
|
|
279
|
+
transactionHash_
|
|
280
|
+
timestamp_
|
|
281
|
+
contractId_
|
|
282
|
+
sender
|
|
283
|
+
shares
|
|
284
|
+
owner
|
|
285
|
+
`;
|
|
286
|
+
const EVM_V2_DEPOSIT_QUERY_PROPS = `
|
|
287
|
+
id
|
|
288
|
+
assetIn
|
|
289
|
+
amountIn
|
|
290
|
+
transactionHash_
|
|
291
|
+
timestamp_
|
|
292
|
+
contractId_
|
|
293
|
+
senderAddr
|
|
294
|
+
receiverAddr
|
|
295
|
+
`;
|
|
296
|
+
// New deployment process uses a different subgraph schema (no trailing underscores).
|
|
297
|
+
// Vaults in SUBGRAPH_VAULT_URLS use the old schema; everything else uses the new schema.
|
|
298
|
+
// GraphQL aliases map new-schema fields to what the SDK expects internally.
|
|
299
|
+
function isOldSubgraphSchema(vaultSymbol) {
|
|
300
|
+
return (vaultSymbol?.toLowerCase() in
|
|
301
|
+
core_1.SUBGRAPH_VAULT_URLS);
|
|
302
|
+
}
|
|
303
|
+
// New schema query props (shared across evm-1 and evm-2 — the new subgraph schema
|
|
304
|
+
// normalized field names, so no per-version variants are needed)
|
|
305
|
+
const NEW_DEPOSIT_QUERY_PROPS = `
|
|
306
|
+
id
|
|
307
|
+
assetIn
|
|
308
|
+
amountIn
|
|
309
|
+
transactionHash_: transactionHash
|
|
310
|
+
timestamp_: blockTimestamp
|
|
311
|
+
senderAddr
|
|
312
|
+
receiverAddr
|
|
313
|
+
`;
|
|
314
|
+
// The `block_number: blockNumber` alias on these new-schema withdrawal prop
|
|
315
|
+
// sets is required, not cosmetic: getWithdrawalRequestsWithStatus prunes by
|
|
316
|
+
// `Number(req.block_number) >= blockCutoff` (per the ISubgraphBase contract).
|
|
317
|
+
// New-schema subgraphs expose the field as `blockNumber`, so without the alias
|
|
318
|
+
// it reads undefined → Number(undefined) is NaN → every request is pruned
|
|
319
|
+
// (AUGUST-6514). Only the REQUESTED set is read today; the processed/withdrawals
|
|
320
|
+
// aliases below are kept for the same type contract so the NaN prune can't recur.
|
|
321
|
+
const NEW_WITHDRAWALS_REQUESTED_QUERY_PROPS = `
|
|
322
|
+
id
|
|
323
|
+
shares
|
|
324
|
+
receiverAddr
|
|
325
|
+
holderAddr
|
|
326
|
+
block_number: blockNumber
|
|
327
|
+
transactionHash_: transactionHash
|
|
328
|
+
timestamp_: blockTimestamp
|
|
329
|
+
`;
|
|
330
|
+
const NEW_WITHDRAWALS_PROCESSED_QUERY_PROPS = `
|
|
331
|
+
id
|
|
332
|
+
receiverAddr
|
|
333
|
+
assetsAmount
|
|
334
|
+
block_number: blockNumber
|
|
335
|
+
transactionHash_: transactionHash
|
|
336
|
+
timestamp_: blockTimestamp
|
|
337
|
+
`;
|
|
338
|
+
const NEW_WITHDRAWALS_QUERY_PROPS = `
|
|
339
|
+
id
|
|
340
|
+
transactionHash_: transactionHash
|
|
341
|
+
timestamp_: blockTimestamp
|
|
342
|
+
block_number: blockNumber
|
|
343
|
+
assets
|
|
344
|
+
receiver
|
|
345
|
+
sender
|
|
346
|
+
shares
|
|
347
|
+
owner
|
|
348
|
+
`;
|
|
349
|
+
// New schema: transfer query props
|
|
350
|
+
const NEW_TRANSFER_QUERY_PROPS = `
|
|
351
|
+
id
|
|
352
|
+
from
|
|
353
|
+
to
|
|
354
|
+
value
|
|
355
|
+
transactionHash_: transactionHash
|
|
356
|
+
timestamp_: blockTimestamp
|
|
357
|
+
block_number: blockNumber
|
|
358
|
+
`;
|
|
359
|
+
const TRANSFER_QUERY_PROPS = `
|
|
360
|
+
id
|
|
361
|
+
from
|
|
362
|
+
to
|
|
363
|
+
value
|
|
364
|
+
transactionHash_
|
|
365
|
+
timestamp_
|
|
366
|
+
block_number
|
|
367
|
+
contractId_
|
|
368
|
+
`;
|
|
369
|
+
/**
|
|
370
|
+
* Goldsky caps every list field at 1000 rows per request, so a busy vault's
|
|
371
|
+
* withdrawal entities silently truncate unless we page on `skip`. Both bounds
|
|
372
|
+
* are shared by every withdrawal reader below.
|
|
373
|
+
*/
|
|
374
|
+
const WITHDRAWAL_PAGE_SIZE = 1000;
|
|
375
|
+
/**
|
|
376
|
+
* Upper bound on pages fetched per withdrawal reader (20 × 1000 = 20 000 rows
|
|
377
|
+
* per entity). A vault past this bound is logged and returns the rows gathered
|
|
378
|
+
* so far rather than looping on a subgraph that keeps reporting full pages.
|
|
379
|
+
*/
|
|
380
|
+
const WITHDRAWAL_MAX_PAGES = 20;
|
|
381
|
+
/**
|
|
382
|
+
* Page a withdrawal query on `skip` until every requested entity returns a
|
|
383
|
+
* short page (fewer than {@link WITHDRAWAL_PAGE_SIZE} rows).
|
|
384
|
+
*
|
|
385
|
+
* Why: `withdrawalRequesteds` / `withdrawalProcesseds` were previously read
|
|
386
|
+
* with a single `first: 1000` request, so vaults with more than 1000 events
|
|
387
|
+
* lost their oldest rows (and `getWithdrawalRequestsWithStatus` under-counted
|
|
388
|
+
* pending requests). Mirrors the lockstep paging in
|
|
389
|
+
* {@link getSubgraphVaultHistory}; ordering is whatever `buildQuery` encodes
|
|
390
|
+
* (newest-first), and pages are concatenated in fetch order so the result
|
|
391
|
+
* stays sorted.
|
|
392
|
+
*
|
|
393
|
+
* @param source - Caller name for log attribution.
|
|
394
|
+
* @param goldskyUrl - Subgraph endpoint.
|
|
395
|
+
* @param buildQuery - Renders the GraphQL document for one page. Every entity
|
|
396
|
+
* in `entityKeys` must carry `first: pageSize, skip: skip`.
|
|
397
|
+
* @param entityKeys - Top-level `data` keys to accumulate across pages.
|
|
398
|
+
* @returns The first page's HTTP status (so callers keep their existing
|
|
399
|
+
* non-200 warn/alert path) plus the accumulated rows per entity. A later
|
|
400
|
+
* page failing is logged and the rows gathered so far are returned.
|
|
401
|
+
*
|
|
402
|
+
* RPC budget: 1 request per 1000 rows of the largest entity, capped at
|
|
403
|
+
* {@link WITHDRAWAL_MAX_PAGES} requests.
|
|
404
|
+
*/
|
|
405
|
+
async function fetchPagedWithdrawals(source, goldskyUrl, buildQuery, entityKeys) {
|
|
406
|
+
const data = Object.fromEntries(entityKeys.map((key) => [key, []]));
|
|
407
|
+
let skip = 0;
|
|
408
|
+
for (let page = 0; page < WITHDRAWAL_MAX_PAGES; page++) {
|
|
409
|
+
const result = await (0, fetcher_1.fetchSubgraph)(goldskyUrl, buildQuery(WITHDRAWAL_PAGE_SIZE, skip), GOLDSKY_API_KEY);
|
|
410
|
+
if (result.status !== 200) {
|
|
411
|
+
// First page failing is the caller's existing error path; a later page
|
|
412
|
+
// failing still yields whatever earlier pages accumulated.
|
|
413
|
+
if (skip === 0) {
|
|
414
|
+
return { status: result.status, statusText: result.statusText, data };
|
|
415
|
+
}
|
|
416
|
+
core_1.Logger.log.warn(source, `${result.statusText}::${result.status}: page fetch failed, returning partial rows`, { skip });
|
|
417
|
+
break;
|
|
418
|
+
}
|
|
419
|
+
const json = (await result.json());
|
|
420
|
+
let needMore = false;
|
|
421
|
+
for (const key of entityKeys) {
|
|
422
|
+
const rows = json?.data?.[key] ?? [];
|
|
423
|
+
data[key].push(...rows);
|
|
424
|
+
if (rows.length === WITHDRAWAL_PAGE_SIZE)
|
|
425
|
+
needMore = true;
|
|
426
|
+
}
|
|
427
|
+
if (!needMore)
|
|
428
|
+
break;
|
|
429
|
+
skip += WITHDRAWAL_PAGE_SIZE;
|
|
430
|
+
if (page === WITHDRAWAL_MAX_PAGES - 1) {
|
|
431
|
+
core_1.Logger.log.warn(source, `hit the ${WITHDRAWAL_MAX_PAGES}-page cap; older withdrawal rows were not fetched`, { skip });
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
return { status: 200, statusText: 'OK', data };
|
|
435
|
+
}
|
|
436
|
+
/**
|
|
437
|
+
*
|
|
438
|
+
* @param pool
|
|
439
|
+
* @param provider
|
|
440
|
+
* @returns
|
|
441
|
+
*/
|
|
442
|
+
async function getSubgraphWithdrawRequests(pool, provider, slackWebookUrl = (0, slack_1.resolveSlackWebhookUrl)()) {
|
|
443
|
+
// setup
|
|
444
|
+
let vaultSymbol = await (0, core_1.getVaultSymbol)(pool, provider);
|
|
445
|
+
if (vaultSymbol === undefined) {
|
|
446
|
+
core_1.Logger.log.warn('getSubgraphWithdrawRequests', `cannot find vault symbol for pool: ${pool}`);
|
|
447
|
+
return [];
|
|
448
|
+
}
|
|
449
|
+
const networkValue = await provider.provider.getNetwork();
|
|
450
|
+
const network = Number(networkValue.chainId);
|
|
451
|
+
if (needsMonadSuffix(network, vaultSymbol)) {
|
|
452
|
+
vaultSymbol = vaultSymbol.concat('_monad');
|
|
453
|
+
}
|
|
454
|
+
// sanitize
|
|
455
|
+
if (vaultSymbol === 'testWETHTSA') {
|
|
456
|
+
return [];
|
|
457
|
+
}
|
|
458
|
+
const vaultsMetadata = await (0, fetcher_2.fetchVaultMetadata)();
|
|
459
|
+
const { subgraph } = vaultsMetadata?.[vaultSymbol?.toLowerCase()] || {};
|
|
460
|
+
const goldskyUrl = subgraph ||
|
|
461
|
+
core_1.SUBGRAPH_VAULT_URLS[vaultSymbol?.toLowerCase()] ||
|
|
462
|
+
(0, core_1.getDefaultSubgraphUrl)(networkValue.name, vaultSymbol);
|
|
463
|
+
const requests = [];
|
|
464
|
+
if (!goldskyUrl) {
|
|
465
|
+
const chainId = await (0, core_1.getChainId)(provider);
|
|
466
|
+
core_1.Logger.log.warn('getSubgraphWithdrawRequests', `goldsky url is undefined: ${vaultSymbol}::${pool}`);
|
|
467
|
+
alertMissingSubgraphOnce({
|
|
468
|
+
source: 'getSubgraphWithdrawRequests',
|
|
469
|
+
pool,
|
|
470
|
+
chainId,
|
|
471
|
+
slackWebookUrl,
|
|
472
|
+
});
|
|
473
|
+
return [];
|
|
474
|
+
}
|
|
475
|
+
const tokenizedVault = (await (0, core_1.fetchTokenizedVault)(pool, undefined, false, false))?.[0];
|
|
476
|
+
const version = (0, core_1.getVaultVersionV2)(tokenizedVault);
|
|
477
|
+
// Probe the deployed subgraph to learn its actual field schema (cached per
|
|
478
|
+
// URL) instead of guessing from the vault symbol. See resolveSubgraphSchema —
|
|
479
|
+
// the old symbol-map heuristic silently emptied this set for vaults deployed
|
|
480
|
+
// on the old template but absent from SUBGRAPH_VAULT_URLS (AUGUST-6568).
|
|
481
|
+
const useOldSchema = (await (0, schema_1.resolveSubgraphSchema)(goldskyUrl, GOLDSKY_API_KEY)) === 'old';
|
|
482
|
+
const orderByTimestamp = useOldSchema ? 'timestamp_' : 'blockTimestamp';
|
|
483
|
+
const withdrawalRequestedProps = useOldSchema
|
|
484
|
+
? version === 'evm-2'
|
|
485
|
+
? EVM_V2_WITHDRAWALS_REQUESTED_QUERY_PROPS
|
|
486
|
+
: WITHDRAWALS_REQUESTED_QUERY_PROPS
|
|
487
|
+
: NEW_WITHDRAWALS_REQUESTED_QUERY_PROPS;
|
|
488
|
+
const result = await fetchPagedWithdrawals('getSubgraphWithdrawRequests', goldskyUrl, (pageSize, skip) => `{
|
|
489
|
+
withdrawalRequesteds(
|
|
490
|
+
first: ${pageSize},
|
|
491
|
+
skip: ${skip},
|
|
492
|
+
orderBy: ${orderByTimestamp},
|
|
493
|
+
orderDirection: desc,
|
|
494
|
+
) {
|
|
495
|
+
${withdrawalRequestedProps}
|
|
496
|
+
}
|
|
497
|
+
}`, ['withdrawalRequesteds']);
|
|
498
|
+
if (result.status !== 200) {
|
|
499
|
+
core_1.Logger.log.warn('getSubgraphWithdrawRequests', `${result.statusText}::${result.status}: ${vaultSymbol}::${pool}`);
|
|
500
|
+
alertMissingSubgraphOnce({
|
|
501
|
+
source: 'getSubgraphWithdrawRequests',
|
|
502
|
+
pool,
|
|
503
|
+
// Already resolved at the top of this function — no re-fetch, and the
|
|
504
|
+
// alert fires synchronously.
|
|
505
|
+
chainId: network,
|
|
506
|
+
reason: `subgraph returned ${result.status} ${result.statusText}`,
|
|
507
|
+
slackWebookUrl,
|
|
508
|
+
});
|
|
509
|
+
return [];
|
|
510
|
+
}
|
|
511
|
+
requests.push(...result.data.withdrawalRequesteds);
|
|
512
|
+
return requests;
|
|
513
|
+
}
|
|
514
|
+
async function getSubgraphWithdrawProccessed(pool, provider, slackWebookUrl = (0, slack_1.resolveSlackWebhookUrl)()) {
|
|
515
|
+
try {
|
|
516
|
+
// setup
|
|
517
|
+
let vaultSymbol = await (0, core_1.getVaultSymbol)(pool, provider);
|
|
518
|
+
if (vaultSymbol === undefined) {
|
|
519
|
+
core_1.Logger.log.warn('getSubgraphWithdrawProccessed', `cannot find vault symbol for pool: ${pool}`);
|
|
520
|
+
return [];
|
|
521
|
+
}
|
|
522
|
+
const networkValue = await provider.provider.getNetwork();
|
|
523
|
+
const network = Number(networkValue.chainId);
|
|
524
|
+
if (needsMonadSuffix(network, vaultSymbol)) {
|
|
525
|
+
vaultSymbol = vaultSymbol.concat('_monad');
|
|
526
|
+
}
|
|
527
|
+
const noWithdrawalProcessed = vaultSymbol === 'agETH';
|
|
528
|
+
// sanitize
|
|
529
|
+
if (vaultSymbol === 'testWETHTSA' || noWithdrawalProcessed) {
|
|
530
|
+
return [];
|
|
531
|
+
}
|
|
532
|
+
const vaultsMetadata = await (0, fetcher_2.fetchVaultMetadata)();
|
|
533
|
+
const { subgraph } = vaultsMetadata?.[vaultSymbol?.toLowerCase()] || {};
|
|
534
|
+
const goldskyUrl = subgraph ||
|
|
535
|
+
core_1.SUBGRAPH_VAULT_URLS[vaultSymbol?.toLowerCase()] ||
|
|
536
|
+
(0, core_1.getDefaultSubgraphUrl)(networkValue.name, vaultSymbol);
|
|
537
|
+
const requests = [];
|
|
538
|
+
if (!goldskyUrl) {
|
|
539
|
+
const chainId = await (0, core_1.getChainId)(provider);
|
|
540
|
+
core_1.Logger.log.warn('getSubgraphWithdrawProccessed.missing-subgraph-url', `goldsky url is undefined: ${vaultSymbol}::${pool}`, { chainId });
|
|
541
|
+
alertMissingSubgraphOnce({
|
|
542
|
+
source: 'getSubgraphWithdrawProccessed',
|
|
543
|
+
pool,
|
|
544
|
+
chainId,
|
|
545
|
+
slackWebookUrl,
|
|
546
|
+
});
|
|
547
|
+
return [];
|
|
548
|
+
}
|
|
549
|
+
const tokenizedVault = (await (0, core_1.fetchTokenizedVault)(pool, undefined, false, false))?.[0];
|
|
550
|
+
const version = (0, core_1.getVaultVersionV2)(tokenizedVault);
|
|
551
|
+
// Probe the deployed subgraph's actual field schema (cached per URL) rather
|
|
552
|
+
// than guessing from the vault symbol — see resolveSubgraphSchema (AUGUST-6568).
|
|
553
|
+
const useOldSchema = (await (0, schema_1.resolveSubgraphSchema)(goldskyUrl, GOLDSKY_API_KEY)) === 'old';
|
|
554
|
+
const orderByTimestamp = useOldSchema ? 'timestamp_' : 'blockTimestamp';
|
|
555
|
+
const withdrawalProcessedProps = useOldSchema
|
|
556
|
+
? version === 'evm-2'
|
|
557
|
+
? EVM_V2_WITHDRAWALS_PROCESSED_QUERY_PROPS
|
|
558
|
+
: WITHDRAWALS_PROCESSED_QUERY_PROPS
|
|
559
|
+
: NEW_WITHDRAWALS_PROCESSED_QUERY_PROPS;
|
|
560
|
+
const result = await fetchPagedWithdrawals('getSubgraphWithdrawProccessed', goldskyUrl, (pageSize, skip) => `{
|
|
561
|
+
withdrawalProcesseds (
|
|
562
|
+
first: ${pageSize},
|
|
563
|
+
skip: ${skip},
|
|
564
|
+
orderBy: ${orderByTimestamp},
|
|
565
|
+
orderDirection: desc,
|
|
566
|
+
) {
|
|
567
|
+
${withdrawalProcessedProps}
|
|
568
|
+
}
|
|
569
|
+
}`, ['withdrawalProcesseds']);
|
|
570
|
+
if (result.status !== 200) {
|
|
571
|
+
core_1.Logger.log.warn('getSubgraphWithdrawProccessed', `${result.statusText}::${result.status}: ${vaultSymbol}::${pool}`);
|
|
572
|
+
alertMissingSubgraphOnce({
|
|
573
|
+
source: 'getSubgraphWithdrawProccessed',
|
|
574
|
+
pool,
|
|
575
|
+
// Already resolved at the top of this function — no re-fetch, and the
|
|
576
|
+
// alert fires synchronously.
|
|
577
|
+
chainId: network,
|
|
578
|
+
reason: `subgraph returned ${result.status} ${result.statusText}`,
|
|
579
|
+
slackWebookUrl,
|
|
580
|
+
});
|
|
581
|
+
return [];
|
|
582
|
+
}
|
|
583
|
+
requests.push(...result.data.withdrawalProcesseds);
|
|
584
|
+
return requests;
|
|
585
|
+
}
|
|
586
|
+
catch (e) {
|
|
587
|
+
core_1.Logger.log.error('getSubgraphWithdrawProccessed', e, { pool });
|
|
588
|
+
return [];
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
/**
|
|
592
|
+
* Fetch a vault's `withdrawalRequesteds` and `withdrawalProcesseds` from its
|
|
593
|
+
* Goldsky subgraph in one paged query.
|
|
594
|
+
*
|
|
595
|
+
* Without `receiver`, every wallet's rows are returned (up to the page cap) —
|
|
596
|
+
* on busy vaults that is ~0.9 MB per call. Pass `receiver` when the caller only
|
|
597
|
+
* needs one wallet's rows: both entities are then filtered server-side with
|
|
598
|
+
* `where: { receiverAddr }` (the same filter {@link getSubgraphUserHistory}
|
|
599
|
+
* uses), which shrinks the response to that wallet's rows (AUGUST-8317).
|
|
600
|
+
*
|
|
601
|
+
* Side effects: one schema probe per subgraph URL (cached) plus one Goldsky
|
|
602
|
+
* POST per 1,000-row page.
|
|
603
|
+
*
|
|
604
|
+
* @param pool - Vault contract address.
|
|
605
|
+
* @param provider - Contract runner, used to resolve the vault symbol/network.
|
|
606
|
+
* @param options - Optional settings.
|
|
607
|
+
* @param options.slackWebookUrl - Webhook for missing-subgraph alerts.
|
|
608
|
+
* Defaults to {@link resolveSlackWebhookUrl}.
|
|
609
|
+
* @param options.receiver - Optional wallet; when a valid EVM address, only
|
|
610
|
+
* rows whose `receiverAddr` matches it (case-insensitive) are fetched.
|
|
611
|
+
* @returns Both entity lists, newest first. Empty lists on any failure.
|
|
612
|
+
*/
|
|
613
|
+
async function getSubgraphAllWithdrawals(pool, provider, { slackWebookUrl = (0, slack_1.resolveSlackWebhookUrl)(), receiver, } = {}) {
|
|
614
|
+
let query = '';
|
|
615
|
+
try {
|
|
616
|
+
// setup
|
|
617
|
+
const errorReturnObj = {
|
|
618
|
+
withdrawalRequesteds: [],
|
|
619
|
+
withdrawalProcesseds: [],
|
|
620
|
+
};
|
|
621
|
+
let vaultSymbol = await (0, core_1.getVaultSymbol)(pool, provider);
|
|
622
|
+
if (vaultSymbol === undefined) {
|
|
623
|
+
core_1.Logger.log.warn('getSubgraphAllWithdrawals', `cannot find vault symbol for pool: ${pool}`);
|
|
624
|
+
return errorReturnObj;
|
|
625
|
+
}
|
|
626
|
+
const networkValue = await provider.provider.getNetwork();
|
|
627
|
+
const network = Number(networkValue.chainId);
|
|
628
|
+
if (needsMonadSuffix(network, vaultSymbol)) {
|
|
629
|
+
vaultSymbol = vaultSymbol.concat('_monad');
|
|
630
|
+
}
|
|
631
|
+
const noWithdrawalProcessed = vaultSymbol === 'agETH';
|
|
632
|
+
// sanitize
|
|
633
|
+
if (vaultSymbol === 'testWETHTSA') {
|
|
634
|
+
return errorReturnObj;
|
|
635
|
+
}
|
|
636
|
+
const vaultsMetadata = await (0, fetcher_2.fetchVaultMetadata)();
|
|
637
|
+
const { subgraph } = vaultsMetadata?.[vaultSymbol?.toLowerCase()] || {};
|
|
638
|
+
const goldskyUrl = subgraph ||
|
|
639
|
+
core_1.SUBGRAPH_VAULT_URLS[vaultSymbol?.toLowerCase()] ||
|
|
640
|
+
(0, core_1.getDefaultSubgraphUrl)(networkValue.name, vaultSymbol);
|
|
641
|
+
if (!goldskyUrl) {
|
|
642
|
+
const chainId = await (0, core_1.getChainId)(provider);
|
|
643
|
+
core_1.Logger.log.warn('getSubgraphAllWithdrawals', `goldsky url is undefined: ${vaultSymbol}::${pool}`);
|
|
644
|
+
alertMissingSubgraphOnce({
|
|
645
|
+
source: 'getSubgraphAllWithdrawals',
|
|
646
|
+
pool,
|
|
647
|
+
chainId,
|
|
648
|
+
slackWebookUrl,
|
|
649
|
+
});
|
|
650
|
+
return errorReturnObj;
|
|
651
|
+
}
|
|
652
|
+
const tokenizedVault = (await (0, core_1.fetchTokenizedVault)(pool, undefined, false, false))?.[0];
|
|
653
|
+
const version = (0, core_1.getVaultVersionV2)(tokenizedVault);
|
|
654
|
+
// Probe the deployed subgraph's actual field schema (cached per URL) rather
|
|
655
|
+
// than guessing from the vault symbol — see resolveSubgraphSchema (AUGUST-6568).
|
|
656
|
+
const useOldSchema = (await (0, schema_1.resolveSubgraphSchema)(goldskyUrl, GOLDSKY_API_KEY)) === 'old';
|
|
657
|
+
const orderByTimestamp = useOldSchema ? 'timestamp_' : 'blockTimestamp';
|
|
658
|
+
const withdrawalRequestedProps = useOldSchema
|
|
659
|
+
? version === 'evm-2'
|
|
660
|
+
? EVM_V2_WITHDRAWALS_REQUESTED_QUERY_PROPS
|
|
661
|
+
: WITHDRAWALS_REQUESTED_QUERY_PROPS
|
|
662
|
+
: NEW_WITHDRAWALS_REQUESTED_QUERY_PROPS;
|
|
663
|
+
const withdrawalProcessedProps = useOldSchema
|
|
664
|
+
? version === 'evm-2'
|
|
665
|
+
? EVM_V2_WITHDRAWALS_PROCESSED_QUERY_PROPS
|
|
666
|
+
: WITHDRAWALS_PROCESSED_QUERY_PROPS
|
|
667
|
+
: NEW_WITHDRAWALS_PROCESSED_QUERY_PROPS;
|
|
668
|
+
// Subgraph stores addresses lowercased; only interpolate a validated
|
|
669
|
+
// address into the query.
|
|
670
|
+
const receiverWhere = receiver && (0, ethers_1.isAddress)(receiver)
|
|
671
|
+
? `where: { receiverAddr: "${receiver.toLowerCase()}" },`
|
|
672
|
+
: '';
|
|
673
|
+
const buildQuery = (pageSize, skip) => {
|
|
674
|
+
// Keep the last-rendered document in the outer `query` so the catch
|
|
675
|
+
// below can log it on failure.
|
|
676
|
+
query = `{
|
|
677
|
+
withdrawalRequesteds(
|
|
678
|
+
first: ${pageSize},
|
|
679
|
+
skip: ${skip},
|
|
680
|
+
orderBy: ${orderByTimestamp},
|
|
681
|
+
orderDirection: desc,
|
|
682
|
+
${receiverWhere}
|
|
683
|
+
) {
|
|
684
|
+
${withdrawalRequestedProps}
|
|
685
|
+
}
|
|
686
|
+
${noWithdrawalProcessed
|
|
687
|
+
? ''
|
|
688
|
+
: `withdrawalProcesseds (
|
|
689
|
+
first: ${pageSize},
|
|
690
|
+
skip: ${skip},
|
|
691
|
+
orderBy: ${orderByTimestamp},
|
|
692
|
+
orderDirection: desc,
|
|
693
|
+
${receiverWhere}
|
|
694
|
+
) {
|
|
695
|
+
${withdrawalProcessedProps}
|
|
696
|
+
}
|
|
697
|
+
`}
|
|
698
|
+
}`;
|
|
699
|
+
return query;
|
|
700
|
+
};
|
|
701
|
+
const result = await fetchPagedWithdrawals('getSubgraphAllWithdrawals', goldskyUrl, buildQuery, ['withdrawalRequesteds', 'withdrawalProcesseds']);
|
|
702
|
+
if (result.status !== 200) {
|
|
703
|
+
core_1.Logger.log.warn('getSubgraphAllWithdrawals', `${result.statusText}::${result.status}: ${vaultSymbol}::${pool}`);
|
|
704
|
+
alertMissingSubgraphOnce({
|
|
705
|
+
source: 'getSubgraphAllWithdrawals',
|
|
706
|
+
pool,
|
|
707
|
+
chainId: network,
|
|
708
|
+
reason: `subgraph returned ${result.status} ${result.statusText}`,
|
|
709
|
+
slackWebookUrl,
|
|
710
|
+
});
|
|
711
|
+
return errorReturnObj;
|
|
712
|
+
}
|
|
713
|
+
const requests = {
|
|
714
|
+
withdrawalRequesteds: result.data
|
|
715
|
+
.withdrawalRequesteds,
|
|
716
|
+
withdrawalProcesseds: result.data
|
|
717
|
+
.withdrawalProcesseds,
|
|
718
|
+
};
|
|
719
|
+
return requests;
|
|
720
|
+
}
|
|
721
|
+
catch (e) {
|
|
722
|
+
core_1.Logger.log.error('getSubgraphAllWithdrawals', `${pool}::${e}::${query}`);
|
|
723
|
+
return {
|
|
724
|
+
withdrawalRequesteds: [],
|
|
725
|
+
withdrawalProcesseds: [],
|
|
726
|
+
};
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
/**
|
|
730
|
+
* Fetch a user's deposit/withdraw history for an archived vault from the backend
|
|
731
|
+
* Mongo snapshot (`/upshift/vault_history`) instead of its retired subgraph.
|
|
732
|
+
*
|
|
733
|
+
* Returns the same {@link ISubgraphUserHistoryItem} shape as the subgraph path,
|
|
734
|
+
* so the caller's downstream transform/normalization is unchanged. `amount` is
|
|
735
|
+
* the raw deposited-asset amount (base units); `decimals` is attached so the
|
|
736
|
+
* caller can normalize, mirroring the subgraph path.
|
|
737
|
+
*
|
|
738
|
+
* Pre-deposit vaults accept multiple deposit assets with differing decimals
|
|
739
|
+
* (e.g. USDS at 18, USDC at 6). When the backend supplies `asset_address` per
|
|
740
|
+
* row, it is propagated as {@link ISubgraphUserHistoryItem.assetIn} (and, when
|
|
741
|
+
* present, `asset_decimals` is used for that row's `decimals`) so lifetime PnL
|
|
742
|
+
* resolves each deposit against its own token rather than the vault decimals —
|
|
743
|
+
* without it, an 18-decimal deposit normalized at the vault's 6 decimals
|
|
744
|
+
* inflates the cost basis by ~1e12. This mirrors the subgraph path, whose
|
|
745
|
+
* deposit rows already carry `assetIn`.
|
|
746
|
+
*
|
|
747
|
+
* Side effects: one RPC read (`getDecimals`) and one HTTP GET to the public API.
|
|
748
|
+
*
|
|
749
|
+
* @param user - The wallet whose history to fetch.
|
|
750
|
+
* @param provider - Contract runner, used to read the vault's decimals.
|
|
751
|
+
* @param pool - The (archived) vault contract address.
|
|
752
|
+
* @returns The user's deposits and settled withdrawals. Empty on a non-200
|
|
753
|
+
* response.
|
|
754
|
+
*/
|
|
755
|
+
async function getArchivedVaultUserHistory(user, provider, pool) {
|
|
756
|
+
const decimals = await (0, core_1.getDecimals)(provider, pool);
|
|
757
|
+
const response = await (0, core_1.fetchUpshiftPublic)(core_1.WEBSERVER_ENDPOINTS.public.tokenizedVault.userHistory(pool, user));
|
|
758
|
+
if (response.status !== 200) {
|
|
759
|
+
core_1.Logger.log.error('getArchivedVaultUserHistory', `non-200 from vault_history for ${pool}: ${response.status}`);
|
|
760
|
+
return [];
|
|
761
|
+
}
|
|
762
|
+
const rows = (await response.json());
|
|
763
|
+
// The backend already stores final ISubgraphUserHistoryItem.type values, so
|
|
764
|
+
// no translation is needed. Two row-level guards before mapping, since both
|
|
765
|
+
// bad shapes propagate destructively downstream:
|
|
766
|
+
// - amount_raw must be a non-negative integer: the caller does
|
|
767
|
+
// BigInt(amount) outside a try/catch, and one bad row would throw and
|
|
768
|
+
// wipe the user's entire (all-vault) history.
|
|
769
|
+
// - timestamp must parse to a real time: a malformed value makes getTime()
|
|
770
|
+
// return NaN, which stringifies to "NaN" and then sorts/normalizes
|
|
771
|
+
// incorrectly downstream. Drop the row rather than emit a "NaN" stamp.
|
|
772
|
+
return (rows
|
|
773
|
+
.filter((row) => /^\d+$/.test(row.amount_raw) &&
|
|
774
|
+
!Number.isNaN(new Date(row.timestamp).getTime()))
|
|
775
|
+
.map((row) => ({
|
|
776
|
+
id: row.transaction_hash,
|
|
777
|
+
contractId_: pool,
|
|
778
|
+
timestamp_: String(Math.floor(new Date(row.timestamp).getTime() / 1000)),
|
|
779
|
+
transactionHash_: row.transaction_hash,
|
|
780
|
+
block_number: row.block_number != null ? String(row.block_number) : '0',
|
|
781
|
+
address: row.wallet,
|
|
782
|
+
amount: row.amount_raw,
|
|
783
|
+
type: row.type,
|
|
784
|
+
// Per-asset decimals when known, else the vault's. PnL re-resolves
|
|
785
|
+
// decimals from `assetIn` anyway; this keeps display/normalization
|
|
786
|
+
// correct for any consumer that reads the row's `decimals` directly.
|
|
787
|
+
decimals: row.asset_decimals ?? decimals,
|
|
788
|
+
// Carry the deposit asset through so mixed-decimal deposits normalize
|
|
789
|
+
// against their own token, not the vault's. Omitted when unknown.
|
|
790
|
+
...(row.asset_address ? { assetIn: row.asset_address } : {}),
|
|
791
|
+
}))
|
|
792
|
+
// Match the subgraph path's ordering contract: sortUserHistory sorts
|
|
793
|
+
// ascending by unix timestamp_, and downstream consumers rely on that
|
|
794
|
+
// chronology. The backend returns rows in arbitrary order, so re-sort here.
|
|
795
|
+
.sort((a, b) => Number(a.timestamp_) - Number(b.timestamp_)));
|
|
796
|
+
}
|
|
797
|
+
async function getSubgraphUserHistory(user, provider, pool, slackWebookUrl = (0, slack_1.resolveSlackWebhookUrl)()) {
|
|
798
|
+
try {
|
|
799
|
+
// This path is EVM-only: it reads chain id and network from an EVM
|
|
800
|
+
// JsonRpcProvider (eth_chainId / getNetwork) and queries an EVM subgraph.
|
|
801
|
+
// A non-EVM (Solana / Stellar) vault address routed here would call
|
|
802
|
+
// eth_chainId against a Solana/Stellar RPC and fail with a 400
|
|
803
|
+
// ("eth_chainId is not available on SOLANA_MAINNET"). Bail early so non-EVM
|
|
804
|
+
// vaults are simply skipped rather than throwing on every history fetch.
|
|
805
|
+
if (!(0, ethers_1.isAddress)(pool)) {
|
|
806
|
+
return [];
|
|
807
|
+
}
|
|
808
|
+
// Archived vaults: serve history from the backend Mongo snapshot instead of
|
|
809
|
+
// the (retired) subgraph. The archived set is fetched from the backend (the
|
|
810
|
+
// routing source of truth) so a vault is only rerouted once its history is
|
|
811
|
+
// backfilled. Same return shape keeps downstream unchanged.
|
|
812
|
+
const archivedVaults = await (0, fetcher_2.fetchArchivedVaults)();
|
|
813
|
+
if (archivedVaults.has(pool.toLowerCase())) {
|
|
814
|
+
return await getArchivedVaultUserHistory(user, provider, pool);
|
|
815
|
+
}
|
|
816
|
+
// setup
|
|
817
|
+
const chainId = await (0, core_1.getChainId)(provider);
|
|
818
|
+
const requests = [];
|
|
819
|
+
let vaultSymbol = await (0, core_1.getVaultSymbol)(pool, provider);
|
|
820
|
+
if (vaultSymbol === undefined) {
|
|
821
|
+
core_1.Logger.log.warn('getSubgraphUserHistory', `cannot find vault symbol for pool: ${pool}`);
|
|
822
|
+
return requests;
|
|
823
|
+
}
|
|
824
|
+
const networkValue = await provider.provider.getNetwork();
|
|
825
|
+
const network = Number(networkValue.chainId);
|
|
826
|
+
if (needsMonadSuffix(network, vaultSymbol)) {
|
|
827
|
+
vaultSymbol = vaultSymbol.concat('_monad');
|
|
828
|
+
}
|
|
829
|
+
const noWithdrawalProcessed = vaultSymbol === 'agETH';
|
|
830
|
+
// sanitize
|
|
831
|
+
if (vaultSymbol === 'testWETHTSA') {
|
|
832
|
+
return requests;
|
|
833
|
+
}
|
|
834
|
+
const vaultsMetadata = await (0, fetcher_2.fetchVaultMetadata)();
|
|
835
|
+
const { subgraph } = vaultsMetadata?.[vaultSymbol?.toLowerCase()] || {};
|
|
836
|
+
const goldskyUrl = subgraph ||
|
|
837
|
+
core_1.SUBGRAPH_VAULT_URLS[vaultSymbol?.toLowerCase()] ||
|
|
838
|
+
(0, core_1.getDefaultSubgraphUrl)(networkValue.name, vaultSymbol);
|
|
839
|
+
if (!goldskyUrl) {
|
|
840
|
+
core_1.Logger.log.warn('getSubgraphUserHistory', `goldsky url is undefined: ${vaultSymbol}::${pool}`);
|
|
841
|
+
alertMissingSubgraphOnce({
|
|
842
|
+
source: 'getSubgraphUserHistory',
|
|
843
|
+
pool,
|
|
844
|
+
chainId,
|
|
845
|
+
slackWebookUrl,
|
|
846
|
+
});
|
|
847
|
+
return requests;
|
|
848
|
+
}
|
|
849
|
+
const tokenizedVault = (await (0, core_1.fetchTokenizedVault)(pool, undefined, false, false))?.[0];
|
|
850
|
+
const version = (0, core_1.getVaultVersionV2)(tokenizedVault);
|
|
851
|
+
// Probe the deployed subgraph's actual field schema (cached per URL) rather
|
|
852
|
+
// than guessing from the vault symbol — see resolveSubgraphSchema (AUGUST-6568).
|
|
853
|
+
const useOldSchema = (await (0, schema_1.resolveSubgraphSchema)(goldskyUrl, GOLDSKY_API_KEY)) === 'old';
|
|
854
|
+
const orderByTimestamp = useOldSchema ? 'timestamp_' : 'blockTimestamp';
|
|
855
|
+
const depositProps = useOldSchema
|
|
856
|
+
? version === 'evm-2'
|
|
857
|
+
? EVM_V2_DEPOSIT_QUERY_PROPS
|
|
858
|
+
: DEPOSIT_QUERY_PROPS
|
|
859
|
+
: NEW_DEPOSIT_QUERY_PROPS;
|
|
860
|
+
const withdrawProps = useOldSchema
|
|
861
|
+
? version === 'evm-2'
|
|
862
|
+
? EVM_V2_WITHDRAWALS_QUERY_PROPS
|
|
863
|
+
: WITHDRAWALS_QUERY_PROPS
|
|
864
|
+
: NEW_WITHDRAWALS_QUERY_PROPS;
|
|
865
|
+
const withdrawalRequestedProps = useOldSchema
|
|
866
|
+
? version === 'evm-2'
|
|
867
|
+
? EVM_V2_WITHDRAWALS_REQUESTED_QUERY_PROPS
|
|
868
|
+
: WITHDRAWALS_REQUESTED_QUERY_PROPS
|
|
869
|
+
: NEW_WITHDRAWALS_REQUESTED_QUERY_PROPS;
|
|
870
|
+
const withdrawalProcessedProps = useOldSchema
|
|
871
|
+
? version === 'evm-2'
|
|
872
|
+
? EVM_V2_WITHDRAWALS_PROCESSED_QUERY_PROPS
|
|
873
|
+
: WITHDRAWALS_PROCESSED_QUERY_PROPS
|
|
874
|
+
: NEW_WITHDRAWALS_PROCESSED_QUERY_PROPS;
|
|
875
|
+
// The Deposit filter field must follow the subgraph schema, not the vault
|
|
876
|
+
// version: the new schema has no `owner` at all (it is `receiverAddr` for
|
|
877
|
+
// every version, see NEW_DEPOSIT_QUERY_PROPS), so an evm-1 vault on a new
|
|
878
|
+
// subgraph used to send `where: { owner }` and get a field error → empty
|
|
879
|
+
// history. Only the old schema differs per version (`owner` on evm-1,
|
|
880
|
+
// `receiverAddr` on evm-2).
|
|
881
|
+
const depositFilterField = useOldSchema && version !== 'evm-2' ? 'owner' : 'receiverAddr';
|
|
882
|
+
const depositQuery = `deposits (
|
|
883
|
+
first: 1000,
|
|
884
|
+
orderBy: ${orderByTimestamp},
|
|
885
|
+
orderDirection: desc,
|
|
886
|
+
where: { ${depositFilterField}: "${user?.toLowerCase()}" }
|
|
887
|
+
) {
|
|
888
|
+
${depositProps}
|
|
889
|
+
}`;
|
|
890
|
+
const fullRequest = `{
|
|
891
|
+
withdraws (
|
|
892
|
+
first: 1000,
|
|
893
|
+
orderBy: ${orderByTimestamp},
|
|
894
|
+
orderDirection: desc,
|
|
895
|
+
where: { receiver: "${user?.toLowerCase()}" }
|
|
896
|
+
) {
|
|
897
|
+
${withdrawProps}
|
|
898
|
+
}
|
|
899
|
+
withdrawalRequesteds (
|
|
900
|
+
first: 1000,
|
|
901
|
+
orderBy: ${orderByTimestamp},
|
|
902
|
+
orderDirection: desc,
|
|
903
|
+
where: { receiverAddr: "${user?.toLowerCase()}" }
|
|
904
|
+
) {
|
|
905
|
+
${withdrawalRequestedProps}
|
|
906
|
+
}
|
|
907
|
+
${noWithdrawalProcessed
|
|
908
|
+
? ''
|
|
909
|
+
: `withdrawalProcesseds (
|
|
910
|
+
first: 1000,
|
|
911
|
+
orderBy: ${orderByTimestamp},
|
|
912
|
+
orderDirection: desc,
|
|
913
|
+
where: { receiverAddr: "${user?.toLowerCase()}" }
|
|
914
|
+
) {
|
|
915
|
+
${withdrawalProcessedProps}
|
|
916
|
+
}
|
|
917
|
+
`}
|
|
918
|
+
${depositQuery}
|
|
919
|
+
}`;
|
|
920
|
+
const result = await (0, fetcher_1.fetchSubgraph)(goldskyUrl, fullRequest, GOLDSKY_API_KEY);
|
|
921
|
+
if (result.status !== 200) {
|
|
922
|
+
core_1.Logger.log.warn('getSubgraphUserHistory', `${result.statusText}::${result.status}: ${vaultSymbol}::${pool}`);
|
|
923
|
+
alertMissingSubgraphOnce({
|
|
924
|
+
source: 'getSubgraphUserHistory',
|
|
925
|
+
pool,
|
|
926
|
+
chainId,
|
|
927
|
+
reason: `subgraph returned ${result.status} ${result.statusText}`,
|
|
928
|
+
slackWebookUrl,
|
|
929
|
+
});
|
|
930
|
+
return requests;
|
|
931
|
+
}
|
|
932
|
+
const json = (await result.json());
|
|
933
|
+
// Format data — vault decimals and per-asset decimals are independent reads.
|
|
934
|
+
const [decimals, assetDecimals] = await Promise.all([
|
|
935
|
+
(0, core_1.getDecimals)(provider, pool),
|
|
936
|
+
buildDepositAssetDecimals(provider, json.data?.deposits),
|
|
937
|
+
]);
|
|
938
|
+
const formattedRequests = sortUserHistory(json.data, chainId, decimals, pool, assetDecimals);
|
|
939
|
+
return formattedRequests;
|
|
940
|
+
}
|
|
941
|
+
catch (e) {
|
|
942
|
+
core_1.Logger.log.error('getSubgraphUserHistory', `${pool}::${e}`);
|
|
943
|
+
return [];
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
async function getSubgraphVaultHistory(provider, pool, slackWebookUrl = (0, slack_1.resolveSlackWebhookUrl)(), opts = {}) {
|
|
947
|
+
try {
|
|
948
|
+
// setup
|
|
949
|
+
const requests = [];
|
|
950
|
+
let vaultSymbol = await (0, core_1.getVaultSymbol)(pool, provider);
|
|
951
|
+
if (vaultSymbol === undefined) {
|
|
952
|
+
core_1.Logger.log.warn('getSubgraphVaultHistory', `cannot find vault symbol for pool: ${pool}`);
|
|
953
|
+
return requests;
|
|
954
|
+
}
|
|
955
|
+
const networkValue = await provider.provider.getNetwork();
|
|
956
|
+
const network = Number(networkValue.chainId);
|
|
957
|
+
if (needsMonadSuffix(network, vaultSymbol)) {
|
|
958
|
+
vaultSymbol = vaultSymbol.concat('_monad');
|
|
959
|
+
} // sanitize
|
|
960
|
+
if (vaultSymbol === 'testWETHTSA') {
|
|
961
|
+
return requests;
|
|
962
|
+
}
|
|
963
|
+
const vaultsMetadata = await (0, fetcher_2.fetchVaultMetadata)();
|
|
964
|
+
const { subgraph } = vaultsMetadata?.[vaultSymbol?.toLowerCase()] || {};
|
|
965
|
+
const goldskyUrl = subgraph ||
|
|
966
|
+
core_1.SUBGRAPH_VAULT_URLS[vaultSymbol?.toLowerCase()] ||
|
|
967
|
+
(0, core_1.getDefaultSubgraphUrl)(networkValue.name, vaultSymbol);
|
|
968
|
+
if (!goldskyUrl) {
|
|
969
|
+
const chainId = await (0, core_1.getChainId)(provider);
|
|
970
|
+
core_1.Logger.log.warn('getSubgraphVaultHistory', `goldsky url is undefined: ${vaultSymbol}::${pool}`);
|
|
971
|
+
alertMissingSubgraphOnce({
|
|
972
|
+
source: 'getSubgraphVaultHistory',
|
|
973
|
+
pool,
|
|
974
|
+
chainId,
|
|
975
|
+
slackWebookUrl,
|
|
976
|
+
});
|
|
977
|
+
return requests;
|
|
978
|
+
}
|
|
979
|
+
const tokenizedVault = (await (0, core_1.fetchTokenizedVault)(pool, undefined, false, false))?.[0];
|
|
980
|
+
const version = (0, core_1.getVaultVersionV2)(tokenizedVault);
|
|
981
|
+
// Probe the deployed subgraph's actual field schema (cached per URL) rather
|
|
982
|
+
// than guessing from the vault symbol — see resolveSubgraphSchema (AUGUST-6568).
|
|
983
|
+
const useOldSchema = (await (0, schema_1.resolveSubgraphSchema)(goldskyUrl, GOLDSKY_API_KEY)) === 'old';
|
|
984
|
+
const orderByTimestamp = useOldSchema ? 'timestamp_' : 'blockTimestamp';
|
|
985
|
+
const withdrawProps = useOldSchema
|
|
986
|
+
? version === 'evm-2'
|
|
987
|
+
? EVM_V2_WITHDRAWALS_QUERY_PROPS
|
|
988
|
+
: WITHDRAWALS_QUERY_PROPS
|
|
989
|
+
: NEW_WITHDRAWALS_QUERY_PROPS;
|
|
990
|
+
const withdrawalRequestedProps = useOldSchema
|
|
991
|
+
? version === 'evm-2'
|
|
992
|
+
? EVM_V2_WITHDRAWALS_REQUESTED_QUERY_PROPS
|
|
993
|
+
: WITHDRAWALS_REQUESTED_QUERY_PROPS
|
|
994
|
+
: NEW_WITHDRAWALS_REQUESTED_QUERY_PROPS;
|
|
995
|
+
const withdrawalProcessedProps = useOldSchema
|
|
996
|
+
? version === 'evm-2'
|
|
997
|
+
? EVM_V2_WITHDRAWALS_PROCESSED_QUERY_PROPS
|
|
998
|
+
: WITHDRAWALS_PROCESSED_QUERY_PROPS
|
|
999
|
+
: NEW_WITHDRAWALS_PROCESSED_QUERY_PROPS;
|
|
1000
|
+
const depositProps = useOldSchema
|
|
1001
|
+
? version === 'evm-2'
|
|
1002
|
+
? EVM_V2_DEPOSIT_QUERY_PROPS
|
|
1003
|
+
: DEPOSIT_QUERY_PROPS
|
|
1004
|
+
: NEW_DEPOSIT_QUERY_PROPS;
|
|
1005
|
+
// Each of the four event entities is capped at 1000 rows per request, so
|
|
1006
|
+
// a busy vault would silently truncate. Page all four in lockstep on a
|
|
1007
|
+
// shared `skip` cursor (rows are ordered newest-first) and keep going while
|
|
1008
|
+
// any entity returned a full page. When `sinceTs` is set we can stop early:
|
|
1009
|
+
// once an entity's oldest row in the page predates the window, no later
|
|
1010
|
+
// page can contain in-window rows for it.
|
|
1011
|
+
const PAGE_SIZE = 1000;
|
|
1012
|
+
const accumulated = {
|
|
1013
|
+
withdraws: [],
|
|
1014
|
+
withdrawalRequesteds: [],
|
|
1015
|
+
withdrawalProcesseds: [],
|
|
1016
|
+
deposits: [],
|
|
1017
|
+
};
|
|
1018
|
+
let skip = 0;
|
|
1019
|
+
for (;;) {
|
|
1020
|
+
const result = await (0, fetcher_1.fetchSubgraph)(goldskyUrl, `{
|
|
1021
|
+
withdraws (
|
|
1022
|
+
first: ${PAGE_SIZE},
|
|
1023
|
+
skip: ${skip},
|
|
1024
|
+
orderBy: ${orderByTimestamp},
|
|
1025
|
+
orderDirection: desc,
|
|
1026
|
+
) {
|
|
1027
|
+
${withdrawProps}
|
|
1028
|
+
}
|
|
1029
|
+
withdrawalRequesteds (
|
|
1030
|
+
first: ${PAGE_SIZE},
|
|
1031
|
+
skip: ${skip},
|
|
1032
|
+
orderBy: ${orderByTimestamp},
|
|
1033
|
+
orderDirection: desc,
|
|
1034
|
+
) {
|
|
1035
|
+
${withdrawalRequestedProps}
|
|
1036
|
+
}
|
|
1037
|
+
withdrawalProcesseds (
|
|
1038
|
+
first: ${PAGE_SIZE},
|
|
1039
|
+
skip: ${skip},
|
|
1040
|
+
orderBy: ${orderByTimestamp},
|
|
1041
|
+
orderDirection: desc,
|
|
1042
|
+
) {
|
|
1043
|
+
${withdrawalProcessedProps}
|
|
1044
|
+
}
|
|
1045
|
+
deposits (
|
|
1046
|
+
first: ${PAGE_SIZE},
|
|
1047
|
+
skip: ${skip},
|
|
1048
|
+
orderBy: ${orderByTimestamp},
|
|
1049
|
+
orderDirection: desc,
|
|
1050
|
+
) {
|
|
1051
|
+
${depositProps}
|
|
1052
|
+
}
|
|
1053
|
+
}`, GOLDSKY_API_KEY);
|
|
1054
|
+
if (result.status !== 200) {
|
|
1055
|
+
core_1.Logger.log.warn('getSubgraphVaultHistory', `${result.statusText}::${result.status}: ${vaultSymbol}::${pool}`, { skip });
|
|
1056
|
+
alertMissingSubgraphOnce({
|
|
1057
|
+
source: 'getSubgraphVaultHistory',
|
|
1058
|
+
pool,
|
|
1059
|
+
chainId: network,
|
|
1060
|
+
reason: `subgraph returned ${result.status} ${result.statusText}`,
|
|
1061
|
+
slackWebookUrl,
|
|
1062
|
+
});
|
|
1063
|
+
// First page failed → nothing to return. A later page failing still
|
|
1064
|
+
// yields whatever earlier pages accumulated.
|
|
1065
|
+
if (skip === 0)
|
|
1066
|
+
return requests;
|
|
1067
|
+
break;
|
|
1068
|
+
}
|
|
1069
|
+
const json = (await result.json());
|
|
1070
|
+
const page = json.data;
|
|
1071
|
+
accumulated.withdraws.push(...(page?.withdraws ?? []));
|
|
1072
|
+
accumulated.withdrawalRequesteds.push(...(page?.withdrawalRequesteds ?? []));
|
|
1073
|
+
accumulated.withdrawalProcesseds.push(...(page?.withdrawalProcesseds ?? []));
|
|
1074
|
+
accumulated.deposits.push(...(page?.deposits ?? []));
|
|
1075
|
+
const entities = [
|
|
1076
|
+
page?.withdraws,
|
|
1077
|
+
page?.withdrawalRequesteds,
|
|
1078
|
+
page?.withdrawalProcesseds,
|
|
1079
|
+
page?.deposits,
|
|
1080
|
+
];
|
|
1081
|
+
const needMore = entities.some((rows) => {
|
|
1082
|
+
if ((rows?.length ?? 0) < PAGE_SIZE)
|
|
1083
|
+
return false;
|
|
1084
|
+
if (opts.sinceTs === undefined)
|
|
1085
|
+
return true;
|
|
1086
|
+
const oldest = Number(rows?.[rows.length - 1]?.timestamp_);
|
|
1087
|
+
return !Number.isFinite(oldest) || oldest >= opts.sinceTs;
|
|
1088
|
+
});
|
|
1089
|
+
if (!needMore)
|
|
1090
|
+
break;
|
|
1091
|
+
skip += PAGE_SIZE;
|
|
1092
|
+
}
|
|
1093
|
+
// Format data — vault decimals and per-asset decimals are independent reads.
|
|
1094
|
+
const chainId = await (0, core_1.getChainId)(provider);
|
|
1095
|
+
const [decimals, assetDecimals] = await Promise.all([
|
|
1096
|
+
(0, core_1.getDecimals)(provider, pool),
|
|
1097
|
+
buildDepositAssetDecimals(provider, accumulated?.deposits),
|
|
1098
|
+
]);
|
|
1099
|
+
const formattedRequests = sortUserHistory(accumulated, chainId, decimals, pool, assetDecimals);
|
|
1100
|
+
return formattedRequests;
|
|
1101
|
+
}
|
|
1102
|
+
catch (e) {
|
|
1103
|
+
core_1.Logger.log.error('getSubgraphVaultHistory', e, { pool });
|
|
1104
|
+
return [];
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
/**
|
|
1108
|
+
* Every transfer of the vault's share token into or out of `user`, oldest
|
|
1109
|
+
* first. Transfers to or from the reward distributors are excluded.
|
|
1110
|
+
*
|
|
1111
|
+
* @param user - Wallet address.
|
|
1112
|
+
* @param provider - EVM provider for the vault's chain.
|
|
1113
|
+
* @param pool - Vault address.
|
|
1114
|
+
* @param slackWebookUrl - Where a missing-subgraph alert is posted.
|
|
1115
|
+
* @param options - `receiptSubgraph: true` reads the vault's receipt-token
|
|
1116
|
+
* subgraph when the registry has one: evm-2 shares are a separate receipt
|
|
1117
|
+
* token, which the base subgraph does not index. Falls back to the base
|
|
1118
|
+
* subgraph, which indexes the shares of vaults that are their own token.
|
|
1119
|
+
* @returns The transfers, or `[]` when the subgraph is missing or the query
|
|
1120
|
+
* fails.
|
|
1121
|
+
*/
|
|
1122
|
+
async function getSubgraphUserTransfers(user, provider, pool, slackWebookUrl = (0, slack_1.resolveSlackWebhookUrl)(), options = {}) {
|
|
1123
|
+
try {
|
|
1124
|
+
// setup
|
|
1125
|
+
let amountOfTransfers = 0;
|
|
1126
|
+
let userTransfers = [];
|
|
1127
|
+
let hasNoData = false;
|
|
1128
|
+
const chainId = await (0, core_1.getChainId)(provider);
|
|
1129
|
+
const walletAddress = user.toLocaleLowerCase();
|
|
1130
|
+
const rewardDistributorAddresses = (0, core_1.REWARD_DISTRIBUTOR_ADDRESS)(chainId).filter((addr) => addr !== '0x0000000000000000000000000000000000000000');
|
|
1131
|
+
let vaultSymbol = await (0, core_1.getVaultSymbol)(pool, provider);
|
|
1132
|
+
if (vaultSymbol === undefined) {
|
|
1133
|
+
core_1.Logger.log.warn('getSubgraphUserTransfers', `cannot find vault symbol for pool: ${pool}`);
|
|
1134
|
+
return userTransfers;
|
|
1135
|
+
}
|
|
1136
|
+
const networkValue = await provider.provider.getNetwork();
|
|
1137
|
+
const network = Number(networkValue.chainId);
|
|
1138
|
+
if (needsMonadSuffix(network, vaultSymbol)) {
|
|
1139
|
+
vaultSymbol = vaultSymbol.concat('_monad');
|
|
1140
|
+
} // sanitize
|
|
1141
|
+
if (vaultSymbol === 'testWETHTSA') {
|
|
1142
|
+
return userTransfers;
|
|
1143
|
+
}
|
|
1144
|
+
const vaultsMetadata = await (0, fetcher_2.fetchVaultMetadata)();
|
|
1145
|
+
const { subgraph, receipt_subgraph } = vaultsMetadata?.[vaultSymbol?.toLowerCase()] || {};
|
|
1146
|
+
const goldskyUrl = (options.receiptSubgraph && receipt_subgraph) ||
|
|
1147
|
+
subgraph ||
|
|
1148
|
+
core_1.SUBGRAPH_VAULT_URLS[vaultSymbol?.toLowerCase()] ||
|
|
1149
|
+
(0, core_1.getDefaultSubgraphUrl)(networkValue.name, vaultSymbol);
|
|
1150
|
+
if (!goldskyUrl) {
|
|
1151
|
+
const chainId = await (0, core_1.getChainId)(provider);
|
|
1152
|
+
core_1.Logger.log.warn('getSubgraphUserTransfers', `goldsky url is undefined: ${vaultSymbol}::${pool}`);
|
|
1153
|
+
alertMissingSubgraphOnce({
|
|
1154
|
+
source: 'getSubgraphUserTransfers',
|
|
1155
|
+
pool,
|
|
1156
|
+
chainId,
|
|
1157
|
+
slackWebookUrl,
|
|
1158
|
+
});
|
|
1159
|
+
return userTransfers;
|
|
1160
|
+
}
|
|
1161
|
+
// Probe the deployed subgraph's actual field schema (cached per URL) rather
|
|
1162
|
+
// than guessing from the vault symbol — see resolveSubgraphSchema (AUGUST-6568).
|
|
1163
|
+
const useOldSchema = (await (0, schema_1.resolveSubgraphSchema)(goldskyUrl, GOLDSKY_API_KEY)) === 'old';
|
|
1164
|
+
const orderByTimestamp = useOldSchema ? 'timestamp_' : 'blockTimestamp';
|
|
1165
|
+
const transferProps = useOldSchema
|
|
1166
|
+
? TRANSFER_QUERY_PROPS
|
|
1167
|
+
: NEW_TRANSFER_QUERY_PROPS;
|
|
1168
|
+
do {
|
|
1169
|
+
// get all the transfers, includes redeem requests and deposits, excludes stake and withdraw events
|
|
1170
|
+
const where = `
|
|
1171
|
+
where: {
|
|
1172
|
+
and: [
|
|
1173
|
+
{
|
|
1174
|
+
or: [
|
|
1175
|
+
{from: "${walletAddress}"},
|
|
1176
|
+
{to: "${walletAddress}"}
|
|
1177
|
+
]
|
|
1178
|
+
},
|
|
1179
|
+
${rewardDistributorAddresses.length
|
|
1180
|
+
? `
|
|
1181
|
+
{
|
|
1182
|
+
from_not_in: [
|
|
1183
|
+
${rewardDistributorAddresses.map((addr) => `"${addr.toLocaleLowerCase()}"`).join(', ')}
|
|
1184
|
+
],
|
|
1185
|
+
to_not_in: [${rewardDistributorAddresses.map((addr) => `"${addr.toLocaleLowerCase()}"`).join(', ')}]
|
|
1186
|
+
}
|
|
1187
|
+
`
|
|
1188
|
+
: ''}
|
|
1189
|
+
]
|
|
1190
|
+
},
|
|
1191
|
+
`;
|
|
1192
|
+
if (!pool) {
|
|
1193
|
+
throw new Error('Pool address is required for HyperEVM');
|
|
1194
|
+
}
|
|
1195
|
+
const result = await (0, fetcher_1.fetchSubgraph)(goldskyUrl, `{
|
|
1196
|
+
transfers(
|
|
1197
|
+
first: 1000, skip: ${amountOfTransfers},
|
|
1198
|
+
${where}
|
|
1199
|
+
orderBy: ${orderByTimestamp}, orderDirection: asc
|
|
1200
|
+
) {
|
|
1201
|
+
${transferProps}
|
|
1202
|
+
}
|
|
1203
|
+
}`, GOLDSKY_API_KEY);
|
|
1204
|
+
const json = (await result.json());
|
|
1205
|
+
const { data } = json;
|
|
1206
|
+
userTransfers = [...userTransfers, ...(data?.transfers || [])];
|
|
1207
|
+
amountOfTransfers += data?.transfers?.length || 0;
|
|
1208
|
+
hasNoData = !data?.transfers?.length;
|
|
1209
|
+
} while ((amountOfTransfers === 0 || amountOfTransfers % 1000 === 0) &&
|
|
1210
|
+
!hasNoData);
|
|
1211
|
+
return userTransfers;
|
|
1212
|
+
}
|
|
1213
|
+
catch (e) {
|
|
1214
|
+
core_1.Logger.log.error('getSubgraphUserTransfers', e, { pool });
|
|
1215
|
+
return [];
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
/**
|
|
1219
|
+
* Fetch the `ReserveDeposit` events that minted vault shares to `user`.
|
|
1220
|
+
*
|
|
1221
|
+
* Some vaults mint shares without an ERC-4626 `Deposit` event: High Growth ETH
|
|
1222
|
+
* emits `ReserveDeposit(account, shares, assets)` for deposits made through
|
|
1223
|
+
* Kelp's gain adapter, so {@link getSubgraphUserHistory} never sees them. Its
|
|
1224
|
+
* subgraph indexes the event as `reserveDeposits`.
|
|
1225
|
+
*
|
|
1226
|
+
* Side effects: one `getVaultSymbol` RPC read (cached), the vault metadata and
|
|
1227
|
+
* schema probes (cached), and one subgraph query.
|
|
1228
|
+
*
|
|
1229
|
+
* @param user - The wallet the shares were minted to.
|
|
1230
|
+
* @param provider - Contract runner for the vault's chain.
|
|
1231
|
+
* @param pool - The vault contract address.
|
|
1232
|
+
* @returns Up to 1000 events, oldest first. Empty when the vault's subgraph
|
|
1233
|
+
* has no `reserveDeposits` entity, has no URL, or the query fails.
|
|
1234
|
+
* @example
|
|
1235
|
+
* ```ts
|
|
1236
|
+
* const reserveDeposits = await getSubgraphUserReserveDeposits(wallet, provider, vault);
|
|
1237
|
+
* ```
|
|
1238
|
+
*/
|
|
1239
|
+
async function getSubgraphUserReserveDeposits(user, provider, pool) {
|
|
1240
|
+
try {
|
|
1241
|
+
let vaultSymbol = await (0, core_1.getVaultSymbol)(pool, provider);
|
|
1242
|
+
if (vaultSymbol === undefined)
|
|
1243
|
+
return [];
|
|
1244
|
+
const networkValue = await provider.provider.getNetwork();
|
|
1245
|
+
if (needsMonadSuffix(Number(networkValue.chainId), vaultSymbol)) {
|
|
1246
|
+
vaultSymbol = vaultSymbol.concat('_monad');
|
|
1247
|
+
}
|
|
1248
|
+
const vaultsMetadata = await (0, fetcher_2.fetchVaultMetadata)();
|
|
1249
|
+
const { subgraph } = vaultsMetadata?.[vaultSymbol.toLowerCase()] || {};
|
|
1250
|
+
const goldskyUrl = subgraph ||
|
|
1251
|
+
core_1.SUBGRAPH_VAULT_URLS[vaultSymbol.toLowerCase()] ||
|
|
1252
|
+
(0, core_1.getDefaultSubgraphUrl)(networkValue.name, vaultSymbol);
|
|
1253
|
+
if (!goldskyUrl)
|
|
1254
|
+
return [];
|
|
1255
|
+
const useOldSchema = (await (0, schema_1.resolveSubgraphSchema)(goldskyUrl, GOLDSKY_API_KEY)) === 'old';
|
|
1256
|
+
const props = useOldSchema
|
|
1257
|
+
? 'id account shares assets transactionHash_ timestamp_ block_number'
|
|
1258
|
+
: 'id account shares assets transactionHash_: transactionHash timestamp_: blockTimestamp block_number: blockNumber';
|
|
1259
|
+
const result = await (0, fetcher_1.fetchSubgraph)(goldskyUrl, `{
|
|
1260
|
+
reserveDeposits(
|
|
1261
|
+
first: 1000,
|
|
1262
|
+
orderBy: ${useOldSchema ? 'timestamp_' : 'blockTimestamp'},
|
|
1263
|
+
orderDirection: asc,
|
|
1264
|
+
where: { account: "${user.toLowerCase()}" }
|
|
1265
|
+
) {
|
|
1266
|
+
${props}
|
|
1267
|
+
}
|
|
1268
|
+
}`, GOLDSKY_API_KEY);
|
|
1269
|
+
if (result.status !== 200)
|
|
1270
|
+
return [];
|
|
1271
|
+
const json = (await result.json());
|
|
1272
|
+
if (json.errors?.length && !(0, schema_1.isSubgraphSchemaFieldError)(json.errors)) {
|
|
1273
|
+
core_1.Logger.log.warn('getSubgraphUserReserveDeposits', `${pool}::${JSON.stringify(json.errors).slice(0, 200)}`);
|
|
1274
|
+
}
|
|
1275
|
+
return json.data?.reserveDeposits ?? [];
|
|
1276
|
+
}
|
|
1277
|
+
catch (e) {
|
|
1278
|
+
core_1.Logger.log.warn('getSubgraphUserReserveDeposits', `${pool}::${e}`);
|
|
1279
|
+
return [];
|
|
1280
|
+
}
|
|
1281
|
+
}
|
|
1282
|
+
//# sourceMappingURL=vaults.js.map
|