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

Create an IBT entity to get more IBT Rate precision #156

Merged
merged 2 commits into from
May 27, 2024
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
6 changes: 6 additions & 0 deletions schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,12 @@ type Asset @entity {
ibt: Asset
fytTokenDetails: FYTTokenDetails
lpTokenDetails: LPTokenDetails
"in case the AssetType is IBT we give the IBT Rates"
lastIBTRate: BigDecimal
"IBT to underlying asset as returned by convertToAssets(UNIT). The number is in underlying asset decimals"
convertToAssetsUnit: BigInt
lastUpdateTimestamp: BigInt

}

"AssetPrice entity to assign a price of a token to an Asset entity and its price source"
Expand Down
16 changes: 16 additions & 0 deletions src/entities/ERC20.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
import { Address, BigInt, log } from "@graphprotocol/graph-ts"

import { Asset } from "../../generated/schema"
import { ERC20 } from "../../generated/templates/ERC20/ERC20"
import { ZERO_BI } from "../constants"

const UNKNOWN = "Unknown"

export function getERC20Name(address: Address): string {
let asset = Asset.load(address.toHex())
matstyler marked this conversation as resolved.
Show resolved Hide resolved
if (asset) {
return asset.name
}

let erc20Contract = ERC20.bind(address)

let nameCall = erc20Contract.try_name()
Expand All @@ -21,6 +27,11 @@ export function getERC20Name(address: Address): string {
}

export function getERC20Symbol(address: Address): string {
let asset = Asset.load(address.toHex())
if (asset) {
return asset.symbol
}

let erc20Contract = ERC20.bind(address)

let symbolCall = erc20Contract.try_symbol()
Expand All @@ -36,6 +47,11 @@ export function getERC20Symbol(address: Address): string {
}

export function getERC20Decimals(address: Address): i32 {
let asset = Asset.load(address.toHex())
if (asset) {
return asset.decimals
}

let erc20Contract = ERC20.bind(address)

let decimalsCall = erc20Contract.try_decimals()
Expand Down
38 changes: 36 additions & 2 deletions src/entities/ERC4626.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import { Address, BigInt, log } from "@graphprotocol/graph-ts"

import { Asset } from "../../generated/schema"
import { ERC4626 } from "../../generated/templates/PrincipalToken/ERC4626"
import { UNIT_BI, ZERO_BI } from "../constants"
import { UNIT_BI, ZERO_ADDRESS, ZERO_BI } from "../constants"
import { getERC20Decimals } from "./ERC20"

export function getIBTRate(address: Address): BigInt {
let erc4626Contract = ERC4626.bind(address)
let rate = erc4626Contract.try_convertToAssets(UNIT_BI)
const ibtDecimals = getERC20Decimals(address)
const IBT_UNIT = BigInt.fromI32(10).pow(ibtDecimals as u8)
let rate = erc4626Contract.try_convertToAssets(IBT_UNIT)

if (!rate.reverted) {
return rate.value
Expand All @@ -15,6 +19,36 @@ export function getIBTRate(address: Address): BigInt {
return UNIT_BI
}

export function getERC4626Asset(address: Address): Address {
let erc4626Contract = ERC4626.bind(address)
let asset = erc4626Contract.try_asset()

if (!asset.reverted) {
return asset.value
}

log.warning("asset() call reverted for {}", [address.toHex()])

return ZERO_ADDRESS
}

export function getERC4626UnderlyingDecimals(address: Address): i32 {
let ibtAsset = Asset.load(address.toHex())
if (ibtAsset) {
let underlyingAddress = ibtAsset.underlying
if (underlyingAddress) {
return getERC20Decimals(Address.fromString(underlyingAddress))
}
}
let underlying = getERC4626Asset(address)
return getERC20Decimals(underlying)
}

export function getUnderlyingUnit(address: Address): BigInt {
let underlyingDecimals = getERC4626UnderlyingDecimals(address)
return BigInt.fromI32(10).pow(underlyingDecimals as u8)
}

export function getERC4626Balance(
tokenAddress: Address,
account: Address
Expand Down
43 changes: 43 additions & 0 deletions src/entities/IBTAsset.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { Address, BigInt, Bytes } from "@graphprotocol/graph-ts"

import { Asset } from "../../generated/schema"
import { AssetType } from "../utils"
import { getAsset } from "./Asset"
import { getERC20Decimals } from "./ERC20"
import { getERC4626Asset, getIBTRate, getUnderlyingUnit } from "./ERC4626"
import { getNetwork } from "./Network"

export function getIBTAsset(ibtAddress: Bytes, timestamp: BigInt): Asset {
let ibt = Asset.load(ibtAddress.toString())
if (ibt) {
return ibt
}
ibt = createIBTAsset(ibtAddress, timestamp)
return ibt
}

export function updateIBTRates(ibtAddress: Bytes, timestamp: BigInt): void {
let ibt = getIBTAsset(ibtAddress, timestamp)
let convertToAssets = getIBTRate(Address.fromBytes(ibtAddress))
ibt.convertToAssetsUnit = convertToAssets
const UNDERLYING_UNIT = getUnderlyingUnit(Address.fromBytes(ibtAddress))
ibt.lastIBTRate = convertToAssets.divDecimal(UNDERLYING_UNIT.toBigDecimal())
ibt.lastUpdateTimestamp = timestamp
ibt.save()
}

export function createIBTAsset(ibtAddress: Bytes, timestamp: BigInt): Asset {
let ibt = getAsset(ibtAddress.toHex(), timestamp, AssetType.IBT)
ibt.chainId = getNetwork().chainId
ibt.address = ibtAddress
ibt.createdAtTimestamp = timestamp
let convertToAssets = getIBTRate(Address.fromBytes(ibtAddress))
ibt.convertToAssetsUnit = convertToAssets
const underlying = getERC4626Asset(Address.fromBytes(ibtAddress))
const underlying_decimals = getERC20Decimals(underlying)
const UNDERLYING_UNIT = BigInt.fromI32(10).pow(underlying_decimals as u8)
ibt.lastIBTRate = convertToAssets.divDecimal(UNDERLYING_UNIT.toBigDecimal())
ibt.lastUpdateTimestamp = timestamp
ibt.save()
return ibt as Asset
}
15 changes: 9 additions & 6 deletions src/mappings/futures.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Address, ethereum, log } from "@graphprotocol/graph-ts"
import { Address, Bytes, ethereum, log } from "@graphprotocol/graph-ts"

import {
CurveFactoryChange, // CurveFactoryChange,
Expand All @@ -15,6 +15,7 @@ import {
import {
ERC20, // LPVault as LPVaultTemplate,
PrincipalToken as PrincipalTokenTemplate,
IBT,
} from "../../generated/templates"
import {
FeeClaimed,
Expand Down Expand Up @@ -47,6 +48,7 @@ import {
getTotalAssets,
getYT,
} from "../entities/FutureVault"
import { getIBTAsset } from "../entities/IBTAsset"
import { getNetwork } from "../entities/Network"
import { createPool } from "../entities/Pool"
import { createTransaction } from "../entities/Transaction"
Expand Down Expand Up @@ -104,17 +106,15 @@ export function handlePTDeployed(event: PTDeployed): void {
underlyingAsset.save()

let ibtAddress = getIBT(ptAddress)
let ibtAsset = getAsset(
ibtAddress.toHex(),
event.block.timestamp,
AssetType.IBT
let ibtAsset = getIBTAsset(
Bytes.fromHexString(ibtAddress.toHex()),
event.block.timestamp
)
ibtAsset.underlying = underlyingAsset.id
ibtAsset.save()

newFuture.underlyingAsset = underlyingAddress.toHex()
newFuture.ibtAsset = ibtAddress.toHex()

newFuture.yieldGenerators = []

newFuture.save()
Expand All @@ -140,6 +140,9 @@ export function handlePTDeployed(event: PTDeployed): void {
// Create dynamic data source for PT token events
ERC20.create(event.params.pt)

// Create dynamic data source for IBT token events
IBT.create(ibtAddress)

// Create dynamic data source for YT token events
ERC20.create(Address.fromBytes(ytToken.address))

Expand Down
10 changes: 10 additions & 0 deletions src/mappings/transfers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
updateAccountAssetYTBalance,
} from "../entities/AccountAsset"
import { getAssetAmount } from "../entities/AssetAmount"
import { updateIBTRates } from "../entities/IBTAsset"
import { updateYieldForAll } from "../entities/Yield"
import { AssetType, logWarning } from "../utils"
import { generateTransferId } from "../utils/idGenerators"
Expand Down Expand Up @@ -89,3 +90,12 @@ export function handleTransfer(event: TransferEvent): void {
])
}
}

/** @dev Handles the Transfer event for IBT tokens.
* @param event The Transfer event.
* @notice We use a separate function for IBT tokens because to limit the number of entities stored we won't store all IBT transfer entities. We will simply update the IBT entity to update its IBTRate.
* @returns void
*/
export function handleIBTTransfer(event: TransferEvent): void {
updateIBTRates(event.address, event.block.timestamp)
}
31 changes: 27 additions & 4 deletions src/tests/amm.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { BigInt, ethereum } from "@graphprotocol/graph-ts"
import { Address, BigInt, ethereum } from "@graphprotocol/graph-ts"
import {
describe,
test,
Expand Down Expand Up @@ -63,8 +63,10 @@ import {
POOL_PT_BALANCE_MOCK,
POOL_LP_BALANCE_MOCK,
LP_TOTAL_SUPPLY,
ETH_ADDRESS_MOCK,
} from "./mocks/ERC20"
import {
createAssetCallMock,
createConvertToAssetsCallMock,
createConvertToSharesCallMock,
} from "./mocks/ERC4626"
Expand Down Expand Up @@ -155,7 +157,11 @@ describe("handleAddLiquidity()", () => {
IBT_ADDRESS_MOCK,
toPrecision(BigInt.fromI32(10), 1, 18)
)

createConvertToAssetsCallMock(IBT_ADDRESS_MOCK, 1)
createAssetCallMock(
IBT_ADDRESS_MOCK,
Address.fromString(ETH_ADDRESS_MOCK)
)
emitFactoryUpdated()
emitFutureVaultDeployed(FIRST_FUTURE_VAULT_ADDRESS_MOCK)
emiCurveFactoryChange()
Expand Down Expand Up @@ -448,6 +454,10 @@ describe("handleRemoveLiquidity()", () => {
tokenSupplyParam,
]
createConvertToAssetsCallMock(IBT_ADDRESS_MOCK, 1)
createAssetCallMock(
IBT_ADDRESS_MOCK,
Address.fromString(ETH_ADDRESS_MOCK)
)
handleRemoveLiquidity(removeLiquidityEvent)
})

Expand Down Expand Up @@ -710,7 +720,11 @@ describe("handleTokenExchange()", () => {
boughtIdParam,
tokensBoughtParam,
]

createConvertToAssetsCallMock(IBT_ADDRESS_MOCK, 1)
createAssetCallMock(
IBT_ADDRESS_MOCK,
Address.fromString(ETH_ADDRESS_MOCK)
)
handleTokenExchange(tokenExchangeEvent)
})

Expand Down Expand Up @@ -1039,7 +1053,11 @@ describe("handleRemoveLiquidityOne()", () => {
coinIndexParam,
coinAmountParam,
]

createConvertToAssetsCallMock(IBT_ADDRESS_MOCK, 1)
createAssetCallMock(
IBT_ADDRESS_MOCK,
Address.fromString(ETH_ADDRESS_MOCK)
)
handleRemoveLiquidityOne(removeLiquidityOneEvent)
})

Expand Down Expand Up @@ -1319,6 +1337,11 @@ describe("handleClaimAdminFee", () => {

claimAdminFeeEvent.parameters = [adminParam, tokensParam]

createConvertToAssetsCallMock(IBT_ADDRESS_MOCK, 1)
createAssetCallMock(
IBT_ADDRESS_MOCK,
Address.fromString(ETH_ADDRESS_MOCK)
)
handleClaimAdminFee(claimAdminFeeEvent)
})

Expand Down
18 changes: 15 additions & 3 deletions src/tests/futureDayData.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { BigDecimal, BigInt } from "@graphprotocol/graph-ts"
import { Address, BigDecimal, BigInt } from "@graphprotocol/graph-ts"
import { assert, beforeAll, clearStore, describe, test } from "matchstick-as"

import { FutureDailyStats } from "../../generated/schema"
Expand All @@ -15,8 +15,15 @@ import {
FIRST_POOL_ADDRESS_MOCK,
mockCurvePoolFunctions,
} from "./mocks/CurvePool"
import { mockERC20Balances, mockERC20Functions } from "./mocks/ERC20"
import { createConvertToAssetsCallMockFromString } from "./mocks/ERC4626"
import {
ETH_ADDRESS_MOCK,
mockERC20Balances,
mockERC20Functions,
} from "./mocks/ERC20"
import {
createAssetCallMock,
createConvertToAssetsCallMock,
} from "./mocks/ERC4626"
import { mockFactoryFunctions } from "./mocks/Factory"
import { mockFeedRegistryInterfaceFunctions } from "./mocks/FeedRegistryInterface"
import {
Expand All @@ -39,6 +46,11 @@ describe("APY Computations on futureDailyStats", () => {
mockFeedRegistryInterfaceFunctions()
mockFactoryFunctions()
mockCurvePoolFunctions()
createConvertToAssetsCallMock(IBT_ADDRESS_MOCK, 1)
createAssetCallMock(
IBT_ADDRESS_MOCK,
Address.fromString(ETH_ADDRESS_MOCK)
)

emitFactoryUpdated()
emitFutureVaultDeployed(FIRST_FUTURE_VAULT_ADDRESS_MOCK)
Expand Down
Loading
Loading