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.
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
Adjust the mappings
Add Loan related entities to subgraph.yaml
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.