UNPKG

@augustdigital/vaults

Version:

JS SDK for web3 interactions with the August Digital Lending Pools

779 lines 37.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getVault = getVault; exports.getVaultLoans = getVaultLoans; exports.getVaultAllocations = getVaultAllocations; exports.getVaultAvailableRedemptions = getVaultAvailableRedemptions; exports.getVaultRedemptionHistory = getVaultRedemptionHistory; exports.getVaultPositions = getVaultPositions; exports.getVaultApy = getVaultApy; exports.getRewardsStakingPositions = getRewardsStakingPositions; const abis_1 = require("@augustdigital/abis"); const utils_1 = require("@augustdigital/utils"); const ethers_1 = require("ethers"); const services_1 = require("@augustdigital/services"); const utils_2 = require("./utils"); async function getVault({ vault, loans = false, allocations = false, options, }) { let returnedVault; try { const tokenizedVault = (await (0, utils_1.fetchTokenizedVaults)(vault))?.[0]; const isSolana = services_1.Solana.utils.isSolanaAddress(vault); if (isSolana) { const solanaRpcUrl = options.rpcUrl; const vaultState = await services_1.Solana.utils.getVaultStateReadOnly({ idl: services_1.Solana.constants.vaultIdl, vaultProgramId: vault, endpoint: solanaRpcUrl, connection: options.solanaService?.connection, }); let depositMint = null; if (vaultState.vaultState && vaultState.vaultState.depositMint) { depositMint = await services_1.Solana.utils.getToken({ mintAddress: vaultState.vaultState.depositMint, endpoint: solanaRpcUrl, connection: options.solanaService?.connection, }); } 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, }; let shareMintInfo = null; let totalSupply = (0, utils_1.toNormalizedBn)(0, vaultState.depositMintDecimals || 0); try { const shareMintPda = services_1.Solana.utils.deriveShareMintPda(vault); const shareMintAccountInfo = await options.solanaService?.connection.getParsedAccountInfo(shareMintPda); if (shareMintAccountInfo?.value) { const parsedData = shareMintAccountInfo.value.data; const { supply, decimals } = parsedData.parsed.info; totalSupply = (0, utils_1.toNormalizedBn)(supply, decimals); } } catch (error) { console.warn('Error fetching share mint info:', error); } const deployedAum = vaultState.vaultState?.deployedAum; const totalAssets = (0, utils_1.toNormalizedBn)(deployedAum ? BigInt(deployedAum.toString()) : BigInt(0), vaultState.depositMintDecimals || 0); console.log('totalAssets (deployedAum):', totalAssets); console.log('totalSupply (share mint supply):', totalSupply); const returnObj = { address: vault, chainId: utils_1.SPECIAL_CHAINS.solana.chainId, name: tokenizedVault?.vault_name || 'Solana Program', logoUrl: tokenizedVault?.vault_logo_url || '/img/strategist/august.svg', symbol: tokenizedVault?.receipt_token_symbol || 'upSOL', description: tokenizedVault?.description || 'Description here', startDatetime: new Date(tokenizedVault?.start_datetime).toISOString() || new Date().toISOString(), status: 'active', internalType: tokenizedVault?.internal_type || 'tokenizedVault', publicType: tokenizedVault?.public_type || 'Defi Yield', tags: [tokenizedVault?.public_type || 'Defi Yield'], isFeatured: tokenizedVault?.is_featured || false, isVisible: tokenizedVault?.is_visible || true, reserveTarget: tokenizedVault?.reserve_target || 0, reserveTolerance: tokenizedVault?.reserve_tolerance || 0, decimals: vaultState.depositMintDecimals || 0, totalAssets: totalAssets, totalSupply: totalSupply, loansOperator: '0x', maxSupply: (0, utils_1.toNormalizedBn)(1000000000000), underlying: { address: depositMint?.address, symbol: depositMint?.symbol, decimals: depositMint?.decimals || services_1.Solana.constants.fallbackDecimals, name: depositMint?.name, }, apy: apy.apy, apyBreakdown: apy, rewards: { upshiftPoints: '0', latestUpshiftPointMultiplier: 0, upshiftPointsMultipliers: [], additionalPoints: [], }, weeklyPerformanceFee: tokenizedVault?.weekly_performance_fee_bps || 0, platformFee: { fee: tokenizedVault?.platform_fee_override?.management_fee || 0, isWaived: false, }, lagDuration: 0, maxDailyDrawdown: tokenizedVault?.max_daily_drawdown || 0, risk: tokenizedVault?.risk || 'low', isWithdrawalPaused: false, isDepositPaused: false, idleAssets: (0, utils_1.toNormalizedBn)(0), loans: [], allocations: { unfilteredTokens: [], defi: [], tokens: [], cefi: [], otc: {}, exposurePerCategory: { borrowing: [], supplying: [], lending: [], wallet: [], cefiBalance: 0, defiBalance: 0, walletBalance: 0, loanBalance: 0, }, netValue: 0, defiPerBorrower: {}, }, position: { vault: vault, status: 'active', availableRedemptions: [], pendingRedemptions: [], redeemable: (0, utils_1.toNormalizedBn)(0), walletBalance: (0, utils_1.toNormalizedBn)(0), }, strategists: [ { address: '0xE926502EdBcE3d56A409ef5dA352B5b522542D7c', logo: '/img/strategist/august.svg', name: 'August', }, ], }; returnedVault = returnObj; return returnObj; } else if ((0, ethers_1.isAddress)(vault)) { const provider = (0, utils_1.createProvider)(options.rpcUrl); const tokenizedVault = (await (0, utils_1.fetchTokenizedVaults)(vault, options?.headers))?.[0]; if (tokenizedVault.status === 'closed' && tokenizedVault.is_visible === false) { console.log('#getVault::closed:', tokenizedVault.vault_name); return null; } const vaultContract = (0, utils_1.createContract)({ address: vault, abi: abis_1.ABI_LENDING_POOL_V2, provider, }); const vaultContractCalls = await Promise.all(utils_2.POOL_FUNCTIONS.map((f) => { if (f === 'totalSupply' && utils_2.MULTI_ASSET_VAULTS.includes(vault)) { return 0; } if (f === 'symbol') { return (0, utils_1.getSymbol)(provider, vault); } if (f === 'decimals') { return (0, utils_1.getDecimals)(provider, vault); } return vaultContract[f](); })); const formattedContractCalls = vaultContractCalls.reduce((acc, curr, i) => { let val; if (utils_2.POOL_FUNCTIONS[i] === 'totalSupply' || utils_2.POOL_FUNCTIONS[i] === 'totalAssets' || utils_2.POOL_FUNCTIONS[i] === 'globalLoansAmount' || utils_2.POOL_FUNCTIONS[i] === 'maxSupply') { val = (0, utils_1.toNormalizedBn)(curr, vaultContractCalls[0]); } else if (utils_2.POOL_FUNCTIONS[i] === 'getTotalLoansDeployed') { val = (0, utils_1.toNormalizedBn)(curr, 0); } else if (utils_2.POOL_FUNCTIONS[i] === 'withdrawalFee') { val = (0, utils_1.toNormalizedBn)(curr, 2); } else if (utils_2.POOL_FUNCTIONS[i] === 'decimals') { val = Number(curr.toString()); } else if (utils_2.POOL_FUNCTIONS[i] === 'loansOperator') { val = '0x4DCb388488622e47683EAd1a147947140a31e485'; } else { val = curr; } return { ...acc, [utils_2.POOL_FUNCTIONS[i]]: val }; }, {}); const returnObj = await (0, utils_2.buildFormattedVault)(provider, tokenizedVault, formattedContractCalls); returnedVault = returnObj; } } catch (err) { console.error(`#getVault::${vault}:`, err); throw new Error(`#getVault::${vault}:${err?.message}`); } if (!(0, utils_1.isBadVault)(vault)) { if (loans) { try { returnedVault = { ...returnedVault, loans: await getVaultLoans(returnedVault, options), }; } catch (e) { console.error(`getVault::${returnedVault.symbol}:`, e?.message); } } if (allocations) { try { const vaultAllocations = await getVaultAllocations(vault, options); returnedVault = { ...returnedVault, allocations: vaultAllocations, }; } catch (e) { console.error(`getVault::${returnedVault.symbol}:`, e?.message); throw new Error('Failure fetching debank res'); } } } return returnedVault; } async function getVaultLoans(vault, options) { const vaultAddress = typeof vault === 'string' ? vault : vault.address; const isOldLendingPool = utils_1.OLD_LENDING_POOLS.includes(vaultAddress); if (!isOldLendingPool) return []; try { let poolTotalSupply; let poolDecimals; const tokenizedVault = (await (0, utils_1.fetchTokenizedVaults)(vaultAddress, options?.headers))?.[0]; const chainId = options?.chainId || tokenizedVault?.chain; const provider = (0, utils_1.createProvider)(options.rpcUrl); const tokenizedVaultLoans = await (0, utils_1.fetchTokenizedVaultLoans)(vaultAddress, chainId); if (typeof vault === 'string') { const poolContract = (0, utils_1.createContract)({ provider, address: vaultAddress, abi: abis_1.ABI_LENDING_POOL_V2, }); [poolTotalSupply, poolDecimals] = await Promise.all([ poolContract.totalSupply(), (0, utils_1.getDecimals)(provider, vaultAddress), ]); poolTotalSupply = BigInt(poolTotalSupply).toString(); poolDecimals = Number(poolDecimals); } else { poolTotalSupply = vault.totalSupply.raw; poolDecimals = vault.decimals; } const newLoans = (await Promise.all((Array.isArray(tokenizedVaultLoans) ? tokenizedVaultLoans : [])?.map(async (l) => { const borrower = l.borrower; const allocation = l.principal_amount / Number((0, ethers_1.formatUnits)(poolTotalSupply, poolDecimals)); const loanFeeRate = await (0, utils_1.getLoanOracleFeeRate)(provider, 'LOAN.REPAY.INTERESTS', l.address, chainId); const loanApr = Number(l.apr || 0) / 100; const loanAprAfterFees = loanApr * (1 - loanFeeRate / 100); const isIdleCapital = utils_1.IDLE_CAPITAL_BORROWER_ADDRESS.includes(borrower); const newLoanObj = { vault: vaultAddress, address: l.address, lender: l.lender, borrower: l.borrower, state: l.state, totalRepaid: l.total_repaid, principalToken: l.principal_token, principalAmount: l.principal_amount, interestAmount: l.interest_amount, upcomingPayment: { amount: l.upcoming_payment.amount, dueDate: l.upcoming_payment.due_date, }, apr: loanAprAfterFees, initialPrincipalAmount: l.initial_principal_amount, deployedDate: l.deployed_date, isIdleCapital, paymentInterval: l.payment_interval, allocation, }; return newLoanObj; }))).filter((l) => l !== undefined); return newLoans; } catch (e) { console.error('#getVaultLoans:', e); throw new Error(`#getVaultLoans::${vault}:${e?.message}`); } } async function getVaultAllocations(vault, options) { let protocolExposure = []; let tokenExposure = []; let cefiExposure = []; let cefiBorrowerResponses = {}; let otcPositions = {}; let defiPerBorrower = {}; let exposurePerCategory = { supplying: [], borrowing: [], wallet: [], walletBalance: 0, cefiBalance: 0, defiBalance: 0, lending: [], loanBalance: 0, }; let netValue = { value: 0 }; let debankErr = false; let unfilteredTokens = []; let uniqueBorrowers; const isOldLendingPool = utils_1.OLD_LENDING_POOLS.includes(vault); const tokenizedVault = (await (0, utils_1.fetchTokenizedVaults)(vault, options?.headers))?.[0]; try { if (isOldLendingPool) { const loans = await getVaultLoans(vault, options); uniqueBorrowers = [...new Set(loans.map((l) => l.borrower))]; } else { uniqueBorrowers = tokenizedVault.subaccounts.map((s) => s.address); } } catch (e) { console.error('#getVaultAllocations::borrowers:', e); } if (vault.toLowerCase() === utils_2.VAULT_AgoraAUSD.toLowerCase()) { const debankRes = await (0, utils_1.fetchDebankResponse)(utils_2.SUBACCOUNT_CALEB); console.log('debankRes:', debankRes); if (debankRes === false) { debankErr = true; } (0, utils_1.parseVaultLevelDebank)(debankRes, protocolExposure, tokenExposure, utils_2.SUBACCOUNT_CALEB, exposurePerCategory, netValue); unfilteredTokens = debankRes?.subaccount?.tokens; const debankPerLoan = (0, utils_1.parseLoanLevelDebank)(debankRes); defiPerBorrower[utils_2.SUBACCOUNT_CALEB] = debankPerLoan; } else { for (const borrower of uniqueBorrowers) { try { const debankRes = await (0, utils_1.fetchDebankResponse)(borrower); if (debankRes === false) { debankErr = true; } (0, utils_1.parseVaultLevelDebank)(debankRes, protocolExposure, tokenExposure, borrower, exposurePerCategory, netValue); unfilteredTokens = debankRes?.subaccount?.tokens; const debankPerLoan = (0, utils_1.parseLoanLevelDebank)(debankRes); defiPerBorrower[borrower] = debankPerLoan; } catch (e) { console.error('#getVaultAllocations::debank:', e); } try { const cefiResponse = await (0, utils_1.fetchAugustWithKey)(options.augustKey, utils_1.WEBSERVER_ENDPOINTS.subaccount.cefi(borrower), { headers: options?.headers }); if (cefiResponse.status !== 200) { console.error('#getVaultAllocations::cefi:', cefiResponse.status, cefiResponse.statusText); } if (cefiResponse.status === 200) { const cefiRes = (await cefiResponse.json()); cefiBorrowerResponses[borrower] = cefiRes; cefiExposure = cefiRes; } } catch (e) { console.error('#getVaultAllocations::cefi:', e); } try { const otcResponse = await (0, utils_1.fetchAugustWithKey)(options.augustKey, utils_1.WEBSERVER_ENDPOINTS.subaccount.otc_positions(borrower), { headers: options?.headers }); if (otcResponse.status !== 200) { console.error('#getVaultAllocations::otc:', otcResponse.status, otcResponse.statusText); } if (otcResponse.status === 200) { const otcRes = (await otcResponse.json()); otcPositions[borrower] = otcRes; } } catch (e) { console.error('#getVaultAllocations::otc:', e); } } } const walletBalance = exposurePerCategory.wallet.reduce((sum, item) => sum + item.amount, 0); const defiBalance = protocolExposure.reduce((sum, item) => sum + item.netUsdValue, 0); const cefiBalance = cefiExposure.reduce((sum, item) => sum + item.value, 0); exposurePerCategory.walletBalance = walletBalance; exposurePerCategory.defiBalance = defiBalance; exposurePerCategory.cefiBalance = cefiBalance; netValue.value += cefiBalance; if (debankErr) { throw Error('failure to fetch debank response'); } if (vault === '0x828BC5895b78b2fb591018Ca5bDC2064742D6D0f') { console.log('protocolExposure:', { defi: protocolExposure, cefi: cefiExposure, otc: otcPositions, tokens: tokenExposure, defiPerBorrower, exposurePerCategory, netValue: netValue.value, }); } return { defi: protocolExposure, cefi: cefiExposure, otc: otcPositions, tokens: tokenExposure, defiPerBorrower, exposurePerCategory, netValue: netValue.value, unfilteredTokens: unfilteredTokens, }; } async function getVaultAvailableRedemptions({ vault, wallet, options, }) { try { const provider = (0, utils_1.createProvider)(options.rpcUrl); const tokenizedVault = (await (0, utils_1.fetchTokenizedVaults)(vault, options?.headers))?.[0]; if (!tokenizedVault) { return { availableRedemptions: [], pendingRedemptions: [] }; } const poolContract = (0, utils_1.createContract)({ address: vault, abi: abis_1.ABI_LENDING_POOL_V2, provider, }); const { withdrawalRequesteds, withdrawalProcesseds } = await (0, services_1.getSubgraphAllWithdrawals)(vault, provider); const decimals = await (0, utils_1.getDecimals)(provider, vault); const availableRedemptions = []; const pendingRedemptions = []; for (const ev of withdrawalRequesteds) { if (!ev || typeof ev !== 'object') { console.warn('#getVaultAvailableRedemptions: Skipping invalid event:', ev); continue; } if (!ev.year || !ev.month || !ev.day || !ev.receiverAddr) { console.warn('#getVaultAvailableRedemptions: Skipping event with missing required properties:', ev); continue; } const fullDate = new Date(Number(ev.year), Number(ev.month) - 1, Number(ev.day)); const foundRedemptionAgainstClaim = withdrawalProcesseds.find((h) => new Date(h.processedOn).toDateString() === fullDate.toDateString() && h.receiverAddr === ev.receiverAddr); if (wallet && (0, ethers_1.isAddress)(wallet)) { if (ev?.receiverAddr?.toLowerCase() === wallet.toLowerCase()) { const alreadyRedeemed = availableRedemptions.find((red) => BigInt(red.day.raw) === BigInt(ev.day) && BigInt(red.month.raw) === BigInt(ev.month) && BigInt(red.year.raw) === BigInt(ev.year)); if (!(foundRedemptionAgainstClaim && alreadyRedeemed)) { try { const trueClaimableAmount = await poolContract?.getClaimableAmountByReceiver?.(BigInt(ev.year), BigInt(ev.month), BigInt(ev.day), (0, ethers_1.getAddress)(wallet)); if (trueClaimableAmount > BigInt(0)) { availableRedemptions.push({ id: ev.transactionHash_ || ev.id, hash: ev.transactionHash_ || ev.id, timestamp: Number(ev.timestamp_), receiver: ev.receiverAddr, day: (0, utils_1.toNormalizedBn)(ev.day, 0), month: (0, utils_1.toNormalizedBn)(ev.month, 0), year: (0, utils_1.toNormalizedBn)(ev.year, 0), amount: (0, utils_1.toNormalizedBn)(trueClaimableAmount, decimals), date: fullDate, vault, }); } pendingRedemptions.push({ id: ev.transactionHash_ || ev.id, hash: ev.transactionHash_ || ev.id, timestamp: Number(ev.timestamp_), receiver: ev.receiverAddr, day: (0, utils_1.toNormalizedBn)(ev.day, 0), month: (0, utils_1.toNormalizedBn)(ev.month, 0), year: (0, utils_1.toNormalizedBn)(ev.year, 0), amount: (0, utils_1.toNormalizedBn)(trueClaimableAmount || BigInt(0), decimals), date: fullDate, vault, }); } catch (contractError) { console.error('#getVaultAvailableRedemptions: Contract call failed:', contractError); pendingRedemptions.push({ id: ev.transactionHash_ || ev.id, hash: ev.transactionHash_ || ev.id, timestamp: Number(ev.timestamp_), receiver: ev.receiverAddr, day: (0, utils_1.toNormalizedBn)(ev.day, 0), month: (0, utils_1.toNormalizedBn)(ev.month, 0), year: (0, utils_1.toNormalizedBn)(ev.year, 0), amount: (0, utils_1.toNormalizedBn)(BigInt(0), decimals), date: fullDate, vault, }); } } } } else { if (!!foundRedemptionAgainstClaim) { availableRedemptions.push({ id: ev.transactionHash_ || ev.id, hash: ev.transactionHash_ || ev.id, timestamp: Number(ev.timestamp_), receiver: ev.receiverAddr, day: (0, utils_1.toNormalizedBn)(ev.day, 0), month: (0, utils_1.toNormalizedBn)(ev.month, 0), year: (0, utils_1.toNormalizedBn)(ev.year, 0), amount: (0, utils_1.toNormalizedBn)(ev.assets || BigInt(0), decimals), date: fullDate, vault, }); } } } return { availableRedemptions, pendingRedemptions }; } catch (e) { console.error('#getVaultAvailableRedemptions:', e); return { availableRedemptions: [], pendingRedemptions: [] }; } } async function getVaultRedemptionHistory({ vault, wallet, options, }) { try { const provider = (0, utils_1.createProvider)(options.rpcUrl); const tokenizedVault = (await (0, utils_1.fetchTokenizedVaults)(vault, options?.headers))?.[0]; if (!tokenizedVault) { return []; } const chainId = tokenizedVault.chain; const poolContract = (0, utils_1.createContract)({ address: vault, abi: abis_1.ABI_LENDING_POOL_V2, provider, }); let logPromises = []; const currentBlock = await provider.getBlockNumber(); let startingBlock = currentBlock - (0, utils_2.determineBlockSkipInternal)(chainId); let endBlock = currentBlock; const cutoffBlock = currentBlock - (0, utils_2.determineBlockCutoff)(chainId); while (endBlock >= cutoffBlock) { const logBloomsPromises = poolContract.queryFilter('WithdrawalProcessed', BigInt(startingBlock), BigInt(endBlock)); logPromises.push(logBloomsPromises); startingBlock -= (0, utils_2.determineBlockSkipInternal)(chainId); endBlock -= (0, utils_2.determineBlockSkipInternal)(chainId); } const logs = (await Promise.all(logPromises.flat())).flat(); const iface = new ethers_1.ethers.Interface([ 'event WithdrawalProcessed (uint256 assetsAmount, uint256 processedOn, address receiverAddr, uint256 requestedOn)', ]); const events = logs.map((log) => iface.parseLog(log)); const decimals = await (0, utils_1.getDecimals)(provider, vault); const redemptions = []; events?.forEach((ev) => { if (!ev?.args) return; const [assetsAmount, processedOn, receiverAddr, requestedOn] = ev.args; if (wallet) { if (String(receiverAddr)?.toLowerCase() === wallet.toLowerCase()) { redemptions.push({ receiver: receiverAddr, amount: (0, utils_1.toNormalizedBn)(assetsAmount, decimals), processed: new Date(Number(processedOn) * 1000), requested: new Date(Number(requestedOn) * 1000), vault, }); } } else { redemptions.push({ receiver: receiverAddr, amount: (0, utils_1.toNormalizedBn)(assetsAmount, decimals), processed: new Date(Number(processedOn) * 1000), requested: new Date(Number(requestedOn) * 1000), vault, }); } }); if (options.env === 'DEV') console.log('#getVaultRedemptionHistory:', redemptions.slice(0, 1)); return redemptions; } catch (e) { console.error('#getVaultRedemptionHistory:', e); return []; } } async function getVaultPositions({ vault, wallet, solanaWallet, options, }) { try { const tokenizedVaults = await (0, utils_1.fetchTokenizedVaults)(vault ? vault : undefined, options?.headers); if (!tokenizedVaults || tokenizedVaults.length === 0) { return []; } function renderStatus(_redemptions, _balance) { if (_redemptions?.length) return 'REDEEM'; if (BigInt(_balance.raw) > BigInt(0)) return 'STAKED'; return 'PENDING'; } const promises = await Promise.all(tokenizedVaults.map(async (v) => { try { if (services_1.Solana.utils.isSolanaAddress(v.address)) { let balance = (0, utils_1.toNormalizedBn)(0); if (services_1.Solana.utils.isSolanaAddress(solanaWallet)) { const vaultStateRes = await options.solanaService.getVaultState(String(v.address), services_1.Solana.constants.vaultIdl); if (vaultStateRes && vaultStateRes?.vaultState?.shareMint) { balance = (0, utils_1.toNormalizedBn)(await options.solanaService.fetchUserShareBalance(solanaWallet, vaultStateRes?.vaultState?.shareMint)); } } return { vault, status: renderStatus([], balance), availableRedemptions: [], pendingRedemptions: [], redeemable: balance, walletBalance: balance, }; } else { const provider = (0, utils_1.createProvider)(options.rpcUrl); const decimals = await (0, utils_1.getDecimals)(provider, vault); const poolContract = (0, utils_1.createContract)({ provider, abi: abis_1.ABI_LENDING_POOL_V2, address: v.address, }); const bal = wallet ? await poolContract.balanceOf(wallet) : 0; const balance = (0, utils_1.toNormalizedBn)(bal || 0, decimals); const { availableRedemptions, pendingRedemptions } = await getVaultAvailableRedemptions({ vault: v.address, wallet, options, }); const aggregateAvailableRedemptions = availableRedemptions?.reduce((acc, curr) => acc + BigInt(curr.amount.raw), BigInt(0)); return { vault, status: renderStatus(availableRedemptions, balance), availableRedemptions, pendingRedemptions, redeemable: (0, utils_1.toNormalizedBn)(aggregateAvailableRedemptions, decimals), walletBalance: balance, }; } } catch (vaultError) { console.error(`#getVaultPositions: Error processing vault ${v.address}:`, vaultError); return { vault, status: 'PENDING', availableRedemptions: [], pendingRedemptions: [], redeemable: (0, utils_1.toNormalizedBn)(0), walletBalance: (0, utils_1.toNormalizedBn)(0), }; } })); return promises.flat(); } catch (e) { console.error('#getVaultPositions:', e); throw new Error(`#getVaultPositions::${vault}:${e?.message}`); } } async function getVaultApy({ vault, options, }) { try { const tokenizedVault = (await (0, utils_1.fetchTokenizedVaults)(vault, options?.headers))?.[0]; return tokenizedVault?.reported_apy?.apy || 0; } catch (e) { console.error('#getVaultApy:', e); throw new Error(`#getVaultApy::${vault}:${e?.message}`); } } async function getRewardsStakingPositions({ rpcUrl, wallet, coinGeckoKey, }) { const REWARDS_CHAIN = 43114; const REWARDS_SYMBOL = 'AVAX'; const REWARDS_DECIMALS = 18; const REWARDS_NAME = 'Avalanche'; const APR_MULTIPLIER = 31536000; const UP_AUSD_SYMBOL = 'upAUSD'; try { const provider = (0, utils_1.createProvider)(rpcUrl); const chainId = await (0, utils_1.getChainId)(provider); if (chainId !== REWARDS_CHAIN) { console.warn('#getStakingPositions: no rewards distributor on chain_id', chainId); return []; } if (wallet && !(0, ethers_1.isAddress)(wallet)) { console.warn('#getStakingPositions: wallet passed is not a valid address', wallet); return []; } const rewardDistributorAddresses = (0, utils_1.REWARD_DISTRIBUTOR_ADDRESS)(chainId); const positions = await Promise.all(rewardDistributorAddresses.map(async (contract, i) => { const rewardContract = (0, utils_1.createContract)({ address: contract, provider: provider, abi: abis_1.ABI_REWARD_DISTRIBUTOR, }); const totalStaked = await rewardContract.totalStaked(); const rewardsPerSecond = await rewardContract.rewardsPerSecond(); const stakingTokenCalls = ['decimals', 'symbol', 'name', 'totalSupply']; const stakingTokenAddress = (await rewardContract.stakingToken()); const stakingTokenContract = (0, utils_1.createContract)({ address: stakingTokenAddress, provider: provider, abi: abis_1.ABI_ERC20, }); const [decimals, symbol, name, totalSupply] = await Promise.all(stakingTokenCalls.map((staking) => stakingTokenContract[staking]())); let balance; let earned; if (wallet) { const formattedWallet = (0, ethers_1.getAddress)(wallet); balance = await rewardContract.balanceOf(formattedWallet); earned = await rewardContract.earned(formattedWallet); } const rewardTokenPriceInUsd = await (0, utils_1.fetchTokenPrice)(REWARDS_SYMBOL, null, coinGeckoKey); const normalizedRewardTokenPrice = (0, utils_1.toNormalizedBn)(rewardTokenPriceInUsd); const normalizedTotalStakedInPool = (0, utils_1.toNormalizedBn)(totalStaked, decimals); const normalizedRedeemable = (0, utils_1.toNormalizedBn)(earned, REWARDS_DECIMALS); const normalizedRewardsPerSecond = (0, utils_1.toNormalizedBn)(rewardsPerSecond, REWARDS_DECIMALS); const normalizedTotalStakedBalance = (0, utils_1.toNormalizedBn)(balance, decimals); const rewardTokenPriceToMultiply = symbol === UP_AUSD_SYMBOL ? Number(normalizedRewardTokenPrice?.normalized) : 1; const STAKED_APR = ((Number(normalizedRewardsPerSecond?.normalized) * APR_MULTIPLIER * rewardTokenPriceToMultiply) / (Number(normalizedTotalStakedInPool?.normalized) * Number(1))) * 100; const MAX_APR = ((Number(normalizedRewardsPerSecond?.normalized) * APR_MULTIPLIER * rewardTokenPriceToMultiply) / (Number(normalizedTotalStakedInPool?.normalized) * Number(1))) * 100; const activePosition = { id: String(i), rewardToken: { decimals: REWARDS_DECIMALS, symbol: REWARDS_SYMBOL, address: ethers_1.ZeroAddress, chain: REWARDS_CHAIN, redeemable: normalizedRedeemable, usd: normalizedRewardTokenPrice, name: REWARDS_NAME, }, stakingToken: { decimals: Number(decimals), symbol: symbol, address: stakingTokenAddress, chain: REWARDS_CHAIN, totalStaked: normalizedTotalStakedBalance, usd: normalizedRewardTokenPrice, totalSupply: normalizedTotalStakedInPool, name: name, }, rewardDistributor: contract, rewardPerSecond: (0, utils_1.toNormalizedBn)(rewardsPerSecond), apy: STAKED_APR, maxApy: MAX_APR, chainId: REWARDS_CHAIN, }; return activePosition; })); return positions; } catch (e) { console.error('#getStakingPositions:', e); } } //# sourceMappingURL=getters.js.map