Skip to content

Commit

Permalink
refactor: read underlying decimals to calculate exchange rate
Browse files Browse the repository at this point in the history
  • Loading branch information
coreyar committed Dec 12, 2024
1 parent 6bb9bd1 commit 166e2f3
Show file tree
Hide file tree
Showing 6 changed files with 62 additions and 19 deletions.
10 changes: 9 additions & 1 deletion subgraphs/etherfi-promo/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,12 @@ type TVL @entity {
Entity to iterate over suppliers
"""
type Supply @entity {
"Token Address"
"VToken Address"
id: Bytes!
"Address of the asset"
underlyingAddress: Bytes!
"Decimals of the asset"
underlyingDecimals: Int!
suppliers: [SupplierAccount!]! @derivedFrom(field: "token")
}

Expand All @@ -21,6 +25,10 @@ Entity to iterate over borrowers
type Borrow @entity {
"Token Address"
id: Bytes!
"Address of the asset"
underlyingAddress: Bytes!
"Decimals of the asset"
underlyingDecimals: Int!
borrowers: [BorrowerAccount!]! @derivedFrom(field: "token")
}

Expand Down
31 changes: 18 additions & 13 deletions subgraphs/etherfi-promo/src/mappings/vToken.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,28 @@ import { getBorrow, getSupply } from '../operations/get';
import { getOrCreateBorrowerAccount, getOrCreateSupplierAccount } from '../operations/getOrCreate';
import { updateBorrowerAccount, updateSupplierAccount, updateTvl } from '../operations/update';
import exponentToBigDecimal from '../utilities/exponentToBigDecimal';
import exponentToBigInt from '../utilities/exponentToBigInt';

export function handleMint(event: Mint): void {
const minter = event.params.minter;
const supplierAccount = getOrCreateSupplierAccount(minter, event.address);
const vToken = getSupply(event.address);
updateSupplierAccount(
minter,
event.address,
supplierAccount.effective_balance.plus(
event.params.mintAmount.toBigDecimal().div(exponentToBigDecimal(18)),
event.params.mintAmount.toBigDecimal().div(exponentToBigDecimal(vToken.underlyingDecimals)),
),
);
}

export function handleBorrow(event: Borrow): void {
const borrower = event.params.borrower;
const vToken = getBorrow(event.address);
getOrCreateBorrowerAccount(borrower, event.address);
updateBorrowerAccount(
borrower,
event.address,
event.params.accountBorrows.toBigDecimal().div(exponentToBigDecimal(18)),
event.params.accountBorrows.toBigDecimal().div(exponentToBigDecimal(vToken.underlyingDecimals)),
);
}

Expand All @@ -37,6 +38,7 @@ export function handleTransfer(event: Transfer): void {
const fromAccountAddress = event.params.from;
// If the to account is the vToken address we assume it was a redeem
const toAccountAddress = event.params.to;
const vToken = getSupply(event.address);

if (
fromAccountAddress.notEqual(event.address) &&
Expand All @@ -45,25 +47,23 @@ export function handleTransfer(event: Transfer): void {
) {
const vTokenContract = VTokenContract.bind(event.address);
const exchangeRateMantissa = vTokenContract.exchangeRateCurrent();

const amountUnderlying = exchangeRateMantissa
.times(event.params.amount)
.div(exponentToBigInt(18));
.toBigDecimal()
.div(exponentToBigDecimal(18 + vToken.underlyingDecimals));
const fromAccount = getOrCreateSupplierAccount(fromAccountAddress, event.address);
updateSupplierAccount(
fromAccountAddress,
event.address,
fromAccount.effective_balance.minus(
amountUnderlying.toBigDecimal().div(exponentToBigDecimal(18)),
),
fromAccount.effective_balance.minus(amountUnderlying),
);
// To
const toAccount = getOrCreateSupplierAccount(toAccountAddress, event.address);
updateSupplierAccount(
toAccountAddress,
event.address,
toAccount.effective_balance.plus(
amountUnderlying.toBigDecimal().div(exponentToBigDecimal(18)),
),
toAccount.effective_balance.plus(amountUnderlying),
);
}
}
Expand All @@ -72,23 +72,28 @@ export function handleAccrueInterest(event: AccrueInterest): void {
const supply = getSupply(event.address);
supply.suppliers.load().forEach(supplier => {
const vTokenContract = VTokenContract.bind(Address.fromBytes(supplier.token));
const vToken = getSupply(Address.fromBytes(supplier.token));

const exchangeRateMantissa = vTokenContract.exchangeRateCurrent();
const vTokenBalance = vTokenContract.balanceOf(Address.fromBytes(supplier.address));
const amountUnderlying = exchangeRateMantissa.times(vTokenBalance).div(exponentToBigInt(18));
supplier.effective_balance = amountUnderlying.toBigDecimal().div(exponentToBigDecimal(18));
const amountUnderlying = exchangeRateMantissa
.times(vTokenBalance)
.toBigDecimal()
.div(exponentToBigDecimal(18 + vToken.underlyingDecimals));
supplier.effective_balance = amountUnderlying;
supplier.save();
});

const borrow = getBorrow(event.address);
borrow.borrowers.load().forEach(borrower => {
const vTokenContract = VTokenContract.bind(Address.fromBytes(borrower.token));
const vToken = getBorrow(Address.fromBytes(borrower.token));
const underlyingBorrowBalance = vTokenContract.borrowBalanceCurrent(
Address.fromBytes(borrower.address),
);
borrower.effective_balance = underlyingBorrowBalance
.toBigDecimal()
.div(exponentToBigDecimal(18));
.div(exponentToBigDecimal(vToken.underlyingDecimals));
borrower.save();
});

Expand Down
15 changes: 14 additions & 1 deletion subgraphs/etherfi-promo/src/operations/get.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Address } from '@graphprotocol/graph-ts';

import { VToken } from '../../generated/vWeETH/VToken';
import { Borrow, BorrowerAccount, SupplierAccount, Supply, TVL } from '../../generated/schema';
import { zeroBigDecimal } from '../constants';
import { getPositionId } from '../utilities/ids';
Expand All @@ -19,6 +19,13 @@ export const getSupply = (tokenAddress: Address): Supply => {
let supply = Supply.load(tokenAddress);
if (!supply) {
supply = new Supply(tokenAddress);

const vTokenContract = VToken.bind(tokenAddress);
const underlyingAddress = vTokenContract.underlying();
const erc20 = VToken.bind(underlyingAddress);

supply.underlyingAddress = underlyingAddress;
supply.underlyingDecimals = erc20.decimals();
}
supply.save();
return supply;
Expand All @@ -36,6 +43,12 @@ export const getBorrow = (tokenAddress: Address): Borrow => {
let borrow = Borrow.load(tokenAddress);
if (!borrow) {
borrow = new Borrow(tokenAddress);
const vTokenContract = VToken.bind(tokenAddress);
const underlyingAddress = vTokenContract.underlying();
const erc20 = VToken.bind(underlyingAddress);

borrow.underlyingAddress = underlyingAddress;
borrow.underlyingDecimals = erc20.decimals();
}
borrow.save();
return borrow;
Expand Down
5 changes: 3 additions & 2 deletions subgraphs/etherfi-promo/src/operations/update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Address, BigDecimal, ethereum } from '@graphprotocol/graph-ts';
import { BorrowerAccount, SupplierAccount, TVL } from '../../generated/schema';
import { ERC20 as ERC20Contract } from '../../generated/vWeETH/ERC20';
import { VToken as VTokenContract } from '../../generated/vWeETH/VToken';
import { getBorrowerAccount, getSupplierAccount, getTvl } from './get';
import { getBorrowerAccount, getSupplierAccount, getTvl, getSupply } from './get';
import exponentToBigDecimal from '../utilities/exponentToBigDecimal';

export function updateSupplierAccount(
Expand Down Expand Up @@ -31,6 +31,7 @@ export function updateBorrowerAccount(
export function updateTvl(event: ethereum.Event): TVL {
const vTokenContract = VTokenContract.bind(event.address);
const underlyingAddress = vTokenContract.underlying();
const vToken = getSupply(event.address);
const underlyingContract = ERC20Contract.bind(underlyingAddress);
const tvl = getTvl(event.address);
const totalBorrows = vTokenContract.totalBorrowsCurrent();
Expand All @@ -40,7 +41,7 @@ export function updateTvl(event: ethereum.Event): TVL {
.plus(totalBorrows)
.minus(totalReserves)
.toBigDecimal()
.div(exponentToBigDecimal(18));
.div(exponentToBigDecimal(vToken.underlyingDecimals));
tvl.save();
return tvl;
}
2 changes: 1 addition & 1 deletion subgraphs/etherfi-promo/tests/VToken/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ const cleanup = (): void => {
};

beforeAll(() => {
createVBep20Mock(vTokenAddress, exchangeRateCurrent);
createVBep20Mock(vTokenAddress, underlyingAddress, exchangeRateCurrent);
});

afterEach(() => {
Expand Down
18 changes: 17 additions & 1 deletion subgraphs/etherfi-promo/tests/VToken/mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,24 @@ export const mockPriceOracleAddress = Address.fromString(
'0xb0b0000000000000000000000000000000000000',
);

export const createVBep20Mock = (contractAddress: Address, exchangeRateCurrent: BigInt): void => {
export const createVBep20Mock = (
contractAddress: Address,
underlyingAddress: Address,
exchangeRateCurrent: BigInt,
): void => {
createMockedFunction(
contractAddress,
'exchangeRateCurrent',
'exchangeRateCurrent():(uint256)',
).returns([ethereum.Value.fromUnsignedBigInt(exchangeRateCurrent)]);

createMockedFunction(contractAddress, 'underlying', 'underlying():(address)').returns([
ethereum.Value.fromAddress(underlyingAddress),
]);

createMockedFunction(underlyingAddress, 'decimals', 'decimals():(uint8)').returns([
ethereum.Value.fromI32(18),
]);
};

export const createBep20Mock = (
Expand All @@ -21,6 +33,10 @@ export const createBep20Mock = (
createMockedFunction(contractAddress, 'balanceOf', 'balanceOf(address):(uint256)')
.withArgs([ethereum.Value.fromAddress(accountAddress)])
.returns([ethereum.Value.fromUnsignedBigInt(balanceOf)]);

createMockedFunction(contractAddress, 'decimals', 'decimals():(uint8)').returns([
ethereum.Value.fromI32(18),
]);
};

export const createAccountVTokenBalanceOfMock = (
Expand Down

0 comments on commit 166e2f3

Please sign in to comment.