Skip to content

subgraph - Track loan actions ( create / adjust / close / liquidated ) #2

Description

@0xGingFreecss

One of the most valuable features we will develop with a subgraph is showing the history of a specific loan.

With a bit of wiring we will be able to get subgraph to do a good part of it for us, namely:

Create a "Loan" document on subgraph that will have all the loan actions associated with it:
Create Loan
All "adjust_loan" calls
Close or Liquidate Loan
Have the current "status" of a loan
To achieve that we have to add a few entities to the schema.graphql

type Loan @entity {
  id: ID!
  account: Bytes!
  market: Bytes!
  collateralAmount: BigInt!
  debtAmount: BigInt!
  createdAt: BigInt!
  lastUpdatedAt: BigInt!
  status: String!
  actions: [LoanAction!]! @derivedFrom(field: "loan")
}

type LoanAction @entity {
  id: ID!
  loan: Loan!
  actionType: String!
  collateralChange: BigInt!
  debtChange: BigInt!
  timestamp: BigInt!
  txHash: Bytes!
}

type AccountMarketLoan @entity {
  id: ID!
  account: Bytes!
  market: Bytes!
  latestLoan: Loan!
}

Adjust the mappings

import { BigInt, Address, Bytes } from "@graphprotocol/graph-ts"
import {
  CreateLoanEvent,
  AdjustLoanEvent,
  CloseLoanEvent,
  LiquidateLoanEvent
} from "../generated/Controller/Controller"
import { Loan, LoanAction, AccountMarketLoan } from "../generated/schema"

export function handleCreateLoan(event: CreateLoanEvent): void {
  let loanId = event.transaction.hash.concatI32(event.logIndex.toI32())
  
  let loan = new Loan(loanId);
  loan.account = event.params.account;
  loan.market = event.params.market;
  loan.collateralAmount = event.params.coll_amount;
  loan.debtAmount = event.params.debt_amount;
  loan.createdAt = event.block.timestamp;
  loan.lastUpdatedAt = event.block.timestamp;
  loan.status = 'OPEN';
  loan.save();

  let action = new LoanAction(loanId);
  action.loan = loanId;
  action.actionType = 'CREATE';
  action.collateralChange = event.params.coll_amount;
  action.debtChange = event.params.debt_amount;
  action.timestamp = event.block.timestamp;
  action.txHash = event.transaction.hash;
  action.save();

  // Update AccountMarketLoan
  let accountMarketId = getAccountMarketId(event.params.account, event.params.market);
  let accountMarketLoan = new AccountMarketLoan(accountMarketId);
  accountMarketLoan.account = event.params.account;
  accountMarketLoan.market = event.params.market;
  accountMarketLoan.latestLoan = loanId;
  accountMarketLoan.save();
}

export function handleAdjustLoan(event: AdjustLoanEvent): void {
  let accountMarketId = getAccountMarketId(event.params.account, event.params.market);
  let accountMarketLoan = AccountMarketLoan.load(accountMarketId);
  if (accountMarketLoan) {
    let loan = Loan.load(accountMarketLoan.latestLoan);
    if (loan) {
      loan.collateralAmount = loan.collateralAmount.plus(event.params.coll_adjustment);
      loan.debtAmount = loan.debtAmount.plus(event.params.debt_adjustment);
      loan.lastUpdatedAt = event.block.timestamp;
      loan.save();

      let actionId = event.transaction.hash.concatI32(event.logIndex.toI32())
      let action = new LoanAction(actionId);
      action.loan = loan.id;
      action.actionType = 'ADJUST';
      action.collateralChange = event.params.coll_adjustment;
      action.debtChange = event.params.debt_adjustment;
      action.timestamp = event.block.timestamp;
      action.txHash = event.transaction.hash;
      action.save();
    }
  }
}

export function handleCloseLoan(event: CloseLoanEvent): void {
  let accountMarketId = getAccountMarketId(event.params.account, event.params.market);
  let accountMarketLoan = AccountMarketLoan.load(accountMarketId);
  if (accountMarketLoan) {
    let loan = Loan.load(accountMarketLoan.latestLoan);
    if (loan) {
      loan.collateralAmount = BigInt.fromI32(0);
      loan.debtAmount = BigInt.fromI32(0);
      loan.lastUpdatedAt = event.block.timestamp;
      loan.status = 'CLOSED';
      loan.save();

      let actionId = event.transaction.hash.concatI32(event.logIndex.toI32())
      let action = new LoanAction(actionId);
      action.loan = loan.id;
      action.actionType = 'CLOSE';
      action.collateralChange = event.params.coll_withdrawn.neg();
      action.debtChange = event.params.debt_withdrawn.neg();
      action.timestamp = event.block.timestamp;
      action.txHash = event.transaction.hash;
      action.save();
    }
  }
}

export function handleLiquidateLoan(event: LiquidateLoanEvent): void {
  let accountMarketId = getAccountMarketId(event.params.account, event.params.market);
  let accountMarketLoan = AccountMarketLoan.load(accountMarketId);
  if (accountMarketLoan) {
    let loan = Loan.load(accountMarketLoan.latestLoan);
    if (loan) {
      loan.collateralAmount = BigInt.fromI32(0);
      loan.debtAmount = BigInt.fromI32(0);
      loan.lastUpdatedAt = event.block.timestamp;
      loan.status = 'LIQUIDATED';
      loan.save();

      let actionId = event.transaction.hash.concatI32(event.logIndex.toI32())
      let action = new LoanAction(actionId);
      action.loan = loan.id;
      action.actionType = 'LIQUIDATE';
      action.collateralChange = event.params.coll_received.neg();
      action.debtChange = event.params.debt_repaid.neg();
      action.timestamp = event.block.timestamp;
      action.txHash = event.transaction.hash;
      action.save();
    }
  }
}

function getAccountMarketId(account: Address, market: Address): string {
  return account.toHexString() + "-" + market.toHexString()
}

Add Loan related entities to subgraph.yaml

     entities:
        - Loan
        - LoanAction
        - AccountMarketLoan

If you could kindly take care of this and write the tests for it would be ace.

The only missing bits here would be to track when a user is swap while being in "COLLATERAL CONVERSION MODE", which i'm still trying to figure out a way of tracking / speaking with @consol3cowboy about it.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions