From c14413adce0bedeed325d25cc0c31ec3e7b221ae Mon Sep 17 00:00:00 2001 From: Carl Wiles <131632522+CarlWiles@users.noreply.github.com> Date: Thu, 5 Sep 2024 14:21:20 +0800 Subject: [PATCH] feat: support rho markets apy (#1477) * feat: support rho markets apy * feat: support rho markets borrow * feat: refine rho markets info * feat: refine rho markets info * feat: refine rho markets info * fix: borrow base apy * feat: support ltv --------- Co-authored-by: Carl --- src/adaptors/rho-markets/index.js | 95 +++++++++++++++++++++++ src/adaptors/rho-markets/rho-markets.json | 94 ++++++++++++++++++++++ 2 files changed, 189 insertions(+) create mode 100644 src/adaptors/rho-markets/index.js create mode 100644 src/adaptors/rho-markets/rho-markets.json diff --git a/src/adaptors/rho-markets/index.js b/src/adaptors/rho-markets/index.js new file mode 100644 index 000000000..58672ab9b --- /dev/null +++ b/src/adaptors/rho-markets/index.js @@ -0,0 +1,95 @@ +const sdk = require('@defillama/sdk'); +const utils = require('../utils'); +const abis = require('./rho-markets.json'); +const ethers = require('ethers'); + +const markets_state = '0x5FcDf2257d240Ed53459fAb752E7738e1eF4FA3F'; +const chain = utils.formatChain('Scroll'); +const project = 'rho-markets'; + +function calculateApy(supplyRatePerBlock, blocksPerYear) { + supplyRatePerBlock = BigInt(supplyRatePerBlock); + blocksPerYear = BigInt(blocksPerYear); + + if (supplyRatePerBlock === 0n) return 0; + + const SCALE = BigInt(1e18); + + function pow(base, exponent) { + let result = SCALE; + let basePow = base; + + while (exponent > 0n) { + if (exponent % 2n === 1n) { + result = (result * basePow) / SCALE; + } + basePow = (basePow * basePow) / SCALE; + exponent /= 2n; + } + return result; + } + + const compounded = pow(SCALE + supplyRatePerBlock, blocksPerYear); + const rawData = (compounded - SCALE) * 100n; + + const data = ethers.utils.formatEther(rawData.toString()); + return Number(data); +} + +const apy = async () => { + const allMarketsMetadata = ( + await sdk.api.abi.call({ + target: markets_state, + abi: abis.find((m) => m.name === 'getActiveMarketsInfo'), + chain: 'scroll', + }) + ).output; + + const pools = allMarketsMetadata.map((marketInfo, i) => { + const pool = `${marketInfo.token}-${chain}`.toLowerCase(); + const underlyingSymbol = marketInfo.underlyingSymbol; + + const poolMeta = `Rho ${underlyingSymbol} Market`; + const tvlUsd = Number(ethers.utils.formatEther(marketInfo.tvl.toString())); + const ltv = Number(ethers.utils.formatEther(marketInfo.ltv.toString())); + const totalSupplyUsd = Number( + ethers.utils.formatEther(marketInfo.totalSupply.toString()) + ); + const totalBorrowUsd = Number( + ethers.utils.formatEther(marketInfo.totalBorrows.toString()) + ); + + const supplyRatePerBlock = marketInfo.supplyRatePerBlock; + const borrowRatePerBlock = marketInfo.borrowRatePerBlock; + const blocksPerYear = marketInfo.blocksPerYear; + + const apyBase = calculateApy(supplyRatePerBlock, blocksPerYear); + const apyBaseBorrow = calculateApy(borrowRatePerBlock, blocksPerYear); + + const url = `https://dapp.rhomarkets.xyz/market/${underlyingSymbol}`; + + return { + pool, + chain, + project, + poolMeta, + ltv, + tvlUsd, + totalSupplyUsd, + totalBorrowUsd, + apyBase, + apyBaseBorrow, + symbol: underlyingSymbol, + underlyingTokens: [marketInfo.underlying], + url, + }; + }); + + return pools; +}; + +module.exports = { + timetravel: false, + apy: apy, + url: 'https://dapp.rhomarkets.xyz/', +}; diff --git a/src/adaptors/rho-markets/rho-markets.json b/src/adaptors/rho-markets/rho-markets.json new file mode 100644 index 000000000..13ed95906 --- /dev/null +++ b/src/adaptors/rho-markets/rho-markets.json @@ -0,0 +1,94 @@ +[ + { + "type": "constructor", + "inputs": [ + { + "name": "_comptroller", + "type": "address", + "internalType": "address" + }, + { "name": "_oracle", "type": "address", "internalType": "address" } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "comptroller", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "contract Comptroller" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getActiveMarketsInfo", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "tuple[]", + "internalType": "struct MarketState.MarketsInfo[]", + "components": [ + { "name": "tvl", "type": "uint256", "internalType": "uint256" }, + { "name": "ltv", "type": "uint256", "internalType": "uint256" }, + { + "name": "totalSupply", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "totalBorrows", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "supplyRatePerBlock", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "borrowRatePerBlock", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "blocksPerYear", + "type": "uint256", + "internalType": "uint256" + }, + { "name": "token", "type": "address", "internalType": "address" }, + { + "name": "underlying", + "type": "address", + "internalType": "address" + }, + { "name": "symbol", "type": "string", "internalType": "string" }, + { + "name": "underlyingSymbol", + "type": "string", + "internalType": "string" + } + ] + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "oracle", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "contract PriceOracleV2" + } + ], + "stateMutability": "view" + } +]