Skip to content

Commit

Permalink
Subgraph Improvements (#55)
Browse files Browse the repository at this point in the history
* wip bucketTake test

* expand bucketTake test

* add bucketTake assertions

* test bucketTake tokenId rebalancing

* finish bucketTake test

* finish bucket bankruptcy

* associate lends with buckets on every creation

* update lend.depositTime

* update factory subset hashes

* remove unused imports

* update depositTime to match contract in move events

* add _handleTransferLP

* fix PM lend deposit time and transferLP

* remove commented code

* add TransferLP test

* use lenderInfo for depositTime in transferLP

* check depositTime in assertLendUpdate

* remove unused events from erc20 and erc721 pool templates

* add tracking of screening stage voting power in DistributionPeriodVote

* expand screening stage vote test

* rename DistributionPeriodVote attributes

* add RecordedPostVote to remaining attributes as well

* fix screening stage vote tracking logic

* disassociate bucket and old lend on handleTransferLP

---------

Co-authored-by: Mike <mikehathaway@makerdao.com>
  • Loading branch information
MikeHathaway and Mike authored Aug 17, 2023
1 parent d3806c0 commit 9b39b69
Show file tree
Hide file tree
Showing 20 changed files with 904 additions and 277 deletions.
18 changes: 12 additions & 6 deletions schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,8 @@ type Bucket @entity {
deposit: BigDecimal!
# total LP for all lenders in the bucket
lpb: BigDecimal!
# list of lends associated with the bucket
lends: [Lend!]!
}

# lend occurs per bucket in a pool
Expand Down Expand Up @@ -897,14 +899,17 @@ type ProposalParams @entity {

type DistributionPeriodVote @entity {
id: Bytes! # $accountId + '|'' + $distributionId
voter: Account!
distribution: DistributionPeriod! # uint256
estimatedInitialFundingStageVotingPowerForCalculatingRewards: BigDecimal! # uint256
estimatedRemainingFundingStageVotingPowerForCalculatingRewards: BigDecimal! # uint256
screeningVotes: [ScreeningVote!]! # ScreeningVote[]
fundingVotes: [FundingVote!]! # FundingVote[]
voter: Account! # the account of the voter whose vote state in this distribution is being tracked
distribution: DistributionPeriod! # the distribution period associated with this entity
initialFundingStageVotingPowerRecordedPostVote: BigDecimal! # Voters initial funding stage voting power. Only recorded if the voter cast a screeningVote in this distribution period.
remainingFundingStageVotingPowerRecordedPostVote: BigDecimal! # Voters remaining funding stage voting power.
initialScreeningStageVotingPowerRecordedPostVote: BigDecimal! # Voters initial screening stage voting power. Only recorded if the voter cast a screeningVote in this distribution period.
remainingScreeningStageVotingPowerRecordedPostVote: BigDecimal! # Voters remaining screening stage voting power.
screeningVotes: [ScreeningVote!]! # ScreeningVote[] Array of ScreeningVotes cast.
fundingVotes: [FundingVote!]! # FundingVote[] Array of FundingVotes cast.
}

# 1-1 with Proposal. Multiple screeningVotes on the same proposal write to a single entity
type ScreeningVote @entity {
id: Bytes! # $proposalId + 'screening' + $account.id + $distributionId
distribution: DistributionPeriod! # distribution period the vote was cast in
Expand All @@ -914,6 +919,7 @@ type ScreeningVote @entity {
votesCast: [VoteCast!]! # array of voteCast entities created for each screeningVote on this proposal
}

# 1-1 with Proposal. Multiple fundingVotes on the same proposal write to a single entity
type FundingVote @entity {
id: Bytes! # $proposalId + 'funding' + $account.id + $distributionId
distribution: DistributionPeriod! # distribution period the vote was cast in
Expand Down
14 changes: 3 additions & 11 deletions src/erc-20-pool-factory.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,9 @@
import { PoolCreated as PoolCreatedEvent } from "../generated/ERC20PoolFactory/ERC20PoolFactory"
import { Pool, PoolCreated, Token } from "../generated/schema"
import { PoolCreated, Token } from "../generated/schema"
import { ERC20Pool } from "../generated/templates"
import { ERC20Pool as ERC20PoolContract } from "../generated/templates/ERC20Pool/ERC20Pool"

import {
MAX_PRICE,
MAX_PRICE_INDEX,
ONE_BI,
ZERO_BI,
ZERO_BD,
ZERO_ADDRESS,
ONE_BD
} from "./utils/constants"
import { ONE_BI, ZERO_BI } from "./utils/constants"
import { addressToBytes, wadToDecimal } from "./utils/convert"
import { getTokenDecimals, getTokenName, getTokenSymbol, getTokenTotalSupply } from "./utils/token-erc20"
import { getRatesAndFees, loadOrCreatePool } from "./utils/pool/pool"
Expand Down Expand Up @@ -98,7 +90,7 @@ export function handlePoolCreated(event: PoolCreatedEvent): void {

// record pool type information
pool.poolType = "Fungible"
pool.subsetHash = Bytes.empty() // TODO: use hardcoded subset hash for keccak(ERC20_POOL_SUBSET_HASH)
pool.subsetHash = Bytes.fromHexString("0x2263c4378b4920f0bef611a3ff22c506afa4745b3319c50b6d704a874990b8b2")

// add pool reference to factories' list of pools
factory.pools = factory.pools.concat([pool.id])
Expand Down
94 changes: 21 additions & 73 deletions src/erc-20-pool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import {
AddCollateral as AddCollateralEvent,
AddQuoteToken as AddQuoteTokenEvent,
ApproveLPTransferors as ApproveLPTransferorsEvent,
AuctionNFTSettle as AuctionNFTSettleEvent,
AuctionSettle as AuctionSettleEvent,
BondWithdrawn as BondWithdrawnEvent,
BucketBankruptcy as BucketBankruptcyEvent,
Expand Down Expand Up @@ -33,8 +32,6 @@ import {
import {
Account,
AddCollateral,
AddQuoteToken,
AuctionNFTSettle,
AuctionSettle,
BondWithdrawn,
Bucket,
Expand All @@ -48,12 +45,9 @@ import {
LiquidationAuction,
Loan,
LoanStamped,
MoveQuoteToken,
Pool,
RemoveCollateral,
RemoveQuoteToken,
RepayDebt,
ReserveAuction,
ReserveAuctionKick,
ReserveAuctionTake,
Settle,
Expand All @@ -63,11 +57,11 @@ import {
UpdateInterestRate
} from "../generated/schema"

import { ZERO_BD, ONE_BI, TEN_BI } from "./utils/constants"
import { ZERO_BD, ONE_BI, TEN_BI, ZERO_BI } from "./utils/constants"
import { addressToBytes, bigIntArrayToIntArray, wadToDecimal } from "./utils/convert"
import { loadOrCreateAccount, updateAccountLends, updateAccountLoans, updateAccountPools, updateAccountKicks, updateAccountTakes, updateAccountSettles, updateAccountReserveAuctions } from "./utils/account"
import { getBucketId, getBucketInfo, loadOrCreateBucket } from "./utils/pool/bucket"
import { getLendId, loadOrCreateLend } from "./utils/pool/lend"
import { getBucketId, getBucketInfo, loadOrCreateBucket, updateBucketLends } from "./utils/pool/bucket"
import { getDepositTime, getLendId, loadOrCreateLend } from "./utils/pool/lend"
import { getBorrowerInfo, getLoanId, loadOrCreateLoan } from "./utils/pool/loan"
import { getLiquidationAuctionId, getAuctionInfoERC20Pool, loadOrCreateLiquidationAuction, updateLiquidationAuction, getAuctionStatus, loadOrCreateBucketTake } from "./utils/pool/liquidation"
import { getBurnInfo, updatePool, addLiquidationToPool, addReserveAuctionToPool, getLenderInfo, getRatesAndFees } from "./utils/pool/pool"
Expand All @@ -76,7 +70,7 @@ import { loadOrCreateReserveAuction, reserveAuctionKickerReward } from "./utils/
import { incrementTokenTxCount } from "./utils/token-erc20"
import { approveTransferors, loadOrCreateTransferors, revokeTransferors } from "./utils/pool/lp-transferors"
import { loadOrCreateAllowances, increaseAllowances, decreaseAllowances, revokeAllowances } from "./utils/pool/lp-allowances"
import { _handleAddQuoteToken, _handleMoveQuoteToken, _handleRemoveQuoteToken } from "./mappings/base/base-pool"
import { _handleAddQuoteToken, _handleMoveQuoteToken, _handleRemoveQuoteToken, _handleTransferLP } from "./mappings/base/base-pool"

export function handleAddCollateral(event: AddCollateralEvent): void {
const addCollateral = new AddCollateral(
Expand Down Expand Up @@ -115,8 +109,10 @@ export function handleAddCollateral(event: AddCollateralEvent): void {
// update lend state
const lendId = getLendId(bucketId, accountId)
const lend = loadOrCreateLend(bucketId, lendId, pool.id, addCollateral.actor)
lend.depositTime = addCollateral.blockTimestamp
lend.lpb = lend.lpb.plus(addCollateral.lpAwarded)
lend.lpbValueInQuote = lpbValueInQuote(pool.id, bucket.bucketIndex, lend.lpb)
updateBucketLends(bucket, lend.id)

// update account's list of pools and lends if necessary
updateAccountPools(account, pool)
Expand Down Expand Up @@ -154,10 +150,6 @@ export function handleApproveLPTransferors(
entity.save()
}

// ERC721Pool only
// This is in the code path for ERC20Pools, but will never be emitted
export function handleAuctionNFTSettle(event: AuctionNFTSettleEvent): void {}

// ERC20Pool only
// emitted in conjunction with Settle
export function handleAuctionSettle(event: AuctionSettleEvent): void {
Expand Down Expand Up @@ -240,7 +232,15 @@ export function handleBucketBankruptcy(event: BucketBankruptcyEvent): void {
bucketBankruptcy.bucket = bucketId
bucketBankruptcy.pool = pool.id

// TODO: update Lends
// iterate through all bucket lends and set lend.lpb to zero
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
lend.save()
}

// save entities to store
pool.save()
Expand Down Expand Up @@ -324,8 +324,10 @@ export function handleBucketTake(event: BucketTakeEvent): void {
const bucketTakeLpAwarded = BucketTakeLPAwarded.load(lpAwardedId)!
const kickerLendId = getLendId(bucketId, bucketTakeLpAwarded.kicker)
const kickerLend = loadOrCreateLend(bucketId, kickerLendId, pool.id, bucketTakeLpAwarded.kicker)
kickerLend.depositTime = bucketTake.blockTimestamp
kickerLend.lpb = kickerLend.lpb.plus(bucketTakeLpAwarded.lpAwardedTaker)
kickerLend.lpbValueInQuote = lpbValueInQuote(pool.id, bucket.bucketIndex, kickerLend.lpb)
updateBucketLends(bucket, kickerLendId)

// update kicker account state if they weren't a lender already
const kickerAccountId = bucketTakeLpAwarded.kicker
Expand All @@ -335,8 +337,10 @@ export function handleBucketTake(event: BucketTakeEvent): void {
// update lend state for taker
const takerLendId = getLendId(bucketId, bucketTakeLpAwarded.taker)
const takerLend = loadOrCreateLend(bucketId, takerLendId, pool.id, bucketTakeLpAwarded.taker)
takerLend.depositTime = bucketTake.blockTimestamp
takerLend.lpb = takerLend.lpb.plus(bucketTakeLpAwarded.lpAwardedTaker)
takerLend.lpbValueInQuote = lpbValueInQuote(pool.id, bucket.bucketIndex, takerLend.lpb)
updateBucketLends(bucket, takerLendId)

// update bucketTake pointers
bucketTake.liquidationAuction = auction.id
Expand Down Expand Up @@ -886,7 +890,6 @@ export function handleTake(event: TakeEvent): void {
const auctionStatus = getAuctionStatus(pool, event.params.borrower)
updateLiquidationAuction(auction, auctionInfo, auctionStatus)

const debtCovered = wadToDecimal(event.params.amount)
const collateralPurchased = wadToDecimal(event.params.collateral)
pool.pledgedCollateral = pool.pledgedCollateral.minus(collateralPurchased)
take.auctionPrice = wadToDecimal(auctionStatus.price)
Expand Down Expand Up @@ -965,63 +968,8 @@ export function handleSettle(event: SettleEvent): void {
}

export function handleTransferLP(event: TransferLPEvent): void {
const entity = new TransferLP(
event.transaction.hash.concatI32(event.logIndex.toI32())
)
entity.owner = addressToBytes(event.params.owner)
entity.newOwner = addressToBytes(event.params.newOwner)
entity.indexes = bigIntArrayToIntArray(event.params.indexes)
entity.lp = wadToDecimal(event.params.lp)

entity.blockNumber = event.block.number
entity.blockTimestamp = event.block.timestamp
entity.transactionHash = event.transaction.hash

const poolId = addressToBytes(event.address)
const pool = Pool.load(poolId)!

log.info("handleTransferLP from {} to {}" , [entity.owner.toHexString(), entity.newOwner.toHexString()])

// update Lends for old and new owners, creating entities where necessary
const oldOwnerAccount = Account.load(entity.owner)!
const newOwnerAccount = loadOrCreateAccount(entity.newOwner)
for (var i=0; i<event.params.indexes.length; ++i) {
const bucketIndex = event.params.indexes[i]
const bucketId = getBucketId(poolId, bucketIndex.toU32())
const bucket = Bucket.load(bucketId)!
const oldLendId = getLendId(bucketId, entity.owner)
const newLendId = getLendId(bucketId, entity.newOwner)

// If PositionManager generated this event, it means either:
// Memorialize - transfer from lender to PositionManager, eliminating the lender's Lend
// Redeem - transfer from PositionManager to lender, creating the lender's Lend

// event does not reveal LP amounts transferred for each bucket, so query the pool and update
// remove old lend
const oldLend = loadOrCreateLend(bucketId, oldLendId, poolId, entity.owner)
oldLend.lpb = wadToDecimal(getLenderInfo(pool.id, bucketIndex, event.params.owner).lpBalance)
oldLend.lpbValueInQuote = lpbValueInQuote(poolId, bucket.bucketIndex, oldLend.lpb)
updateAccountLends(oldOwnerAccount, oldLend)
oldLend.save()

// add new lend
const newLend = loadOrCreateLend(bucketId, newLendId, poolId, entity.newOwner)
newLend.lpb = wadToDecimal(getLenderInfo(pool.id, bucketIndex, event.params.newOwner).lpBalance)
newLend.lpbValueInQuote = lpbValueInQuote(poolId, bucket.bucketIndex, newLend.lpb)
updateAccountLends(newOwnerAccount, newLend)
newLend.save()
}
oldOwnerAccount.save()
newOwnerAccount.save()

// increment pool and token tx counts
pool.txCount = pool.txCount.plus(ONE_BI)
const quoteToken = Token.load(pool.quoteToken)!
quoteToken.txCount = quoteToken.txCount.plus(ONE_BI)
quoteToken.save()
pool.save()

entity.save()
event = changetype<TransferLPEvent | null>(event)!
_handleTransferLP(event, null)
}

export function handleUpdateInterestRate(event: UpdateInterestRateEvent): void {
Expand Down
17 changes: 4 additions & 13 deletions src/erc-721-pool-factory.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,15 @@
import { PoolCreated as PoolCreatedEvent } from "../generated/ERC721PoolFactory/ERC721PoolFactory"
import { Pool, PoolCreated, Token } from "../generated/schema"
import { PoolCreated, Token } from "../generated/schema"
import { ERC721Pool } from "../generated/templates"
import { ERC721Pool as ERC721PoolContract } from "../generated/templates/ERC721Pool/ERC721Pool"

import {
MAX_PRICE,
MAX_PRICE_INDEX,
ONE_BI,
ZERO_BI,
ZERO_BD,
ZERO_ADDRESS,
ONE_BD
} from "./utils/constants"
import { ONE_BI, ZERO_BI } from "./utils/constants"
import { addressToBytes, wadToDecimal } from "./utils/convert"
import { loadOrCreateFactory } from "./utils/pool/pool-factory"
import { getPoolSubsetHash, getRatesAndFees, loadOrCreatePool } from "./utils/pool/pool"
import { getTokenName as getTokenNameERC721, getTokenSymbol as getTokenSymbolERC721} from "./utils/token-erc721"
import { getTokenDecimals, getTokenName, getTokenSymbol, getTokenTotalSupply } from "./utils/token-erc20"
import { ByteArray, Bytes, ethereum, log } from "@graphprotocol/graph-ts"
import { ByteArray, Bytes, ethereum } from "@graphprotocol/graph-ts"

export function handlePoolCreated(event: PoolCreatedEvent): void {
const poolCreated = new PoolCreated(
Expand Down Expand Up @@ -118,8 +110,7 @@ export function handlePoolCreated(event: PoolCreatedEvent): void {
pool.subsetHash = getPoolSubsetHash(event.address, tokenIds)
} else {
pool.poolType = "Collection"
// TODO: hardcode the subset hash
pool.subsetHash = Bytes.empty()
pool.subsetHash = Bytes.fromHexString("0x93e3b87db48beb11f82ff978661ba6e96f72f582300e9724191ab4b5d7964364")
}
pool.tokenIdsAllowed = tokenIds

Expand Down
Loading

0 comments on commit 9b39b69

Please sign in to comment.