@augustdigital/vaults
Version:
JS SDK for web3 interactions with the August Digital Lending Pools
779 lines • 37.1 kB
JavaScript
"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