@augustdigital/vaults
Version:
JS SDK for web3 interactions with the August Digital Lending Pools
414 lines • 16.4 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.POOL_FUNCTIONS = exports.determineBlockSkipInternal = exports.determineBlockCutoff = exports.filterOutBySize = exports.MULTI_ASSET_VAULTS = exports.SUBACCOUNT_CALEB = exports.VAULT_AgoraAUSD = void 0;
exports.promiseSettle = promiseSettle;
exports.getVaultRewards = getVaultRewards;
exports.getIdleAssets = getIdleAssets;
exports.buildFormattedVault = buildFormattedVault;
exports.fetchVaultWithFallback = fetchVaultWithFallback;
exports.fetchVaultsBatch = fetchVaultsBatch;
exports.fetchVaultsComprehensive = fetchVaultsComprehensive;
exports.filterVaultsIntelligently = filterVaultsIntelligently;
const abis_1 = require("@augustdigital/abis");
const utils_1 = require("@augustdigital/utils");
exports.VAULT_AgoraAUSD = '0x828BC5895b78b2fb591018Ca5bDC2064742D6D0f';
exports.SUBACCOUNT_CALEB = '0xFff71B0b66f076C60Fa2f176a34a6EA709ccF21B';
exports.MULTI_ASSET_VAULTS = [
'0x18EE038C114a07f4B08b420fb1E4149a4F357249',
];
async function promiseSettle(promises, maxRetries = 3, baseDelay = 1000) {
const promisesWithRetry = promises.map((promise, index) => (0, utils_1.withRetry)(async () => {
try {
return await promise;
}
catch (error) {
console.warn(`Promise at index ${index} failed:`, error);
throw error;
}
}, maxRetries, baseDelay));
const results = await Promise.allSettled(promisesWithRetry);
return results.map((result, index) => {
if (result.status === 'fulfilled') {
return result.value;
}
else {
console.warn(`Promise at index ${index} failed after retries:`, result.reason);
return null;
}
});
}
const filterOutBySize = (usdAmount) => usdAmount > 10000;
exports.filterOutBySize = filterOutBySize;
const determineBlockCutoff = (chain) => {
switch (chain) {
case 56:
return 120000;
case 43114:
return 120000;
default:
return 150000;
}
};
exports.determineBlockCutoff = determineBlockCutoff;
const determineBlockSkipInternal = (chain) => {
switch (chain) {
case 43114:
return 8000;
case 56:
return 8000;
default:
return 50000;
}
};
exports.determineBlockSkipInternal = determineBlockSkipInternal;
exports.POOL_FUNCTIONS = [
'decimals',
'asset',
'totalSupply',
'totalAssets',
'maxSupply',
'withdrawalFee',
'lagDuration',
'withdrawalsPaused',
];
function getVaultRewards(tokenizedVault) {
const upshiftPointRewards = tokenizedVault.rewards?.filter((r) => r.text === 'Upshift Points');
const sortedPointsMultipliers = upshiftPointRewards?.sort((a, b) => new Date(b.start_datetime).getTime() -
new Date(a.start_datetime).getTime());
const upshiftPointsMultipliers = sortedPointsMultipliers?.map((r) => ({
timestamp: new Date(r.start_datetime).getTime() / 1000,
multiplier: r.multiplier,
}));
const latestUpshiftPointMultiplier = upshiftPointsMultipliers?.[0]?.multiplier;
const rewards = {
upshiftPoints: !!upshiftPointRewards.length
? `${latestUpshiftPointMultiplier}x Upshift Points`
: '',
latestUpshiftPointMultiplier,
upshiftPointsMultipliers: upshiftPointsMultipliers,
additionalPoints: tokenizedVault.rewards.map((r) => `${r.multiplier !== 1 ? `${r.multiplier}x` : ''} ${r.text}`),
};
return rewards;
}
async function getIdleAssets(provider, vaultAddress, underlying, totalAssets) {
let idleAssets;
if (utils_1.OLD_LENDING_POOLS.includes(vaultAddress)) {
const globalLoansAmount = await (0, utils_1.createContract)({
provider,
address: vaultAddress,
abi: abis_1.ABI_LENDING_POOLS,
}).globalLoansAmount();
idleAssets = BigInt(totalAssets.raw) - BigInt(globalLoansAmount);
}
else {
idleAssets = await (0, utils_1.createContract)({
provider,
address: underlying,
abi: abis_1.ABI_ERC20,
}).balanceOf(vaultAddress);
}
return idleAssets;
}
async function buildFormattedVault(provider, tokenizedVault, contractCalls) {
const underlying = {
address: contractCalls.asset,
symbol: await (0, utils_1.getSymbol)(provider, contractCalls.asset),
decimals: contractCalls.decimals,
};
if (!tokenizedVault.reported_apy)
console.warn('#buildFormattedVault::reported_apy: no APY found for', tokenizedVault.receipt_token_symbol);
const apy = {
apy: tokenizedVault?.reported_apy?.apy * 100,
explainer: tokenizedVault?.reported_apy?.explainer,
liquidApy: tokenizedVault?.reported_apy?.liquid_apy * 100,
rewardsClaimable: tokenizedVault?.reported_apy?.rewards_claimable,
rewardsCompounded: tokenizedVault?.reported_apy?.rewards_compounded,
underlyingApy: tokenizedVault?.reported_apy?.underlying_apy * 100,
};
const strategists = tokenizedVault.subaccounts.map((s) => ({
address: s.address,
logo: s.strategist?.strategist_logo,
name: s.strategist?.strategist_name,
}));
const platformFee = {
fee: tokenizedVault.platform_fee_override.management_fee,
isWaived: tokenizedVault.platform_fee_override.is_fee_waived,
};
const rewards = getVaultRewards(tokenizedVault);
const idleAssets = await getIdleAssets(provider, tokenizedVault.address, contractCalls.asset, contractCalls.totalAssets);
return {
lagDuration: Number(contractCalls.lagDuration),
address: tokenizedVault.address,
name: tokenizedVault.vault_name,
logoUrl: tokenizedVault.vault_logo_url,
symbol: tokenizedVault.receipt_token_symbol,
description: tokenizedVault.description,
startDatetime: String(tokenizedVault.start_datetime),
publicType: tokenizedVault.public_type,
internalType: tokenizedVault.internal_type,
status: tokenizedVault.status,
tags: [tokenizedVault.public_type],
isFeatured: tokenizedVault.is_featured,
isVisible: tokenizedVault.is_visible,
reserveTarget: tokenizedVault.reserve_target,
reserveTolerance: tokenizedVault.reserve_tolerance,
underlying,
apy: apy.apy,
apyBreakdown: apy,
rewards,
strategists,
weeklyPerformanceFee: tokenizedVault.weekly_performance_fee_bps,
platformFee,
totalAssets: contractCalls.totalAssets,
totalSupply: contractCalls.totalSupply,
loansOperator: contractCalls.loansOperator,
decimals: contractCalls.decimals,
maxSupply: contractCalls.maxSupply,
chainId: tokenizedVault.chain,
maxDailyDrawdown: tokenizedVault.max_daily_drawdown || 0,
risk: tokenizedVault.risk,
isWithdrawalPaused: contractCalls.withdrawalsPaused,
idleAssets: (0, utils_1.toNormalizedBn)(idleAssets, contractCalls.decimals),
isDepositPaused: (0, utils_1.isBadVault)(tokenizedVault.address),
};
}
async function fetchVaultWithFallback(vaultAddress, fetchFn, options = {}) {
const { maxRetries = 3, baseDelay = 1000 } = options;
try {
const data = await (0, utils_1.withRetry)(fetchFn, maxRetries * 2, baseDelay * 2);
return { success: true, data, strategy: 'extended-retry' };
}
catch (error) {
console.warn(`Vault ${vaultAddress} failed with extended retry strategy:`, error);
}
return {
success: false,
error: new Error(`All strategies failed for vault ${vaultAddress}`),
strategy: 'all-failed',
};
}
async function fetchVaultsBatch(vaults, options = {}) {
const { maxRetries = 3, baseDelay = 1000, batchSize = 10, parallelLimit = 5, } = options;
const successful = [];
const failed = [];
let totalAttempted = 0;
for (let i = 0; i < vaults.length; i += batchSize) {
const batch = vaults.slice(i, i + batchSize);
const batchPromises = batch.map(async (vault, batchIndex) => {
const globalIndex = i + batchIndex;
totalAttempted++;
try {
const result = await fetchVaultWithFallback(vault.address, vault.fetchFn, {
maxRetries,
baseDelay,
});
if (result.success && result.data) {
successful.push({
index: globalIndex,
data: result.data,
strategy: result.strategy,
});
}
else {
failed.push({
index: globalIndex,
error: result.error || new Error('Unknown failure'),
address: vault.address,
});
}
}
catch (error) {
failed.push({
index: globalIndex,
error: error,
address: vault.address,
});
}
});
await Promise.all(batchPromises);
if (i + batchSize < vaults.length) {
await new Promise((resolve) => setTimeout(resolve, 100));
}
}
const successRate = totalAttempted > 0 ? (successful.length / totalAttempted) * 100 : 0;
return {
successful,
failed,
totalAttempted,
successRate,
};
}
async function fetchVaultsComprehensive(vaults, fetchFn, options = {}) {
const { maxRetries = 5, baseDelay = 2000, batchSize = 10, parallelLimit = 5, includeClosed = false, includeInvisible = false, fallbackRpcUrls = {}, timeout = 60000, } = options;
const successful = [];
const failed = [];
const rpcFailures = {};
let totalAttempted = 0;
for (let i = 0; i < vaults.length; i += batchSize) {
const batch = vaults.slice(i, i + batchSize);
const batchPromises = batch.map(async (vault, batchIndex) => {
const globalIndex = i + batchIndex;
totalAttempted++;
let attempts = 0;
let lastError;
for (attempts = 1; attempts <= maxRetries; attempts++) {
try {
const data = await Promise.race([
fetchFn(vault),
new Promise((_, reject) => setTimeout(() => reject(new Error('Primary fetch timeout')), timeout)),
]);
successful.push({
index: globalIndex,
data,
strategy: 'primary-retry',
attempts,
});
return;
}
catch (error) {
lastError = error;
if (attempts < maxRetries) {
const delay = baseDelay * Math.pow(2, attempts - 1);
console.warn(`Vault ${vault.address} attempt ${attempts} failed, retrying in ${delay}ms:`, error);
await new Promise((resolve) => setTimeout(resolve, delay));
}
}
}
if (fallbackRpcUrls[vault.chain] &&
fallbackRpcUrls[vault.chain].length > 0) {
for (const fallbackRpc of fallbackRpcUrls[vault.chain]) {
try {
const data = await Promise.race([
fetchFn({ ...vault, fallbackRpc }),
new Promise((_, reject) => setTimeout(() => reject(new Error('Fallback RPC timeout')), timeout)),
]);
successful.push({
index: globalIndex,
data,
strategy: 'fallback-rpc',
attempts: attempts + 1,
});
return;
}
catch (error) {
console.warn(`Vault ${vault.address} failed with fallback RPC ${fallbackRpc}:`, error);
}
}
}
try {
const data = await Promise.race([
fetchFn({ ...vault, minimal: true }),
new Promise((_, reject) => setTimeout(() => reject(new Error('Minimal fetch timeout')), timeout)),
]);
successful.push({
index: globalIndex,
data,
strategy: 'minimal-data',
attempts: attempts + 1,
});
return;
}
catch (error) {
console.warn(`Vault ${vault.address} failed with minimal data:`, error);
}
try {
const extendedDelay = baseDelay * 3;
await new Promise((resolve) => setTimeout(resolve, extendedDelay));
const data = await Promise.race([
fetchFn(vault),
new Promise((_, reject) => setTimeout(() => reject(new Error('Extended retry timeout')), timeout)),
]);
successful.push({
index: globalIndex,
data,
strategy: 'extended-retry',
attempts: attempts + 2,
});
return;
}
catch (error) {
console.warn(`Vault ${vault.address} failed with extended retry:`, error);
}
failed.push({
index: globalIndex,
error: lastError || new Error('All strategies failed'),
address: vault.address,
chain: vault.chain,
attempts: attempts + 2,
});
rpcFailures[vault.chain] = (rpcFailures[vault.chain] || 0) + 1;
});
await Promise.all(batchPromises);
if (i + batchSize < vaults.length) {
await new Promise((resolve) => setTimeout(resolve, 200));
}
}
const successRate = totalAttempted > 0 ? (successful.length / totalAttempted) * 100 : 0;
return {
successful,
failed,
totalAttempted,
successRate,
coverageReport: {
totalVaults: vaults.length,
successfulVaults: successful.length,
failedVaults: failed.length,
closedVaults: 0,
invisibleVaults: 0,
rpcFailures,
},
};
}
function filterVaultsIntelligently(vaults, options = {}) {
const { includeClosed = true, includeInvisible = true, includeNull = false, minStatus = ['active', 'closed'], } = options;
const active = [];
const closed = [];
const invisible = [];
const failed = [];
vaults.forEach((vault, index) => {
if (vault === null) {
if (includeNull) {
failed.push({ index, reason: 'null_response' });
}
return;
}
const status = vault.status || 'unknown';
const isVisible = vault.isVisible ?? vault.is_visible ?? true;
if (status === 'active' && isVisible) {
active.push(vault);
}
else if (status === 'closed' && includeClosed) {
closed.push(vault);
}
else if (!isVisible && includeInvisible) {
invisible.push(vault);
}
else if (minStatus.includes(status)) {
active.push(vault);
}
else {
failed.push({
index,
reason: `status_${status}_invisible_${!isVisible}`,
});
}
});
const total = vaults.length;
const successCount = active.length + closed.length + invisible.length;
const successRate = total > 0 ? (successCount / total) * 100 : 0;
return {
active,
closed,
invisible,
failed,
summary: {
total,
active: active.length,
closed: closed.length,
invisible: invisible.length,
failed: failed.length,
successRate,
},
};
}
//# sourceMappingURL=utils.js.map