diff --git a/.changeset/itchy-mangos-flow.md b/.changeset/itchy-mangos-flow.md new file mode 100644 index 000000000..1691f6b35 --- /dev/null +++ b/.changeset/itchy-mangos-flow.md @@ -0,0 +1,5 @@ +--- +'backend': patch +--- + +add hypurrfi prime vault apr diff --git a/config/hyperevm.ts b/config/hyperevm.ts index 87c865b4b..a3d9b9368 100644 --- a/config/hyperevm.ts +++ b/config/hyperevm.ts @@ -184,6 +184,11 @@ export default { '0x2c910f67dbf81099e6f8e126e7265d7595dc20ad', // hyUSDâ‚®0-hwHLP ], }, + hypurrfiPrime: { + vaults: [ + '0xc200aab602cd7046389b5c8fb088884323f8dd0f', // EVK Vault eUSDC-3 + ], + }, morphoVaultHyperevm: { vaults: [ '0xfc5126377f0efc0041c0969ef9ba903ce67d151e', // feUSDT0 diff --git a/modules/token-yields/handlers/index.ts b/modules/token-yields/handlers/index.ts index 4c18944e4..8e40c8462 100644 --- a/modules/token-yields/handlers/index.ts +++ b/modules/token-yields/handlers/index.ts @@ -9,6 +9,7 @@ const sourceToHandler = { teth: sources.treehouseYieldHandler, sts: sources.stsYieldHandler, hypurrfi: sources.hypurrFiYieldhandler, + hypurrfiPrime: sources.hypurrFiPrimeYieldHandler, morphoVaultHyperevm: sources.morphoHyperevmYieldHandler, http: sources.httpTokenYieldHandler, contract: sources.contractTokenYieldHandler, diff --git a/modules/token-yields/handlers/sources/abis/hypurrfi-vault-lens.ts b/modules/token-yields/handlers/sources/abis/hypurrfi-vault-lens.ts new file mode 100644 index 000000000..0427310c9 --- /dev/null +++ b/modules/token-yields/handlers/sources/abis/hypurrfi-vault-lens.ts @@ -0,0 +1,125 @@ +// ABI for the Euler EVK Vault Lens at 0x0eaDDE9EfCf1540dcA8f94e813E12db55f8405a8 +// Used to fetch lend vault info including supply/borrow APY from the IRM. +// The full struct definition is required for correct ABI decoding. + +const assetPriceInfoComponents = [ + { name: 'queryFailure', type: 'bool' }, + { name: 'queryFailureReason', type: 'bytes' }, + { name: 'timestamp', type: 'uint256' }, + { name: 'oracle', type: 'address' }, + { name: 'asset', type: 'address' }, + { name: 'unitOfAccount', type: 'address' }, + { name: 'amountIn', type: 'uint256' }, + { name: 'amountOutMid', type: 'uint256' }, + { name: 'amountOutBid', type: 'uint256' }, + { name: 'amountOutAsk', type: 'uint256' }, +] as const; + +const oracleDetailedInfoComponents = [ + { name: 'oracle', type: 'address' }, + { name: 'name', type: 'string' }, + { name: 'oracleInfo', type: 'bytes' }, +] as const; + +export const hypurrfiVaultLensAbi = [ + { + type: 'function', + name: 'getVaultInfoFull', + inputs: [{ name: 'vault', type: 'address' }], + outputs: [ + { + name: '', + type: 'tuple', + components: [ + { name: 'timestamp', type: 'uint256' }, + { name: 'vault', type: 'address' }, + { name: 'vaultName', type: 'string' }, + { name: 'vaultSymbol', type: 'string' }, + { name: 'vaultDecimals', type: 'uint256' }, + { name: 'asset', type: 'address' }, + { name: 'assetName', type: 'string' }, + { name: 'assetSymbol', type: 'string' }, + { name: 'assetDecimals', type: 'uint256' }, + { name: 'unitOfAccount', type: 'address' }, + { name: 'unitOfAccountName', type: 'string' }, + { name: 'unitOfAccountSymbol', type: 'string' }, + { name: 'unitOfAccountDecimals', type: 'uint256' }, + { name: 'totalShares', type: 'uint256' }, + { name: 'totalCash', type: 'uint256' }, + { name: 'totalBorrowed', type: 'uint256' }, + { name: 'totalAssets', type: 'uint256' }, + { name: 'accumulatedFeesShares', type: 'uint256' }, + { name: 'accumulatedFeesAssets', type: 'uint256' }, + { name: 'governorFeeReceiver', type: 'address' }, + { name: 'protocolFeeReceiver', type: 'address' }, + { name: 'protocolFeeShare', type: 'uint256' }, + { name: 'interestFee', type: 'uint256' }, + { name: 'hookedOperations', type: 'uint256' }, + { name: 'configFlags', type: 'uint256' }, + { name: 'supplyCap', type: 'uint256' }, + { name: 'borrowCap', type: 'uint256' }, + { name: 'maxLiquidationDiscount', type: 'uint256' }, + { name: 'liquidationCoolOffTime', type: 'uint256' }, + { name: 'dToken', type: 'address' }, + { name: 'oracle', type: 'address' }, + { name: 'interestRateModel', type: 'address' }, + { name: 'hookTarget', type: 'address' }, + { name: 'evc', type: 'address' }, + { name: 'protocolConfig', type: 'address' }, + { name: 'balanceTracker', type: 'address' }, + { name: 'permit2', type: 'address' }, + { name: 'creator', type: 'address' }, + { name: 'governorAdmin', type: 'address' }, + { + name: 'irmInfo', + type: 'tuple', + components: [ + { name: 'queryFailure', type: 'bool' }, + { name: 'queryFailureReason', type: 'bytes' }, + { name: 'vault', type: 'address' }, + { name: 'interestRateModel', type: 'address' }, + { + name: 'interestRateInfo', + type: 'tuple[]', + components: [ + { name: 'cash', type: 'uint256' }, + { name: 'borrows', type: 'uint256' }, + { name: 'borrowSPY', type: 'uint256' }, + { name: 'borrowAPY', type: 'uint256' }, + { name: 'supplyAPY', type: 'uint256' }, + ], + }, + { + name: 'interestRateModelInfo', + type: 'tuple', + components: [ + { name: 'interestRateModel', type: 'address' }, + { name: 'interestRateModelType', type: 'uint8' }, + { name: 'interestRateModelParams', type: 'bytes' }, + ], + }, + ], + }, + { + name: 'collateralLTVInfo', + type: 'tuple[]', + components: [ + { name: 'collateral', type: 'address' }, + { name: 'borrowLTV', type: 'uint256' }, + { name: 'liquidationLTV', type: 'uint256' }, + { name: 'initialLiquidationLTV', type: 'uint256' }, + { name: 'targetTimestamp', type: 'uint256' }, + { name: 'rampDuration', type: 'uint256' }, + ], + }, + { name: 'liabilityPriceInfo', type: 'tuple', components: assetPriceInfoComponents }, + { name: 'collateralPriceInfo', type: 'tuple[]', components: assetPriceInfoComponents }, + { name: 'oracleInfo', type: 'tuple', components: oracleDetailedInfoComponents }, + { name: 'backupAssetPriceInfo', type: 'tuple', components: assetPriceInfoComponents }, + { name: 'backupAssetOracleInfo', type: 'tuple', components: oracleDetailedInfoComponents }, + ], + }, + ], + stateMutability: 'view', + }, +] as const; diff --git a/modules/token-yields/handlers/sources/hypurrfi-prime-yield-handler.ts b/modules/token-yields/handlers/sources/hypurrfi-prime-yield-handler.ts new file mode 100644 index 000000000..0c646d9f0 --- /dev/null +++ b/modules/token-yields/handlers/sources/hypurrfi-prime-yield-handler.ts @@ -0,0 +1,39 @@ +import { formatUnits } from 'viem'; +import { TokenApr, TokenYieldConfig, TokenYieldHandler } from '../../types'; +import { getViemClient } from '../../../sources/viem-client'; +import { hypurrfiVaultLensAbi } from './abis/hypurrfi-vault-lens'; + +const VAULT_LENS = '0x0eaDDE9EfCf1540dcA8f94e813E12db55f8405a8'; + +export const hypurrFiPrimeYieldHandler: TokenYieldHandler = async (config: TokenYieldConfig['hypurrfiPrime']) => { + try { + const client = getViemClient('HYPEREVM'); + + const results = await client.multicall({ + contracts: config!.vaults.map((vault) => ({ + address: VAULT_LENS as `0x${string}`, + abi: hypurrfiVaultLensAbi, + functionName: 'getVaultInfoFull' as const, + args: [vault as `0x${string}`], + })), + allowFailure: true, + }); + + const aprs: TokenApr[] = []; + + for (let i = 0; i < config!.vaults.length; i++) { + const result = results[i]; + if (result.status !== 'success') continue; + const { irmInfo } = result.result; + if (irmInfo.queryFailure) continue; + const rateInfo = irmInfo.interestRateInfo[0]; + if (!rateInfo) continue; + // supplyAPY is 27-decimal ray format; formatUnits(value, 27) gives the float (e.g. 0.015 = 1.5%) + aprs.push({ address: config!.vaults[i].toLowerCase(), apr: Number(formatUnits(rateInfo.supplyAPY, 27)) }); + } + + return aprs; + } catch (error) { + throw Error(`HypurrFi prime vault APR handler failed: ${(error as Error).message}`); + } +}; diff --git a/modules/token-yields/handlers/sources/index.ts b/modules/token-yields/handlers/sources/index.ts index 3e4d8225e..084043b94 100644 --- a/modules/token-yields/handlers/sources/index.ts +++ b/modules/token-yields/handlers/sources/index.ts @@ -6,6 +6,7 @@ export * from './euler-yield-handler'; export * from './teth-yield-handler'; export * from './sts-yield-handler'; export * from './hypurrfi-yield-handler'; +export * from './hypurrfi-prime-yield-handler'; export * from './morpho-hyperevm-yield-handler'; export * from './rate-provider-handler'; export * from './loops-yield-handler'; diff --git a/modules/token-yields/types.ts b/modules/token-yields/types.ts index db77a6191..7f9939a33 100644 --- a/modules/token-yields/types.ts +++ b/modules/token-yields/types.ts @@ -89,6 +89,9 @@ export interface TokenYieldConfig { hypurrfi?: { markets: string[]; }; + hypurrfiPrime?: { + vaults: string[]; + }; morphoVaultHyperevm?: { vaults: string[]; };