Skip to content

Commit

Permalink
Merge pull request #650 from DefiLlama/benqi-lending
Browse files Browse the repository at this point in the history
benqi-lending
  • Loading branch information
dtmkeng committed Jul 22, 2023
2 parents 839eec5 + 699f627 commit 238ad37
Showing 1 changed file with 211 additions and 0 deletions.
211 changes: 211 additions & 0 deletions fees/benqi-lending.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
import { Adapter, ChainBlocks, FetchResultFees } from "../adapters/types"
import { CHAIN } from "../helpers/chains";
import { getBlock } from "../helpers/getBlock";
import * as sdk from "@defillama/sdk";
import { ethers, BigNumber } from "ethers";
import { getPrices } from "../utils/prices";


interface IPrices {
[address: string]: {
decimals: number;
price: number;
symbol: string;
timestamp: number;
};
}

interface IContext {
currentTimestamp: number;
startTimestamp: number;
endTimestamp: number;
startBlock: number;
endBlock: number;
markets: string[];
underlyings: string[];
reserveFactors: string[];
prices: IPrices;
}
interface IAccrueInterestLog {
market: string;
cashPrior: BigNumber;
interestAccumulated: BigNumber;
borrowIndexNew: BigNumber;
totalBorrowsNew: BigNumber;
}

interface ITx {
address: string;
data: string;
topics: string[];
transactionHash: string;
}

const unitroller = "0x486Af39519B4Dc9a7fCcd318217352830E8AD9b4";
const comptrollerABI = {
getAllMarkets: "function getAllMarkets() external view returns (address[])",
};

const topic0_accue_interest = '0x4dec04e750ca11537cabcd8a9eab06494de08da3735bc8871cd41250e190bc04';

const tokenABI = {
underlying: "function underlying() external view returns (address)",
accrueInterest:"event AccrueInterest(uint256 cashPrior,uint256 interestAccumulated,uint256 borrowIndex,uint256 totalBorrows)",
reserveFactorMantissa: "function reserveFactorMantissa() external view returns (uint256)",
};

const contract_interface = new ethers.utils.Interface(Object.values(tokenABI));

const fetch = async (timestamp: number): Promise<FetchResultFees> => {
const context = await getContext(timestamp, {});
const { dailyProtocolFees, dailyProtocolRevenue } = await getDailyProtocolFees(context);
const dailySupplySideRevenue = (dailyProtocolFees - dailyProtocolRevenue);
return {
timestamp,
dailyFees: dailyProtocolFees.toString(),
dailyRevenue: dailyProtocolRevenue.toString(),
dailyHoldersRevenue: dailyProtocolRevenue.toString(),
dailySupplySideRevenue: `${dailySupplySideRevenue}`
}
}

const getAllMarkets = async (
unitroller: string,
chain: CHAIN
): Promise<string[]> => {
return (
await sdk.api.abi.call({
target: unitroller,
abi: comptrollerABI.getAllMarkets,
chain: chain,
})
).output;
};

const getContext = async (timestamp: number, _: ChainBlocks): Promise<IContext> => {
const fromTimestamp = timestamp - 60 * 60 * 24
const toTimestamp = timestamp
const fromBlock = (await getBlock(fromTimestamp, CHAIN.AVAX, {}));
const toBlock = (await getBlock(toTimestamp, CHAIN.AVAX, {}));

const allMarketAddressess = await getAllMarkets(unitroller, CHAIN.AVAX);
const { underlyings, reserveFactors } = await getMarketDetails(allMarketAddressess,CHAIN.AVAX);

const prices = await getPrices(
[
...underlyings.filter((e: string) => e).map((x: string) => `${CHAIN.AVAX}:${x.toLowerCase()}`),
],
timestamp
);

return {
currentTimestamp: timestamp,
startTimestamp: fromTimestamp,
endTimestamp: toTimestamp,
startBlock: fromBlock,
endBlock: toBlock,
markets: allMarketAddressess,
underlyings,
reserveFactors,
prices,
};
};

const getMarketDetails = async (markets: string[], chain: CHAIN): Promise<{underlyings: string[], reserveFactors:string[]}> => {
const underlyings = await sdk.api.abi.multiCall({
calls: markets.map((market: string) => ({
target: market,
})),
abi: tokenABI.underlying,
chain: chain,
permitFailure: true,
});

const reserveFactors = await sdk.api.abi.multiCall({
calls: markets.map((market: string) => ({
target: market,
})),
abi: tokenABI.reserveFactorMantissa,
chain: chain,
permitFailure: true,
});
const _underlyings = underlyings.output.map((x: any) => x.output);
_underlyings[0] = '0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7';
return {
underlyings: _underlyings,
reserveFactors: reserveFactors.output.map((x: any) => x.output),
};
};


const getDailyProtocolFees = async ({
markets,
underlyings,
reserveFactors,
prices,
startBlock,
endBlock,
}: IContext) => {
let dailyProtocolFees = 0;
let dailyProtocolRevenue = 0;
const logs: ITx[] = (await Promise.all(
markets.map((address: string) => sdk.api.util.getLogs({
target: address,
topic: '',
toBlock: endBlock,
fromBlock: startBlock,
keys: [],
chain: CHAIN.AVAX,
topics: [topic0_accue_interest]
}))))
.map((e: any) => e)
.map(e => e.output).flat();

const raw_data: IAccrueInterestLog[] = logs.map((e: ITx) => {
const x = contract_interface.parseLog(e);
return {
market: e.address,
cashPrior: x.args.cashPrior,
interestAccumulated: x.args.interestAccumulated,
borrowIndexNew: x.args.borrowIndex,
totalBorrowsNew: x.args.totalBorrows,
}
});

raw_data.forEach((log: IAccrueInterestLog) => {
const marketIndex = markets.findIndex((e: string) => e === log.market);
const underlying = underlyings[marketIndex].toLowerCase();
const price = prices[`${CHAIN.AVAX}:${underlying?.toLowerCase()}`];

const interestTokens = +ethers.utils.formatUnits(
log.interestAccumulated,
price?.decimals || 0
);
const reserveFactor = +ethers.utils.formatUnits(
reserveFactors[marketIndex],
18
);
const interestUSD = interestTokens * price?.price || 0;

dailyProtocolFees += interestUSD;
dailyProtocolRevenue += interestUSD * reserveFactor;
});

return {
dailyProtocolFees,
dailyProtocolRevenue,
};
};


const adapter: Adapter = {
adapter: {
[CHAIN.AVAX]: {
fetch: fetch,
start: async () => 1664582400,
runAtCurrTime: true,
},
},
};

export default adapter;

0 comments on commit 238ad37

Please sign in to comment.