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

update Position schema; add PositionLend entity #62

Merged
merged 20 commits into from
Aug 24, 2023
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
29 changes: 23 additions & 6 deletions schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,8 @@ type Bucket @entity {
lpb: BigDecimal!
# list of lends associated with the bucket
lends: [Lend!]!
# list of PositionLends associated with the bucket
positionLends: [PositionLend!]!
}

# lend occurs per bucket in a pool
Expand Down Expand Up @@ -234,6 +236,9 @@ type Account @entity {
# amount of tokens delegated to this account
tokensDelegated: BigDecimal!

# positions associated with the account
positions: [Position!]!

# total number of transactions sent by the account
txCount: BigInt!
}
Expand Down Expand Up @@ -707,12 +712,24 @@ type MergeOrRemoveCollateralNFT @entity(immutable: true) {
# # # # # # # # # # # # # # #

type Position @entity {
id: Bytes! # byte encoded tokenId
tokenId: BigInt # tokenId
indexes: [Lend!]! # list of lends which constitute a position
owner: Bytes! # address of the position owner
pool: Bytes! # address of the pool that the position is associated with
token: Token! # pointer to positionNFT
id: Bytes! # byte encoded tokenId
tokenId: BigInt # tokenId
indexes: [PositionLend!]! # list of PositionLends which constitute a position
owner: Bytes! # address of the position owner
pool: Bytes! # address of the pool that the position is associated with
token: Token! # pointer to LPToken entity
tokenURI: String! # tokenURI of the positionNFT
}

# created to handle the seperate lpb positions for each bucket index
type PositionLend @entity {
id: Bytes! # $positionId + '|' + $bucketIndex
bucket: Bucket! # pointer to associated Bucket entity
bucketIndex: Int! # index of the bucket with lpb
depositTime: BigInt! # time at which the position was deposited
lpb: BigDecimal! # amount of LPB position has in the bucket
lpbValueInQuote: BigDecimal! # quote equivalent value of LPB in the bucket
tokenId: BigInt! # tokenId of the position
}

# # # # # # # # # # # # # #
Expand Down
13 changes: 10 additions & 3 deletions src/mappings/base/base-pool.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Address, BigInt, Bytes, ethereum, log } from "@graphprotocol/graph-ts"
import { Account, AddQuoteToken, Bucket, BucketBankruptcy, Flashloan, Lend, LoanStamped, MoveQuoteToken, Pool, RemoveQuoteToken, ReserveAuctionKick, ReserveAuctionTake, Token, TransferLP, UpdateInterestRate } from "../../../generated/schema"
import { Account, AddQuoteToken, Bucket, BucketBankruptcy, Flashloan, Lend, LoanStamped, MoveQuoteToken, Pool, PositionLend, RemoveQuoteToken, ReserveAuctionKick, ReserveAuctionTake, Token, TransferLP, UpdateInterestRate } from "../../../generated/schema"
import {
AddQuoteToken as AddQuoteTokenERC20Event,
MoveQuoteToken as MoveQuoteTokenERC20Event,
Expand All @@ -22,6 +22,7 @@ import { addReserveAuctionToPool, getBurnInfo, getLenderInfo, isERC20Pool, updat
import { incrementTokenTxCount as incrementTokenTxCountERC20Pool } from "../../utils/token-erc20"
import { incrementTokenTxCount as incrementTokenTxCountERC721Pool } from "../../utils/token-erc721"
import { loadOrCreateReserveAuction, reserveAuctionKickerReward } from "../../utils/pool/reserve-auction"
import { saveOrRemovePositionLend } from "../../utils/position"


/*******************************/
Expand Down Expand Up @@ -629,15 +630,21 @@ export function _handleBucketBankruptcy(event: ethereum.Event, index: BigInt, lp
for (let i = 0; i < bucket.lends.length; i++) {
const lendId = bucket.lends[i]
const lend = Lend.load(lendId)!
lend.depositTime = bucketBankruptcy.blockTimestamp.plus(ONE_BI)
lend.lpb = ZERO_BD
lend.lpbValueInQuote = ZERO_BD
updateBucketLends(bucket, lend)
updateAccountLends(loadOrCreateAccount(lend.lender), lend)
// remove lend from store
saveOrRemoveLend(lend)
}

// iterate through all bucket positionLends and set positionLend.lpb to zero
for (let i = 0; i < bucket.positionLends.length; i++) {
const positionLendId = bucket.positionLends[i]
const positionLend = PositionLend.load(positionLendId)!
positionLend.lpb = ZERO_BD
saveOrRemovePositionLend(positionLend)
}

// save entities to store
pool.save()
bucket.save()
Expand Down
132 changes: 93 additions & 39 deletions src/mappings/position-manager.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Address, log } from "@graphprotocol/graph-ts"
import { Address, BigInt, log } from "@graphprotocol/graph-ts"
import {
Approval as ApprovalEvent,
ApprovalForAll as ApprovalForAllEvent,
Expand All @@ -12,6 +12,7 @@ import {
import {
Approval,
ApprovalForAll,
Bucket,
Burn,
MemorializePosition,
Mint,
Expand All @@ -22,10 +23,12 @@ import {
import { getBucketId } from "../utils/pool/bucket"
import { lpbValueInQuote, saveOrRemoveLend } from "../utils/pool/lend"
import { ONE_BI, ZERO_BD } from "../utils/constants"
import { addressToBytes, bigIntArrayToIntArray, wadToDecimal } from "../utils/convert"
import { addressToBytes, bigIntArrayToIntArray, bigIntToBytes, wadToDecimal } from "../utils/convert"
import { getLendId, loadOrCreateLend } from "../utils/pool/lend"
import { deletePosition, getPoolForToken, loadOrCreateLPToken, loadOrCreatePosition } from "../utils/position"
import { deletePosition, getPoolForToken, getPositionInfo, getPositionLendId, loadOrCreateLPToken, loadOrCreatePosition, loadOrCreatePositionLend, saveOrRemovePositionLend, updatePositionLends } from "../utils/position"
import { getLenderInfo } from "../utils/pool/pool"
import { getTokenURI } from "../utils/token-erc721"
import { loadOrCreateAccount, updateAccountPositions } from "../utils/account"

export function handleApproval(event: ApprovalEvent): void {
const approval = new Approval(
Expand Down Expand Up @@ -68,11 +71,19 @@ export function handleBurn(event: BurnEvent): void {
burn.blockTimestamp = event.block.timestamp
burn.transactionHash = event.transaction.hash

// remove tokenId from account's list of positions
const account = loadOrCreateAccount(burn.lender)
const index = account.positions.indexOf(bigIntToBytes(burn.tokenId))
const accountPositions = account.positions
if (index != -1) accountPositions.splice(index, 1)
account.positions = accountPositions
deletePosition(event.params.tokenId);

account.save()
burn.save()
}

// Lends are updated in the associated `TransferLP` event
export function handleMemorializePosition(
event: MemorializePositionEvent
): void {
Expand All @@ -98,15 +109,25 @@ export function handleMemorializePosition(

log.info("handleMemorializePosition for lender {} token {}" , [accountId.toHexString(), memorialize.tokenId.toString()])

const positionIndexes = position.indexes;
for (let i = 0; i < memorialize.indexes.length; i++) {
const index = memorialize.indexes[i];
const bucketId = getBucketId(poolAddress, index)
const lendId = getLendId(bucketId, accountId)
// add lend to position
positionIndexes.push(lendId)
const bucket = Bucket.load(bucketId)!

// create PositionLend entity to track each lpb associated with the position
const positionLendId = getPositionLendId(memorialize.tokenId, BigInt.fromI32(index))
const positionLend = loadOrCreatePositionLend(memorialize.tokenId, bucketId, index)
const positionInfo = getPositionInfo(memorialize.tokenId, BigInt.fromI32(index))
//track the lpb and depositTime associated with each lend that was memorialized via RPC call
positionLend.depositTime = positionInfo.depositTime
positionLend.lpb = wadToDecimal(positionInfo.lpb)
positionLend.lpbValueInQuote = lpbValueInQuote(memorialize.pool, index, positionLend.lpb)
positionLend.save()

// associate positionLend with Bucket and Position
updatePositionLends(positionLend)
bucket.save()
}
position.indexes = positionIndexes

// save entities to store
memorialize.save()
Expand Down Expand Up @@ -135,8 +156,13 @@ export function handleMint(event: MintEvent): void {
position.token = token.id
token.txCount = token.txCount.plus(ONE_BI);

// associate the new position with the lender account
const minterAccount = loadOrCreateAccount(mint.lender)
updateAccountPositions(minterAccount, position)

// save entities to store
mint.save()
minterAccount.save()
position.save()
token.save()
}
Expand All @@ -151,36 +177,51 @@ export function handleMoveLiquidity(event: MoveLiquidityEvent): void {
moveLiquidity.fromIndex = event.params.fromIndex.toU32()
moveLiquidity.toIndex = event.params.toIndex.toU32()

const bucketIdFrom = getBucketId(moveLiquidity.pool, moveLiquidity.fromIndex)
const lendIdFrom = getLendId(bucketIdFrom, moveLiquidity.lender)
const lendFrom = loadOrCreateLend(bucketIdFrom, lendIdFrom, moveLiquidity.pool, moveLiquidity.fromIndex, moveLiquidity.lender)
const bucketIdTo = getBucketId(moveLiquidity.pool, moveLiquidity.toIndex)
const lendIdTo = getLendId(bucketIdTo, moveLiquidity.lender)
const lendTo = loadOrCreateLend(bucketIdTo, lendIdTo, moveLiquidity.pool, moveLiquidity.toIndex, moveLiquidity.lender)

const lendToInfo = getLenderInfo(moveLiquidity.pool, event.params.toIndex, Address.fromBytes(lendTo.lender))
lendTo.depositTime = lendToInfo.depositTime
lendTo.lpb = wadToDecimal(lendToInfo.lpBalance)
lendTo.lpbValueInQuote = lpbValueInQuote(moveLiquidity.pool, moveLiquidity.toIndex, lendTo.lpb)
const lpRedeemedFrom = wadToDecimal(event.params.lpRedeemedFrom)
if (lpRedeemedFrom.le(lendFrom.lpb)) {
lendFrom.lpb = lendFrom.lpb.minus(wadToDecimal(event.params.lpRedeemedFrom))
} else {
log.warning('handleMoveLiquidity: lender {} redeemed more LP ({}) than Lend entity was aware of ({}); resetting to 0',
[moveLiquidity.lender.toHexString(), lpRedeemedFrom.toString(), lendFrom.lpb.toString()])
lendFrom.lpb = ZERO_BD
}
lendFrom.lpbValueInQuote = lpbValueInQuote(moveLiquidity.pool, moveLiquidity.toIndex, lendFrom.lpb)
saveOrRemoveLend(lendFrom)
lendTo.save()
moveLiquidity.blockNumber = event.block.number
moveLiquidity.blockTimestamp = event.block.timestamp
moveLiquidity.transactionHash = event.transaction.hash

// update Token tx count
const token = loadOrCreateLPToken(event.address)
token.txCount = token.txCount.plus(ONE_BI);

moveLiquidity.blockNumber = event.block.number
moveLiquidity.blockTimestamp = event.block.timestamp
moveLiquidity.transactionHash = event.transaction.hash
// load from index state
const bucketIdFrom = getBucketId(moveLiquidity.pool, moveLiquidity.fromIndex)
const positionLendFrom = loadOrCreatePositionLend(moveLiquidity.tokenId, bucketIdFrom, moveLiquidity.fromIndex)
const lpRedeemedFrom = wadToDecimal(event.params.lpRedeemedFrom)

// load to index state
const bucketIdTo = getBucketId(moveLiquidity.pool, moveLiquidity.toIndex)
const positionLendTo = loadOrCreatePositionLend(moveLiquidity.tokenId, bucketIdTo, moveLiquidity.toIndex)
const positionLendToInfo = getPositionInfo(moveLiquidity.tokenId, BigInt.fromI32(moveLiquidity.toIndex))

// update positionLendTo
positionLendTo.depositTime = positionLendToInfo.depositTime
positionLendTo.lpb = wadToDecimal(positionLendToInfo.lpb)
positionLendTo.lpbValueInQuote = lpbValueInQuote(moveLiquidity.pool, moveLiquidity.toIndex, positionLendTo.lpb)
positionLendTo.save()

// associate positionLendTo with Bucket and Position if necessary
updatePositionLends(positionLendTo)

// update PositionLendFrom
// update positionLendFrom lpb
if (lpRedeemedFrom.le(positionLendFrom.lpb)) {
positionLendFrom.lpb = positionLendFrom.lpb.minus(wadToDecimal(event.params.lpRedeemedFrom))
} else {
log.warning('handleMoveLiquidity: lender {} redeemed more LP ({}) than PositionLend entity was aware of ({}); resetting to 0',
[moveLiquidity.lender.toHexString(), lpRedeemedFrom.toString(), positionLendFrom.lpb.toString()])
positionLendFrom.lpb = ZERO_BD
}
// update positionLendFrom lpbValueInQuote
if (positionLendFrom.lpb.equals(ZERO_BD)) {
positionLendFrom.lpbValueInQuote = ZERO_BD
} else {
positionLendFrom.lpbValueInQuote = lpbValueInQuote(moveLiquidity.pool, moveLiquidity.fromIndex, positionLendFrom.lpb)
}

// save entities to store
saveOrRemovePositionLend(positionLendFrom)
moveLiquidity.save()
token.save()
}
Expand All @@ -204,15 +245,13 @@ export function handleRedeemPosition(event: RedeemPositionEvent): void {

log.info("handleRedeemPosition for lender {} token {}" , [accountId.toHexString(), redeem.tokenId.toString()])

// update positionLend entities for each index
const positionIndexes = position.indexes;
for (let index = 0; index < redeem.indexes.length; index++) {
const bucketId = getBucketId(poolAddress, index)
const lendId = getLendId(bucketId, accountId)
// remove lends from position
const existingIndex = position.indexes.indexOf(lendId)
if (existingIndex != -1) {
positionIndexes.splice(existingIndex, 1)
}
const positionLend = loadOrCreatePositionLend(redeem.tokenId, bucketId, index)
positionLend.lpb = ZERO_BD
saveOrRemovePositionLend(positionLend)
}
position.indexes = positionIndexes

Expand Down Expand Up @@ -245,7 +284,22 @@ export function handleTransfer(event: TransferEvent): void {
token.txCount = token.txCount.plus(ONE_BI);
const position = loadOrCreatePosition(transfer.tokenId)
position.owner = event.params.to
position.tokenURI = getTokenURI(event.address, transfer.tokenId)

// remove position from old account
const oldOwnerAccount = loadOrCreateAccount(transfer.from)
const index = oldOwnerAccount.positions.indexOf(bigIntToBytes(transfer.tokenId))
const accountPositions = oldOwnerAccount.positions
if (index != -1) accountPositions.splice(index, 1)
oldOwnerAccount.positions = accountPositions

// add position to new account
const newOwnerAccount = loadOrCreateAccount(transfer.to)
updateAccountPositions(newOwnerAccount, position)

// save entities to store
oldOwnerAccount.save()
newOwnerAccount.save()
token.save();
position.save()
transfer.save()
Expand Down
13 changes: 12 additions & 1 deletion src/utils/account.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Address, BigInt, Bytes, store } from "@graphprotocol/graph-ts"
import { Account, Kick, Lend, Loan, Pool, Settle, Take } from "../../generated/schema"
import { Account, Kick, Lend, Loan, Pool, Position, Settle, Take } from "../../generated/schema"

import { ZERO_BD, ZERO_BI } from "./constants"

Expand All @@ -14,6 +14,7 @@ export function loadOrCreateAccount(accountId: Bytes): Account {
account.lends = []
account.loans = []
account.pools = []
account.positions = []
account.reserveAuctions = []
account.settles = []
account.takes = []
Expand Down Expand Up @@ -77,6 +78,16 @@ export function updateAccountKicks(account: Account, kick: Kick): void {
}
}

// update the list of Positions associated with an account, if it hasn't been added already
export function updateAccountPositions(account: Account, position: Position): void {
const positions = account.positions
// get current index of position in account's list of positions
const index = positions.indexOf(position.id)
if (index == -1) {
account.positions = account.positions.concat([position.id])
}
}

// update the list of reserve auctions interacted with by an account, if it hasn't been added already
export function updateAccountReserveAuctions(account: Account, reserveAuctionId: Bytes): void {
const reserveAuctions = account.reserveAuctions
Expand Down
21 changes: 11 additions & 10 deletions src/utils/pool/bucket.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Address, BigDecimal, BigInt, Bytes, dataSource, log } from "@graphprotocol/graph-ts"

import { Bucket, Lend } from "../../../generated/schema"
import { Bucket, Lend, PositionLend } from "../../../generated/schema"
import { PoolInfoUtils } from '../../../generated/templates/ERC20Pool/PoolInfoUtils'

import { poolInfoUtilsAddressTable, ONE_BD, ZERO_BD } from "../constants"
Expand Down Expand Up @@ -53,15 +53,16 @@ export function loadOrCreateBucket(poolId: Bytes, bucketId: Bytes, index: u32):
// create new bucket if bucket hasn't already been loaded
bucket = new Bucket(bucketId) as Bucket

bucket.bucketIndex = index
bucket.bucketPrice = indexToPrice(index)
bucket.poolAddress = poolId.toHexString()
bucket.pool = poolId
bucket.collateral = ZERO_BD
bucket.deposit = ZERO_BD
bucket.exchangeRate = ONE_BD
bucket.lpb = ZERO_BD
bucket.lends = []
bucket.bucketIndex = index
bucket.bucketPrice = indexToPrice(index)
bucket.poolAddress = poolId.toHexString()
bucket.pool = poolId
bucket.collateral = ZERO_BD
bucket.deposit = ZERO_BD
bucket.exchangeRate = ONE_BD
bucket.lpb = ZERO_BD
bucket.lends = []
bucket.positionLends = []
}
return bucket
}
Expand Down
4 changes: 2 additions & 2 deletions src/utils/pool/pool.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { BigDecimal, BigInt, Bytes, Address, dataSource } from '@graphprotocol/graph-ts'
import { BigDecimal, BigInt, Bytes, Address, dataSource, log } from '@graphprotocol/graph-ts'

import { LiquidationAuction, Pool, ReserveAuction, Token } from "../../../generated/schema"
import { ERC20Pool } from '../../../generated/templates/ERC20Pool/ERC20Pool'
Expand Down Expand Up @@ -262,7 +262,7 @@ export function updatePool(pool: Pool): void {
pool.quoteTokenBalance = wadToDecimal(unnormalizedTokenBalance.times(scaleFactor))
// update collateral token balances
// use the appropriate contract for querying balanceOf the pool
if (pool.poolType == 'Fungible') {
if (pool.poolType === 'Fungible') {
token = Token.load(pool.collateralToken)!
scaleFactor = TEN_BI.pow(18 - token.decimals as u8)
unnormalizedTokenBalance = getTokenBalance(Address.fromBytes(pool.collateralToken), poolAddress)
Expand Down
Loading