Skip to content

Commit

Permalink
Merge pull request #56 from bulla-network/solidoracle/dev-1634-invoic…
Browse files Browse the repository at this point in the history
…eimpaired-and-pool-profit-array-by-timestamp

InvoiceImpaired and pool profit array by timestamp
  • Loading branch information
solidoracle committed Sep 24, 2024
2 parents f51a032 + fe905c2 commit c793e3e
Show file tree
Hide file tree
Showing 7 changed files with 173 additions and 2 deletions.
27 changes: 27 additions & 0 deletions bulla-contracts/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,21 @@ type InvoiceUnfactoredEvent implements IEventLog & IPoolTransaction @entity {
claim: Claim!
}

type InvoiceImpairedEvent implements IEventLog & IPoolTransaction @entity {
id: ID!
invoiceId: String!
eventName: String!
fundedAmount: BigInt!
impairAmount: BigInt!
blockNumber: BigInt!
transactionHash: Bytes!
logIndex: BigInt!
timestamp: BigInt!
poolAddress: Bytes!
priceAfterTransaction: BigInt!
claim: Claim!
}

type DepositMadeEvent implements IEventLog & IPoolTransaction @entity {
id: ID!
depositor: Bytes! #address
Expand Down Expand Up @@ -428,6 +443,18 @@ type User @entity {
factoringEvents: [IEventLog!]!
}

type PoolPnl @entity {
id: ID!
address: Bytes! #address
pnlHistory: [PnlHistoryEntry!]!
}

type PnlHistoryEntry @entity {
id: ID!
pnl: BigInt!
timestamp: BigInt!
}

type FactoringPricePerShare @entity {
id: ID!
address: Bytes! # address
Expand Down
8 changes: 8 additions & 0 deletions bulla-contracts/src/functions/BullaFactoring.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { BigInt, ethereum } from "@graphprotocol/graph-ts";
import {
DepositMadeEvent,
InvoiceFundedEvent,
InvoiceImpairedEvent,
InvoiceKickbackAmountSentEvent,
InvoicePaidEvent,
InvoiceUnfactoredEvent,
Expand All @@ -11,6 +12,7 @@ import {
Deposit,
DepositMadeWithAttachment,
InvoiceFunded,
InvoiceImpaired,
InvoiceKickbackAmountSent,
InvoicePaid,
InvoiceUnfactored,
Expand Down Expand Up @@ -56,3 +58,9 @@ export const getSharesRedeemedEventId = (event: ethereum.Event): string => {
};

export const createSharesRedeemedEvent = (event: Withdraw): SharesRedeemedEvent => new SharesRedeemedEvent(getSharesRedeemedEventId(event));

export const getInvoiceImpairedEventId = (underlyingClaimId: BigInt, event: ethereum.Event): string =>
"InvoiceImpaired-" + underlyingClaimId.toString() + "-" + event.transaction.hash.toHexString() + "-" + event.logIndex.toString();

export const createInvoiceImpairedEvent = (underlyingTokenId: BigInt, event: InvoiceImpaired): InvoiceImpairedEvent =>
new InvoiceImpairedEvent(getInvoiceImpairedEventId(underlyingTokenId, event));
36 changes: 35 additions & 1 deletion bulla-contracts/src/functions/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,17 @@ import { ClaimCreatedClaimAttachmentStruct } from "../../generated/BullaClaimERC
import { ERC20 } from "../../generated/BullaClaimERC721/ERC20";
import { BullaManager as BullaManagerContract } from "../../generated/BullaManager/BullaManager";
import { LoanOfferedLoanOfferAttachmentStruct } from "../../generated/FrendLend/FrendLend";
import { BullaManager, Token, User, FactoringPricePerShare, PriceHistoryEntry, HistoricalFactoringStatistics, FactoringStatisticsEntry } from "../../generated/schema";
import {
BullaManager,
Token,
User,
FactoringPricePerShare,
PriceHistoryEntry,
HistoricalFactoringStatistics,
FactoringStatisticsEntry,
PoolPnl,
PnlHistoryEntry
} from "../../generated/schema";
import { BullaFactoring, DepositMadeWithAttachmentAttachmentStruct, SharesRedeemedWithAttachmentAttachmentStruct } from "../../generated/BullaFactoring/BullaFactoring";
import { BigInt } from "@graphprotocol/graph-ts";

Expand Down Expand Up @@ -188,3 +198,27 @@ export const getOrCreateHistoricalFactoringStatistics = (event: ethereum.Event):

return historicalFactoringStatistics;
};

export const getOrCreatePoolProfitAndLoss = (event: ethereum.Event, pnl: BigInt): PoolPnl => {
let poolPnl = PoolPnl.load(event.address.toHexString());

if (!poolPnl) {
poolPnl = new PoolPnl(event.address.toHexString());
poolPnl.address = event.address;
poolPnl.pnlHistory = [];
}

const pnlHistoryEntryId = poolPnl.id.concat("-").concat(event.block.timestamp.toString());
const pnlHistoryEntry = new PnlHistoryEntry(pnlHistoryEntryId);
pnlHistoryEntry.timestamp = event.block.timestamp;
pnlHistoryEntry.pnl = pnl;
pnlHistoryEntry.save();

let updatedHistory = poolPnl.pnlHistory;
updatedHistory.push(pnlHistoryEntry.id);
poolPnl.pnlHistory = updatedHistory;

poolPnl.save();

return poolPnl;
};
40 changes: 39 additions & 1 deletion bulla-contracts/src/mappings/BullaFactoring.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
Deposit,
DepositMadeWithAttachment,
InvoiceFunded,
InvoiceImpaired,
InvoiceKickbackAmountSent,
InvoicePaid,
InvoicePaid__Params,
Expand All @@ -14,6 +15,7 @@ import { getClaim } from "../functions/BullaClaimERC721";
import {
createDepositMadeEvent,
createInvoiceFundedEvent,
createInvoiceImpairedEvent,
createInvoiceKickbackAmountSentEvent,
createInvoicePaidEvent,
createInvoiceUnfactoredEvent,
Expand All @@ -26,6 +28,7 @@ import {
getIPFSHash_redeemWithAttachment,
getLatestPrice,
getOrCreateHistoricalFactoringStatistics,
getOrCreatePoolProfitAndLoss,
getOrCreatePricePerShare,
getOrCreateUser
} from "../functions/common";
Expand Down Expand Up @@ -106,7 +109,6 @@ export function handleInvoicePaid(event: InvoicePaid): void {
const ev: InvoicePaid__Params = event.params;
const originatingClaimId = ev.invoiceId;

log.info("in handleInvoicePaid", []);
const underlyingClaim = getClaim(originatingClaimId.toString());
const InvoicePaidEvent = createInvoicePaidEvent(originatingClaimId, event);

Expand All @@ -121,6 +123,7 @@ export function handleInvoicePaid(event: InvoicePaid): void {
const price_per_share = getOrCreatePricePerShare(event);
const latestPrice = getLatestPrice(event);
const historical_factoring_statistics = getOrCreateHistoricalFactoringStatistics(event);
const pool_pnl = getOrCreatePoolProfitAndLoss(event, ev.trueInterest);

InvoicePaidEvent.eventName = "InvoicePaid";
InvoicePaidEvent.blockNumber = event.block.number;
Expand All @@ -137,6 +140,7 @@ export function handleInvoicePaid(event: InvoicePaid): void {
original_creditor.save();
price_per_share.save();
historical_factoring_statistics.save();
pool_pnl.save();
}

export function handleInvoiceUnfactored(event: InvoiceUnfactored): void {
Expand Down Expand Up @@ -258,3 +262,37 @@ export function handleSharesRedeemedWithAttachment(event: SharesRedeemedWithAtta

sharesRedeemedEvent.save();
}

export function handleInvoiceImpaired(event: InvoiceImpaired): void {
const ev = event.params;
const originatingClaimId = ev.invoiceId;

const underlyingClaim = getClaim(originatingClaimId.toString());

const InvoiceImpairedEvent = createInvoiceImpairedEvent(originatingClaimId, event);

InvoiceImpairedEvent.invoiceId = underlyingClaim.id;
const price_per_share = getOrCreatePricePerShare(event);
const latestPrice = getLatestPrice(event);
const historical_factoring_statistics = getOrCreateHistoricalFactoringStatistics(event);

InvoiceImpairedEvent.eventName = "InvoiceImpaired";
InvoiceImpairedEvent.blockNumber = event.block.number;
InvoiceImpairedEvent.transactionHash = event.transaction.hash;
InvoiceImpairedEvent.logIndex = event.logIndex;
InvoiceImpairedEvent.fundedAmount = ev.lossAmount;
InvoiceImpairedEvent.impairAmount = ev.gainAmount;
InvoiceImpairedEvent.timestamp = event.block.timestamp;
InvoiceImpairedEvent.poolAddress = event.address;
InvoiceImpairedEvent.priceAfterTransaction = latestPrice;
InvoiceImpairedEvent.claim = underlyingClaim.id;
const lossAccrued = ev.lossAmount
.minus(underlyingClaim.paidAmount)
.minus(ev.gainAmount)
.neg();
const pool_pnl = getOrCreatePoolProfitAndLoss(event, lossAccrued);

InvoiceImpairedEvent.save();
price_per_share.save();
historical_factoring_statistics.save();
}
2 changes: 2 additions & 0 deletions bulla-contracts/template.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -269,4 +269,6 @@ dataSources:
handler: handleSharesRedeemed
- event: SharesRedeemedWithAttachment(indexed address,uint256,uint256,(bytes32,uint8,uint8))
handler: handleSharesRedeemedWithAttachment
- event: InvoiceImpaired(indexed uint256,uint256,uint256)
handler: handleInvoiceImpaired
file: ./src/mappings/BullaFactoring.ts
39 changes: 39 additions & 0 deletions bulla-contracts/tests/BullaFactoring.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
handleDepositMade,
handleDepositMadeWithAttachment,
handleInvoiceFunded,
handleInvoiceImpaired,
handleInvoiceKickbackAmountSent,
handleInvoicePaid,
handleInvoiceUnfactored,
Expand All @@ -28,6 +29,7 @@ import {
newDepositMadeEvent,
newDepositMadeWithAttachmentEvent,
newInvoiceFundedEvent,
newInvoiceImpairedEvent,
newInvoiceKickbackAmountSentEvent,
newInvoicePaidEvent,
newInvoiceUnfactoredEvent,
Expand All @@ -37,6 +39,7 @@ import {
import {
getDepositMadeEventId,
getInvoiceFundedEventId,
getInvoiceImpairedEventId,
getInvoiceKickbackAmountSentEventId,
getInvoicePaidEventId,
getInvoiceUnfactoredEventId,
Expand All @@ -47,6 +50,8 @@ import {
FactoringPricePerShare,
FactoringStatisticsEntry,
HistoricalFactoringStatistics,
PnlHistoryEntry,
PoolPnl,
PriceHistoryEntry,
SharesRedeemedEvent
} from "../generated/schema";
Expand Down Expand Up @@ -258,6 +263,32 @@ test("it handles BullaFactoring events", () => {

log.info("✅ should attach IPFS hash to SharesRedeemed event", []);

const lossAmount = BigInt.fromI32(2000);
const gainAmount = BigInt.fromI32(50);

const invoiceImpairedEvent = newInvoiceImpairedEvent(claimId, lossAmount, gainAmount);
invoiceImpairedEvent.block.timestamp = timestamp;
invoiceImpairedEvent.block.number = blockNum;

handleInvoiceImpaired(invoiceImpairedEvent);

const invoiceImpairedEventId = getInvoiceImpairedEventId(claimId, invoiceImpairedEvent);
assert.fieldEquals("InvoiceImpairedEvent", invoiceImpairedEventId, "invoiceId", invoiceImpairedEvent.params.invoiceId.toString());
assert.fieldEquals("InvoiceImpairedEvent", invoiceImpairedEventId, "fundedAmount", invoiceImpairedEvent.params.lossAmount.toString());
assert.fieldEquals("InvoiceImpairedEvent", invoiceImpairedEventId, "impairAmount", invoiceImpairedEvent.params.gainAmount.toString());
assert.fieldEquals("InvoiceImpairedEvent", invoiceImpairedEventId, "poolAddress", MOCK_BULLA_FACTORING_ADDRESS.toHexString());
assert.fieldEquals("InvoiceImpairedEvent", invoiceImpairedEventId, "claim", claimId.toString());

let poolPnl = PoolPnl.load(MOCK_BULLA_FACTORING_ADDRESS.toHexString());
assert.assertNotNull(poolPnl);

const pnlHistoryEntryId = poolPnl!.pnlHistory[0];
const pnlHistoryEntry = PnlHistoryEntry.load(pnlHistoryEntryId);
assert.assertNotNull(pnlHistoryEntry);
assert.bigIntEquals(lossAmount.minus(gainAmount).neg(), pnlHistoryEntry!.pnl);

log.info("✅ should create a InvoiceImpaired event", []);

afterEach();
});

Expand Down Expand Up @@ -286,6 +317,14 @@ test("it handles InvoicePaid event", () => {

handleInvoicePaid(invoicePaidEvent);

let poolPnl = PoolPnl.load(MOCK_BULLA_FACTORING_ADDRESS.toHexString());
assert.assertNotNull(poolPnl);

const pnlHistoryEntryId = poolPnl!.pnlHistory[0];
const pnlHistoryEntry = PnlHistoryEntry.load(pnlHistoryEntryId);
assert.assertNotNull(pnlHistoryEntry);
assert.bigIntEquals(trueInterest, pnlHistoryEntry!.pnl);

const invoicePaidEventId = getInvoicePaidEventId(claimId, invoicePaidEvent);
assert.fieldEquals("InvoicePaidEvent", invoicePaidEventId, "invoiceId", invoicePaidEvent.params.invoiceId.toString());
assert.fieldEquals("InvoicePaidEvent", invoicePaidEventId, "fundedAmount", invoicePaidEvent.params.fundedAmountNet.toString());
Expand Down
23 changes: 23 additions & 0 deletions bulla-contracts/tests/functions/BullaFactoring.testtools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
DepositMade,
DepositMadeWithAttachment,
InvoiceFunded,
InvoiceImpaired,
InvoiceKickbackAmountSent,
InvoicePaid,
InvoiceUnfactored,
Expand Down Expand Up @@ -226,6 +227,28 @@ export function newSharesRedeemedWithAttachmentEvent(redeemer: Address, assets:
return sharesRedeemedWithAttachmentEvent;
}

export function newInvoiceImpairedEvent(originatingClaimId: BigInt, lossAmount: BigInt, gainAmount: BigInt): InvoiceImpaired {
const mockEvent = newMockEvent();
const invoiceImpairedEvent = new InvoiceImpaired(
mockEvent.address,
mockEvent.logIndex,
mockEvent.transactionLogIndex,
mockEvent.logType,
mockEvent.block,
mockEvent.transaction,
mockEvent.parameters,
mockEvent.receipt
);

invoiceImpairedEvent.address = MOCK_BULLA_FACTORING_ADDRESS;
invoiceImpairedEvent.parameters = new Array();
invoiceImpairedEvent.parameters.push(new ethereum.EventParam("invoiceId", ethereum.Value.fromUnsignedBigInt(originatingClaimId)));
invoiceImpairedEvent.parameters.push(new ethereum.EventParam("lossAmount", ethereum.Value.fromUnsignedBigInt(lossAmount)));
invoiceImpairedEvent.parameters.push(new ethereum.EventParam("gainAmount", ethereum.Value.fromUnsignedBigInt(gainAmount)));

return invoiceImpairedEvent;
}

function createMultihashTuple(): ethereum.Tuple {
const hash: Bytes = changetype<Bytes>(Bytes.fromHexString(MULTIHASH_BYTES));
const multihashArray: Array<ethereum.Value> = [
Expand Down

0 comments on commit c793e3e

Please sign in to comment.