Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

copied apy calculation code from solend-lite to sdk (calculation was broken) #70

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/liquidator.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ jobs:
working-directory: ./liquidator
steps:
- uses: actions/checkout@v3
- name: Use Node.js 16
- name: Use Node.js 18
uses: actions/setup-node@v3
with:
node-version: 16
node-version: 18
- name: Install dependencies
run: yarn install --immutable --immutable-cache --check-cache
- name: Lint
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/solend-sdk.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ jobs:
working-directory: ./solend-sdk
steps:
- uses: actions/checkout@v3
- name: Use Node.js 16
- name: Use Node.js 18
uses: actions/setup-node@v3
with:
node-version: 16
node-version: 18
- name: Install dependencies
run: yarn install --immutable --immutable-cache --check-cache
- name: Lint
Expand Down
2 changes: 1 addition & 1 deletion solend-sdk/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@solendprotocol/solend-sdk",
"version": "0.6.52",
"version": "0.6.53",
"private": true,
"main": "src/index.ts",
"module": "src/index.ts",
Expand Down
88 changes: 20 additions & 68 deletions solend-sdk/src/classes/reserve.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { parseReserve } from "../state/reserve";
import BN from "bn.js";
import { WAD, WANG } from "./constants";
import { ReserveConfigType, RewardsDataType, ReserveDataType } from "./shared";
import { SLOTS_PER_YEAR } from "../core/constants";
import { calculateBorrowInterest, calculateSupplyInterest } from "../core";

type ParsedReserve = NonNullable<ReturnType<typeof parseReserve>>["info"];

Expand All @@ -29,69 +29,19 @@ export class SolendReserve {
}

private calculateSupplyAPY = (reserve: ParsedReserve) => {
const apr = this.calculateSupplyAPR(reserve);
const apy =
new BigNumber(1)
.plus(new BigNumber(apr).dividedBy(SLOTS_PER_YEAR))
.toNumber() **
SLOTS_PER_YEAR -
1;
return apy;
return calculateSupplyInterest(reserve, true).toNumber();
};

private calculateBorrowAPY = (reserve: ParsedReserve) => {
const apr = this.calculateBorrowAPR(reserve);
const apy =
new BigNumber(1)
.plus(new BigNumber(apr).dividedBy(SLOTS_PER_YEAR))
.toNumber() **
SLOTS_PER_YEAR -
1;
return apy;
return calculateBorrowInterest(reserve, true).toNumber();
};

private calculateSupplyAPR(reserve: ParsedReserve) {
const currentUtilization = this.calculateUtilizationRatio(reserve);

const borrowAPY = this.calculateBorrowAPR(reserve);
return currentUtilization * borrowAPY;
}

private calculateUtilizationRatio(reserve: ParsedReserve) {
const totalBorrowsWads = new BigNumber(
reserve.liquidity.borrowedAmountWads.toString()
).div(WAD);
const currentUtilization = totalBorrowsWads
.dividedBy(
totalBorrowsWads.plus(reserve.liquidity.availableAmount.toString())
)
.toNumber();

return currentUtilization;
return calculateSupplyInterest(reserve, false).toNumber();
}

private calculateBorrowAPR(reserve: ParsedReserve) {
const currentUtilization = this.calculateUtilizationRatio(reserve);
const optimalUtilization = reserve.config.optimalUtilizationRate / 100;

let borrowAPR;
if (optimalUtilization === 1.0 || currentUtilization < optimalUtilization) {
const normalizedFactor = currentUtilization / optimalUtilization;
const optimalBorrowRate = reserve.config.optimalBorrowRate / 100;
const minBorrowRate = reserve.config.minBorrowRate / 100;
borrowAPR =
normalizedFactor * (optimalBorrowRate - minBorrowRate) + minBorrowRate;
} else {
const normalizedFactor =
(currentUtilization - optimalUtilization) / (1 - optimalUtilization);
const optimalBorrowRate = reserve.config.optimalBorrowRate / 100;
const maxBorrowRate = reserve.config.maxBorrowRate / 100;
borrowAPR =
normalizedFactor * (maxBorrowRate - optimalBorrowRate) +
optimalBorrowRate;
}

return borrowAPR;
return calculateBorrowInterest(reserve, false).toNumber();
}

setBuffer(buffer: AccountInfo<Buffer> | null) {
Expand All @@ -105,23 +55,23 @@ export class SolendReserve {
if (!this.buffer) {
this.buffer = await this.connection.getAccountInfo(
new PublicKey(this.config.address),
"processed"
"processed",
);
}

if (!this.buffer) {
throw Error(
`Error requesting account info for ${this.config.liquidityToken.name}`
`Error requesting account info for ${this.config.liquidityToken.name}`,
);
}

const parsedData = parseReserve(
new PublicKey(this.config.address),
this.buffer
this.buffer,
)?.info;
if (!parsedData) {
throw Error(
`Unable to parse data of reserve ${this.config.liquidityToken.name}`
`Unable to parse data of reserve ${this.config.liquidityToken.name}`,
);
}

Expand All @@ -133,7 +83,7 @@ export class SolendReserve {
poolSize: string,
rewardPrice: number,
tokenPrice: number,
decimals: number
decimals: number,
) {
const poolValueUSD = new BigNumber(poolSize)
.times(tokenPrice)
Expand Down Expand Up @@ -162,14 +112,14 @@ export class SolendReserve {
stats.totalDepositsWads.toString(),
reward.price,
stats.assetPriceUSD,
this.config.liquidityToken.decimals
this.config.liquidityToken.decimals,
).toNumber(),
price: reward.price,
}));

const totalAPY = new BigNumber(stats.supplyInterestAPY)
.plus(
rewards.reduce((acc, reward) => acc.plus(reward.apy), new BigNumber(0))
rewards.reduce((acc, reward) => acc.plus(reward.apy), new BigNumber(0)),
)
.toNumber();

Expand All @@ -196,14 +146,14 @@ export class SolendReserve {
stats.totalBorrowsWads.toString(),
reward.price,
stats.assetPriceUSD,
this.config.liquidityToken.decimals
this.config.liquidityToken.decimals,
).toNumber(),
price: reward.price,
}));

const totalAPY = new BigNumber(stats.borrowInterestAPY)
.minus(
rewards.reduce((acc, reward) => acc.plus(reward.apy), new BigNumber(0))
rewards.reduce((acc, reward) => acc.plus(reward.apy), new BigNumber(0)),
)
.toNumber();

Expand All @@ -215,11 +165,11 @@ export class SolendReserve {
}

private formatReserveData(
parsedData: NonNullable<ReturnType<typeof parseReserve>>["info"]
parsedData: NonNullable<ReturnType<typeof parseReserve>>["info"],
): ReserveDataType {
const totalBorrowsWads = parsedData.liquidity.borrowedAmountWads;
const totalLiquidityWads = parsedData.liquidity.availableAmount.mul(
new BN(WAD)
new BN(WAD),
);
const totalDepositsWads = totalBorrowsWads.add(totalLiquidityWads);
const cTokenExchangeRate = new BigNumber(totalDepositsWads.toString())
Expand All @@ -238,13 +188,13 @@ export class SolendReserve {
maxBorrowRate: parsedData.config.maxBorrowRate / 100,
protocolTakeRate: parsedData.config.protocolTakeRate / 100,
borrowFeePercentage: new BigNumber(
parsedData.config.fees.borrowFeeWad.toString()
parsedData.config.fees.borrowFeeWad.toString(),
)
.dividedBy(WAD)
.toNumber(),
hostFeePercentage: parsedData.config.fees.hostFeePercentage / 100,
flashLoanFeePercentage: new BigNumber(
parsedData.config.fees.flashLoanFeeWad.toString()
parsedData.config.fees.flashLoanFeeWad.toString(),
)
.dividedBy(WAD)
.toNumber(),
Expand All @@ -262,6 +212,8 @@ export class SolendReserve {
totalLiquidityWads,
supplyInterestAPY: this.calculateSupplyAPY(parsedData),
borrowInterestAPY: this.calculateBorrowAPY(parsedData),
supplyInterestAPR: this.calculateSupplyAPR(parsedData),
borrowInterestAPR: this.calculateBorrowAPR(parsedData),
assetPriceUSD: new BigNumber(parsedData.liquidity.marketPrice.toString())
.div(WAD)
.toNumber(),
Expand Down
2 changes: 2 additions & 0 deletions solend-sdk/src/classes/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ export type ReserveDataType = {
totalLiquidityWads: BN;
supplyInterestAPY: number;
borrowInterestAPY: number;
supplyInterestAPR: number;
borrowInterestAPR: number;
assetPriceUSD: number;
protocolTakeRate: number;
userDepositLimit?: number;
Expand Down
16 changes: 8 additions & 8 deletions solend-sdk/src/core/utils/rates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,18 @@ const calculateSupplyAPR = (reserve: Reserve) => {

const borrowAPR = calculateBorrowAPR(reserve);
const protocolTakePercentage = BigNumber(1).minus(
reserve.config.protocolTakeRate / 100
reserve.config.protocolTakeRate / 100,
);

return currentUtilization.times(borrowAPR).times(protocolTakePercentage);
};

const calculateUtilizationRatio = (reserve: Reserve) => {
const borrowedAmount = new BigNumber(
reserve.liquidity.borrowedAmountWads.toString()
reserve.liquidity.borrowedAmountWads.toString(),
).shiftedBy(-18);
const totalSupply = borrowedAmount.plus(
reserve.liquidity.availableAmount.toString()
reserve.liquidity.availableAmount.toString(),
);
const currentUtilization = borrowedAmount.dividedBy(totalSupply);

Expand All @@ -28,10 +28,10 @@ const calculateUtilizationRatio = (reserve: Reserve) => {
const calculateBorrowAPR = (reserve: Reserve) => {
const currentUtilization = calculateUtilizationRatio(reserve);
const optimalUtilization = new BigNumber(
reserve.config.optimalUtilizationRate / 100
reserve.config.optimalUtilizationRate / 100,
);
const maxUtilizationRate = new BigNumber(
reserve.config.maxUtilizationRate / 100
reserve.config.maxUtilizationRate / 100,
);
let borrowAPR;
if (currentUtilization.isLessThanOrEqualTo(optimalUtilization)) {
Expand All @@ -42,7 +42,7 @@ const calculateBorrowAPR = (reserve: Reserve) => {
const normalizedFactor = currentUtilization.dividedBy(optimalUtilization);

const optimalBorrowRate = new BigNumber(
reserve.config.optimalBorrowRate / 100
reserve.config.optimalBorrowRate / 100,
);

borrowAPR = normalizedFactor
Expand All @@ -54,7 +54,7 @@ const calculateBorrowAPR = (reserve: Reserve) => {
.dividedBy(maxUtilizationRate.minus(optimalUtilization));

const optimalBorrowRate = new BigNumber(
reserve.config.optimalBorrowRate / 100
reserve.config.optimalBorrowRate / 100,
);
const maxBorrowRate = new BigNumber(reserve.config.maxBorrowRate / 100);

Expand All @@ -68,7 +68,7 @@ const calculateBorrowAPR = (reserve: Reserve) => {

const maxBorrowRate = new BigNumber(reserve.config.maxBorrowRate / 100);
const superMaxBorrowRate = new BigNumber(
reserve.config.superMaxBorrowRate.toNumber() / 100
reserve.config.superMaxBorrowRate.toNumber() / 100,
);

borrowAPR = weight
Expand Down
Loading