From 5a37741ade287f86eb993187a94fe04c71ba215a Mon Sep 17 00:00:00 2001 From: Mike Date: Fri, 8 Dec 2023 17:28:14 -0500 Subject: [PATCH] update borrowerInfo interface; update comments and tests --- schema.graphql | 4 ++-- src/mappings/erc-20-pool.ts | 10 +++++++++- src/mappings/erc-721-pool.ts | 8 ++++++++ src/utils/pool/loan.ts | 12 ++++++++---- tests/erc-20-pool.test.ts | 15 ++++++++++----- tests/erc-721-pool.test.ts | 25 +++++++++++++++++-------- tests/utils/mock-contract-calls.ts | 3 ++- 7 files changed, 56 insertions(+), 21 deletions(-) diff --git a/schema.graphql b/schema.graphql index f4c432f..0375be9 100644 --- a/schema.graphql +++ b/schema.graphql @@ -194,7 +194,7 @@ type Loan @entity { # collateral tokens deposited in a pool by the borrower collateralPledged: BigDecimal! # borrower's threshold price in t0 terms - thresholdPrice: BigDecimal! + t0ThresholdPrice: BigDecimal! # list of tokenIds pledged by the borrower tokenIdsPledged: [BigInt!]! # debt in T0 terms, useful when the caller knows the pending inflator @@ -266,7 +266,7 @@ type LiquidationAuction @entity { bondFactor: BigDecimal! # bond factor determining the reward or penalty for the kicker neutralPrice: BigDecimal! # price at which kicker will have their bond returned without penalty or reward referencePrice: BigDecimal! # max(HTP, NP) used in auction price curve - thresholdPrice: BigDecimal! # borrower's threshold price + thresholdPrice: BigDecimal! # Threshold price stamped on the liquidation at time of kick } # tracks the reserve auction process across multiple takes in a single auction diff --git a/src/mappings/erc-20-pool.ts b/src/mappings/erc-20-pool.ts index c31faf9..f13e7ed 100644 --- a/src/mappings/erc-20-pool.ts +++ b/src/mappings/erc-20-pool.ts @@ -46,7 +46,7 @@ import { } from "../../generated/schema" import { ZERO_BD, ONE_BI } from "../utils/constants" -import { addressToBytes, wadToDecimal } from "../utils/convert" +import { addressToBytes, wadToDecimal } from '../utils/convert'; import { loadOrCreateAccount, updateAccountLends, updateAccountLoans, updateAccountPools, updateAccountKicks, updateAccountTakes, updateAccountSettles } from "../utils/account" import { getBucketId, getBucketInfo, loadOrCreateBucket, updateBucketLends } from "../utils/pool/bucket" import { getLendId, loadOrCreateLend, saveOrRemoveLend } from "../utils/pool/lend" @@ -97,6 +97,8 @@ export function handleDrawDebt(event: DrawDebtEvent): void { const borrowerInfo = getBorrowerInfo(addressToBytes(event.params.borrower), pool.id) loan.collateralPledged = wadToDecimal(borrowerInfo.collateral) loan.t0debt = wadToDecimal(borrowerInfo.t0debt) + loan.t0Np = wadToDecimal(borrowerInfo.t0Np) + loan.t0ThresholdPrice = wadToDecimal(borrowerInfo.t0ThresholdPrice) // update account's list of pools and loans if necessary updateAccountPools(account, pool) @@ -149,6 +151,8 @@ export function handleRepayDebt(event: RepayDebtEvent): void { const borrowerInfo = getBorrowerInfo(accountId, pool.id) loan.collateralPledged = wadToDecimal(borrowerInfo.collateral) loan.t0debt = wadToDecimal(borrowerInfo.t0debt) + loan.t0Np = wadToDecimal(borrowerInfo.t0Np) + loan.t0ThresholdPrice = wadToDecimal(borrowerInfo.t0ThresholdPrice) // update account loans if necessary updateAccountLoans(account, loan) @@ -437,6 +441,8 @@ export function handleBucketTake(event: BucketTakeEvent): void { const borrowerInfo = getBorrowerInfo(addressToBytes(event.params.borrower), pool.id) loan.collateralPledged = wadToDecimal(borrowerInfo.collateral) loan.t0debt = wadToDecimal(borrowerInfo.t0debt) + loan.t0Np = wadToDecimal(borrowerInfo.t0Np) + loan.t0ThresholdPrice = wadToDecimal(borrowerInfo.t0ThresholdPrice) // retrieve auction information on the take's auction const auctionInfo = getAuctionInfoERC20Pool(bucketTake.borrower, pool) @@ -550,6 +556,8 @@ export function handleTake(event: TakeEvent): void { const borrowerInfo = getBorrowerInfo(addressToBytes(event.params.borrower), pool.id) loan.collateralPledged = wadToDecimal(borrowerInfo.collateral) loan.t0debt = wadToDecimal(borrowerInfo.t0debt) + loan.t0Np = wadToDecimal(borrowerInfo.t0Np) + loan.t0ThresholdPrice = wadToDecimal(borrowerInfo.t0ThresholdPrice) // update liquidation auction state const auctionId = loan.liquidationAuction! diff --git a/src/mappings/erc-721-pool.ts b/src/mappings/erc-721-pool.ts index 49eaf87..392f3c9 100644 --- a/src/mappings/erc-721-pool.ts +++ b/src/mappings/erc-721-pool.ts @@ -95,6 +95,8 @@ export function handleDrawDebtNFT(event: DrawDebtNFTEvent): void { const borrowerInfo = getBorrowerInfoERC721Pool(addressToBytes(event.params.borrower), pool.id) loan.collateralPledged = wadToDecimal(borrowerInfo.collateral) loan.t0debt = wadToDecimal(borrowerInfo.t0debt) + loan.t0Np = wadToDecimal(borrowerInfo.t0Np) + loan.t0ThresholdPrice = wadToDecimal(borrowerInfo.t0ThresholdPrice) loan.tokenIdsPledged = loan.tokenIdsPledged.concat(event.params.tokenIdsPledged) // update account's list of pools and loans if necessary @@ -142,6 +144,8 @@ export function handleRepayDebt(event: RepayDebtEvent): void { const borrowerInfo = getBorrowerInfoERC721Pool(accountId, pool.id) loan.collateralPledged = wadToDecimal(borrowerInfo.collateral) loan.t0debt = wadToDecimal(borrowerInfo.t0debt) + loan.t0Np = wadToDecimal(borrowerInfo.t0Np) + loan.t0ThresholdPrice = wadToDecimal(borrowerInfo.t0ThresholdPrice) // retrieve the tokenIdsPledged that were pulled in this event const numberOfTokensPulled = event.params.collateralPulled.div(ONE_WAD_BI).toI32() @@ -625,6 +629,8 @@ export function handleBucketTake(event: BucketTakeEvent): void { const borrowerInfo = getBorrowerInfoERC721Pool(addressToBytes(event.params.borrower), pool.id) loan.collateralPledged = wadToDecimal(borrowerInfo.collateral) loan.t0debt = wadToDecimal(borrowerInfo.t0debt) + loan.t0Np = wadToDecimal(borrowerInfo.t0Np) + loan.t0ThresholdPrice = wadToDecimal(borrowerInfo.t0ThresholdPrice) // unique to ERC721Pools // remove collateral taken from loan and pool @@ -751,6 +757,8 @@ export function handleTake(event: TakeEvent): void { const borrowerInfo = getBorrowerInfoERC721Pool(addressToBytes(event.params.borrower), pool.id) loan.collateralPledged = wadToDecimal(borrowerInfo.collateral) loan.t0debt = wadToDecimal(borrowerInfo.t0debt) + loan.t0Np = wadToDecimal(borrowerInfo.t0Np) + loan.t0ThresholdPrice = wadToDecimal(borrowerInfo.t0ThresholdPrice) // remove tokenIdsTaken from loan and pool tokenIdsPledged const numberOfTokensToTake = getWadCollateralFloorTokens(event.params.collateral).toI32() diff --git a/src/utils/pool/loan.ts b/src/utils/pool/loan.ts index ffd98da..e5f0e64 100644 --- a/src/utils/pool/loan.ts +++ b/src/utils/pool/loan.ts @@ -21,7 +21,7 @@ export function loadOrCreateLoan(loanId: Bytes, poolId: Bytes, borrower: Bytes): loan.poolAddress = poolId.toHexString() loan.collateralPledged = ZERO_BD loan.t0debt = ZERO_BD - loan.thresholdPrice = ZERO_BD + loan.t0ThresholdPrice = ZERO_BD loan.inLiquidation = false loan.liquidationAuction = null loan.tokenIdsPledged = [] @@ -47,10 +47,12 @@ export class BorrowerInfo { t0debt: BigInt collateral: BigInt t0Np: BigInt - constructor(t0debt: BigInt, collateral: BigInt, t0Np: BigInt) { + t0ThresholdPrice: BigInt + constructor(t0debt: BigInt, collateral: BigInt, t0Np: BigInt, t0ThresholdPrice: BigInt) { this.t0debt = t0debt this.collateral = collateral this.t0Np = t0Np + this.t0ThresholdPrice = t0ThresholdPrice } } export function getBorrowerInfo(borrower: Bytes, poolId: Bytes): BorrowerInfo { @@ -60,7 +62,8 @@ export function getBorrowerInfo(borrower: Bytes, poolId: Bytes): BorrowerInfo { return new BorrowerInfo( borrowerInfoResult.value0, borrowerInfoResult.value1, - borrowerInfoResult.value2 + borrowerInfoResult.value2, + borrowerInfoResult.value3 ) } @@ -71,7 +74,8 @@ export function getBorrowerInfoERC721Pool(borrower: Bytes, poolId: Bytes): Borro return new BorrowerInfo( borrowerInfoResult.value0, borrowerInfoResult.value1, - borrowerInfoResult.value2 + borrowerInfoResult.value2, + borrowerInfoResult.value3 ) } diff --git a/tests/erc-20-pool.test.ts b/tests/erc-20-pool.test.ts index 209d61b..4f3ad87 100644 --- a/tests/erc-20-pool.test.ts +++ b/tests/erc-20-pool.test.ts @@ -468,8 +468,8 @@ describe("ERC20Pool assertions", () => { const collateralPledged = BigInt.fromI32(1067) const lup = BigInt.fromString("9529276179422528643") // 9.529276179422528643 * 1e18 const index = BigInt.fromI32(234) - const inflator = BigInt.fromString("1002804000000000000") + const thresholdPrice = amountBorrowed.div(collateralPledged) mockPoolInfoUtilsPoolUpdateCalls(poolAddress, { poolSize: ZERO_BI, @@ -498,7 +498,8 @@ describe("ERC20Pool assertions", () => { const expectedBorrowerInfo = new BorrowerInfo( wdiv(amountBorrowed, inflator), collateralPledged, - BigInt.fromString("8766934085068726351")) + BigInt.fromString("8766934085068726351")), + thresholdPrice mockGetBorrowerInfo(poolAddress, borrower, expectedBorrowerInfo) // mock drawDebt event @@ -597,9 +598,11 @@ describe("ERC20Pool assertions", () => { const quoteRepaid = BigInt.fromString("567111000000000000000") // 567.111 * 1e18 const collateralPulled = BigInt.fromString("13400500000000000000") // 13.4005 * 1e18 const lup = BigInt.fromString("63480000000000000000") // 63.48 * 1e18 + const thresholdPrice = quoteRepaid.div(collateralPulled) + // TODO: fix mismatch between using pre-repay and post-repay update returns const expectedBorrowerInfo = new BorrowerInfo(quoteRepaid, collateralPulled, BigInt.fromString("501250000000000000")) - mockGetBorrowerInfo(poolAddress, borrower, expectedBorrowerInfo) + mockGetBorrowerInfo(poolAddress, borrower, expectedBorrowerInfo, thresholdPrice) const newRepayDebtEvent = createRepayDebtEvent( poolAddress, @@ -864,7 +867,8 @@ describe("ERC20Pool assertions", () => { let expectedBorrowerInfo = new BorrowerInfo( wdiv(debt, inflator), collateral, - wdiv(neutralPrice, inflator)) + wdiv(neutralPrice, inflator)), + thresholdPrice mockGetBorrowerInfo(poolAddress, borrower, expectedBorrowerInfo) // mock kick event @@ -911,7 +915,8 @@ describe("ERC20Pool assertions", () => { expectedBorrowerInfo = new BorrowerInfo( wdiv(debt, inflator), collateral.minus(amountToTake), - wdiv(neutralPrice, inflator)) + wdiv(neutralPrice, inflator)), + thresholdPrice mockGetBorrowerInfo(poolAddress, borrower, expectedBorrowerInfo) // mock take event diff --git a/tests/erc-721-pool.test.ts b/tests/erc-721-pool.test.ts index e13d1b8..14c10b1 100644 --- a/tests/erc-721-pool.test.ts +++ b/tests/erc-721-pool.test.ts @@ -257,8 +257,8 @@ describe("Describe entity assertions", () => { const amountPledged = BigInt.fromString("2000000000000000000") const lup = BigInt.fromString("9529276179422528643") // 9.529276179422528643 * 1e18 const index = BigInt.fromI32(123) - const inflator = BigInt.fromString("1002804000000000000") + const thresholdPrice = amountBorrowed.div(amountPledged) mockPoolInfoUtilsPoolUpdateCalls(poolAddress, { poolSize: ZERO_BI, @@ -287,7 +287,8 @@ describe("Describe entity assertions", () => { const expectedBorrowerInfo = new BorrowerInfo( wdiv(amountBorrowed, inflator), amountPledged, - BigInt.fromString("8766934085068726351")) + BigInt.fromString("8766934085068726351")), + thresholdPrice mockGetBorrowerInfo(poolAddress, borrower, expectedBorrowerInfo) const newDrawDebtEvent = createDrawDebtNFTEvent( @@ -404,6 +405,7 @@ describe("Describe entity assertions", () => { const tokenIdsPledged = [BigInt.fromI32(234), BigInt.fromI32(345)] const amountPledged = BigInt.fromString("2000000000000000000") let lup = BigInt.fromString("9529276179422528643") // 9.529276179422528643 * 1e18 + const thresholdPrice = amountBorrowed.div(amountPledged) // mock required contract calls const expectedPoolDebtInfo = new DebtInfo(amountBorrowed, ZERO_BI, ZERO_BI, ZERO_BI) @@ -413,7 +415,8 @@ describe("Describe entity assertions", () => { let expectedBorrowerInfo = new BorrowerInfo( wdiv(amountBorrowed, inflator), amountPledged, - BigInt.fromString("8766934085068726351")) + BigInt.fromString("8766934085068726351")), + thresholdPrice mockGetBorrowerInfo(poolAddress, borrower, expectedBorrowerInfo) const newDrawDebtEvent = createDrawDebtNFTEvent( @@ -456,7 +459,7 @@ describe("Describe entity assertions", () => { const quoteRepaid = BigInt.fromString("567111000000000000000") // 567.111 * 1e18 const collateralPulled = BigInt.fromString("1000000000000000000") // 1 * 1e18 - expectedBorrowerInfo = new BorrowerInfo(quoteRepaid, collateralPulled, BigInt.fromString("501250000000000000")) + expectedBorrowerInfo = new BorrowerInfo(quoteRepaid, collateralPulled, BigInt.fromString("501250000000000000"), thresholdPrice) mockGetBorrowerInfo(poolAddress, borrower, expectedBorrowerInfo) const newRepayDebtEvent = createRepayDebtEvent( @@ -759,6 +762,7 @@ describe("Describe entity assertions", () => { const tokenIdsPledged = [BigInt.fromI32(234), BigInt.fromI32(345), BigInt.fromI32(456), BigInt.fromI32(567), BigInt.fromI32(789)] const amountPledged = BigInt.fromString("5000000000000000000") // 5 * 1e18 const lup = BigInt.fromString("9529276179422528643") // 9.529276179422528643 * 1e18 + const thresholdPrice = amountBorrowed.div(amountPledged) // mock required contract calls const expectedPoolDebtInfo = new DebtInfo(amountBorrowed, ZERO_BI, ZERO_BI, ZERO_BI) @@ -768,7 +772,8 @@ describe("Describe entity assertions", () => { let expectedBorrowerInfo = new BorrowerInfo( wdiv(amountBorrowed, inflator), amountPledged, - BigInt.fromString("8766934085068726351")) + BigInt.fromString("8766934085068726351")), + thresholdPrice mockGetBorrowerInfo(poolAddress, borrower, expectedBorrowerInfo) // create and handle DrawDebt event @@ -877,7 +882,8 @@ describe("Describe entity assertions", () => { expectedBorrowerInfo = new BorrowerInfo( wdiv(amountBorrowed, inflator), amountPledged.minus(collateralToTake), - BigInt.fromString("8766934085068726351")) + BigInt.fromString("8766934085068726351")), + thresholdPrice mockGetBorrowerInfo(poolAddress, borrower, expectedBorrowerInfo) // create and handle Take event @@ -1157,6 +1163,7 @@ describe("Describe entity assertions", () => { const amountBorrowed = BigInt.fromString("567529276179422528643") // 567.529276179422528643 * 1e18 const tokenIdsPledged = [BigInt.fromI32(234), BigInt.fromI32(345), BigInt.fromI32(456), BigInt.fromI32(567), BigInt.fromI32(789)] const amountPledged = BigInt.fromString("5000000000000000000") // 5 * 1e18 + const thresholdPrice = amountBorrowed.div(amountPledged) // mock required contract calls const expectedPoolDebtInfo = new DebtInfo(amountBorrowed, ZERO_BI, ZERO_BI, ZERO_BI) @@ -1166,7 +1173,8 @@ describe("Describe entity assertions", () => { let expectedBorrowerInfo = new BorrowerInfo( wdiv(amountBorrowed, inflator), amountPledged, - BigInt.fromString("8766934085068726351")) + BigInt.fromString("8766934085068726351")), + thresholdPrice mockGetBorrowerInfo(poolAddress, borrower, expectedBorrowerInfo) // create and handle DrawDebt event @@ -1306,7 +1314,8 @@ describe("Describe entity assertions", () => { expectedBorrowerInfo = new BorrowerInfo( wdiv(amountBorrowed, inflator), amountPledged.minus(collateralToTake), - BigInt.fromString("8766934085068726351")) + BigInt.fromString("8766934085068726351")), + thresholdPrice mockGetBorrowerInfo(poolAddress, borrower, expectedBorrowerInfo) // mock bucket take event diff --git a/tests/utils/mock-contract-calls.ts b/tests/utils/mock-contract-calls.ts index 8ba0fd3..f53787e 100644 --- a/tests/utils/mock-contract-calls.ts +++ b/tests/utils/mock-contract-calls.ts @@ -142,7 +142,8 @@ export function mockGetBorrowerInfo(pool: Address, borrower: Address, expectedIn .returns([ ethereum.Value.fromUnsignedBigInt(expectedInfo.t0debt), ethereum.Value.fromUnsignedBigInt(expectedInfo.collateral), - ethereum.Value.fromUnsignedBigInt(expectedInfo.t0Np) + ethereum.Value.fromUnsignedBigInt(expectedInfo.t0Np), + ethereum.Value.fromUnsignedBigInt(expectedInfo.t0ThresholdPrice) ]) }