Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

setup FactoringPricePerShare entity #44

Merged
merged 4 commits into from
Jun 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion bulla-contracts/config/sepolia.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@
"bullaFinance": { "address": "0xB219ecd037E8A5410d2e8839586D9F3996685cfB", "startBlock": 5096555 },
"frendLend": { "address": "0x3E058834CE20A54F0755889c008D3fF62D33cE85", "startBlock": 5096555 },
"instantPayment": { "address": "0x1cD1A83C2965CB7aD55d60551877Eb390e9C3d7A", "startBlock": 5096555 },
"bullaFactoring": { "address": "0x55847492EabE59FcFC72EAb673170645B2D7A097", "startBlock": 5960360 }
"bullaFactoring": { "address": "0xe90D1384Aeb44212dBd959498592D6327B45609B", "startBlock": 5960360 }
}
12 changes: 12 additions & 0 deletions bulla-contracts/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,18 @@ type User @entity {
factoringEvents: [IEventLog!]!
}

type FactoringPricePerShare @entity {
id: ID!
address: Bytes! # address
priceHistory: [PriceHistoryEntry!]!
}

type PriceHistoryEntry @entity {
id: ID!
timestamp: BigInt!
price: BigInt!
}

type BullaManager @entity {
id: ID!
address: Bytes #address
Expand Down
30 changes: 28 additions & 2 deletions bulla-contracts/src/functions/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ 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 } from "../../generated/schema";
import { DepositMadeWithAttachmentAttachmentStruct, SharesRedeemedWithAttachmentAttachmentStruct } from "../../generated/BullaFactoring/BullaFactoring";
import { BullaManager, Token, User, FactoringPricePerShare, PriceHistoryEntry } from "../../generated/schema";
import { BullaFactoring, DepositMadeWithAttachmentAttachmentStruct, SharesRedeemedWithAttachmentAttachmentStruct } from "../../generated/BullaFactoring/BullaFactoring";

export const ADDRESS_ZERO = "0x0000000000000000000000000000000000000000";

Expand Down Expand Up @@ -128,3 +128,29 @@ export const getOrCreateBullaManager = (event: ethereum.Event): BullaManager =>

return bullaManager;
};

export const getOrCreatePricePerShare = (event: ethereum.Event): FactoringPricePerShare => {
let factoringPrice = FactoringPricePerShare.load(event.address.toHexString());
const bullaFactoringContract = BullaFactoring.bind(event.address);
const currentPrice = bullaFactoringContract.pricePerShare();

if (!factoringPrice) {
factoringPrice = new FactoringPricePerShare(event.address.toHexString());
factoringPrice.address = event.address;
factoringPrice.priceHistory = [];
}

const historyEntryId = factoringPrice.id.concat("-").concat(event.block.timestamp.toString());
const historyEntry = new PriceHistoryEntry(historyEntryId);
historyEntry.timestamp = event.block.timestamp;
historyEntry.price = currentPrice;
historyEntry.save();

let updatedHistory = factoringPrice.priceHistory;
updatedHistory.push(historyEntry.id);
factoringPrice.priceHistory = updatedHistory;

factoringPrice.save();

return factoringPrice;
};
4 changes: 3 additions & 1 deletion bulla-contracts/src/mappings/BullaFactoring.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
createSharesRedeemedEvent,
createSharesRedeemedWithAttachmentEvent
} from "../functions/BullaFactoring";
import { getIPFSHash_depositWithAttachment, getIPFSHash_redeemWithAttachment, getOrCreateUser } from "../functions/common";
import { getIPFSHash_depositWithAttachment, getIPFSHash_redeemWithAttachment, getOrCreatePricePerShare, getOrCreateUser } from "../functions/common";

export function handleInvoiceFunded(event: InvoiceFunded): void {
const ev = event.params;
Expand All @@ -30,6 +30,7 @@ export function handleInvoiceFunded(event: InvoiceFunded): void {
InvoiceFundedEvent.fundedAmount = ev.fundedAmount;
InvoiceFundedEvent.originalCreditor = ev.originalCreditor;
const original_creditor = getOrCreateUser(ev.originalCreditor);
const price_per_share = getOrCreatePricePerShare(event);

InvoiceFundedEvent.eventName = "InvoiceFunded";
InvoiceFundedEvent.blockNumber = event.block.number;
Expand All @@ -41,6 +42,7 @@ export function handleInvoiceFunded(event: InvoiceFunded): void {

InvoiceFundedEvent.save();
original_creditor.save();
price_per_share.save();
}

export function handleInvoiceKickbackAmountSent(event: InvoiceKickbackAmountSent): void {
Expand Down
67 changes: 66 additions & 1 deletion bulla-contracts/tests/BullaFactoring.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
handleSharesRedeemedWithAttachment
} from "../src/mappings/BullaFactoring";
import { newClaimCreatedEvent } from "./functions/BullaClaimERC721.testtools";
import { ADDRESS_1, ADDRESS_2, ADDRESS_3, IPFS_HASH, afterEach, setupContracts } from "./helpers";
import { ADDRESS_1, ADDRESS_2, ADDRESS_3, IPFS_HASH, MOCK_BULLA_FACTORING_ADDRESS, afterEach, setupContracts, updatePricePerShareMock } from "./helpers";
import {
newDepositMadeEvent,
newDepositMadeWithAttachmentEvent,
Expand All @@ -31,6 +31,7 @@ import {
getSharesRedeemedEventId,
getSharesRedeemedWithAttachmentEventId
} from "../src/functions/BullaFactoring";
import { FactoringPricePerShare, PriceHistoryEntry } from "../generated/schema";

test("it handles BullaFactoring events", () => {
setupContracts();
Expand Down Expand Up @@ -170,5 +171,69 @@ test("it handles BullaFactoring events", () => {
afterEach();
});

test("it handles BullaFactoring events and stores price history", () => {
setupContracts();

const claimId1 = BigInt.fromI32(1);
const claimId2 = BigInt.fromI32(2);
const fundedAmount = BigInt.fromI32(10000);
const originalCreditor = ADDRESS_1;

const timestamp = BigInt.fromI32(100);
const blockNum = BigInt.fromI32(100);

// Create the first claim
const claimCreatedEvent1 = newClaimCreatedEvent(claimId1.toU32(), CLAIM_TYPE_INVOICE);
claimCreatedEvent1.block.timestamp = timestamp;
claimCreatedEvent1.block.number = blockNum;
handleClaimCreated(claimCreatedEvent1);

// Create the second claim
const claimCreatedEvent2 = newClaimCreatedEvent(claimId2.toU32(), CLAIM_TYPE_INVOICE);
claimCreatedEvent2.block.timestamp = timestamp;
claimCreatedEvent2.block.number = blockNum;
handleClaimCreated(claimCreatedEvent2);

// First InvoiceFunded event
const invoiceFundedEvent1 = newInvoiceFundedEvent(claimId1, fundedAmount, originalCreditor);
invoiceFundedEvent1.block.timestamp = timestamp;
invoiceFundedEvent1.block.number = blockNum;

handleInvoiceFunded(invoiceFundedEvent1);

let factoringPrice = FactoringPricePerShare.load(MOCK_BULLA_FACTORING_ADDRESS.toHexString());

assert.assertNotNull(factoringPrice);
assert.i32Equals(1, factoringPrice!.priceHistory.length);

const historyEntryId = factoringPrice!.priceHistory[0];
const priceHistoryEntry = PriceHistoryEntry.load(historyEntryId);
assert.assertNotNull(priceHistoryEntry);
assert.bigIntEquals(BigInt.fromI32(1000000), priceHistoryEntry!.price);

// Update the mock to return a new price
updatePricePerShareMock(BigInt.fromI32(1100000));

// Second InvoiceFunded event
const newTimestamp = timestamp.plus(BigInt.fromI32(3600)); // 1 hour later
const newBlockNum = blockNum.plus(BigInt.fromI32(100));

const invoiceFundedEvent2 = newInvoiceFundedEvent(claimId2, fundedAmount, originalCreditor);
invoiceFundedEvent2.block.timestamp = newTimestamp;
invoiceFundedEvent2.block.number = newBlockNum;

handleInvoiceFunded(invoiceFundedEvent2);

factoringPrice = FactoringPricePerShare.load(MOCK_BULLA_FACTORING_ADDRESS.toHexString());

assert.assertNotNull(factoringPrice);
assert.i32Equals(2, factoringPrice!.priceHistory.length);

const newHistoryEntryId = factoringPrice!.priceHistory[1];
const newPriceHistoryEntry = PriceHistoryEntry.load(newHistoryEntryId);
assert.assertNotNull(newPriceHistoryEntry);
assert.bigIntEquals(BigInt.fromI32(1100000), newPriceHistoryEntry!.price);
});

// exporting for test coverage
export { handleInvoiceFunded, handleClaimCreated, handleInvoiceKickbackAmountSent, handleInvoiceUnfactored };
36 changes: 23 additions & 13 deletions bulla-contracts/tests/functions/BullaFactoring.testtools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,29 @@ import {
SharesRedeemed,
SharesRedeemedWithAttachment
} from "../../generated/BullaFactoring/BullaFactoring";
import { MULTIHASH_BYTES, MULTIHASH_FUNCTION, MULTIHASH_SIZE, toEthAddress, toUint256 } from "../helpers";

export const newInvoiceFundedEvent = (originatingClaimId: BigInt, fundedAmount: BigInt, originalCreditor: Address): InvoiceFunded => {
const event: InvoiceFunded = changetype<InvoiceFunded>(newMockEvent());

const invoiceId = new ethereum.EventParam("invoiceId", toUint256(originatingClaimId));
const fundedAmountParam = new ethereum.EventParam("fundedAmount", toUint256(fundedAmount));
const originalCreditorParam = new ethereum.EventParam("originalCreditor", toEthAddress(originalCreditor));

event.parameters = [invoiceId, fundedAmountParam, originalCreditorParam];

return event;
};
import { MOCK_BULLA_FACTORING_ADDRESS, MULTIHASH_BYTES, MULTIHASH_FUNCTION, MULTIHASH_SIZE, toEthAddress, toUint256 } from "../helpers";

export function newInvoiceFundedEvent(invoiceId: BigInt, fundedAmount: BigInt, originalCreditor: Address): InvoiceFunded {
const mockEvent = newMockEvent();
const invoiceFundedEvent = new InvoiceFunded(
mockEvent.address,
mockEvent.logIndex,
mockEvent.transactionLogIndex,
mockEvent.logType,
mockEvent.block,
mockEvent.transaction,
mockEvent.parameters,
mockEvent.receipt
);

invoiceFundedEvent.address = MOCK_BULLA_FACTORING_ADDRESS;
invoiceFundedEvent.parameters = new Array();
invoiceFundedEvent.parameters.push(new ethereum.EventParam("invoiceId", ethereum.Value.fromUnsignedBigInt(invoiceId)));
invoiceFundedEvent.parameters.push(new ethereum.EventParam("fundedAmount", ethereum.Value.fromUnsignedBigInt(fundedAmount)));
invoiceFundedEvent.parameters.push(new ethereum.EventParam("originalCreditor", ethereum.Value.fromAddress(originalCreditor)));

return invoiceFundedEvent;
}

export const newInvoiceKickbackAmountSentEvent = (originatingClaimId: BigInt, kickbackAmount: BigInt, originalCreditor: Address): InvoiceKickbackAmountSent => {
const event: InvoiceKickbackAmountSent = changetype<InvoiceKickbackAmountSent>(newMockEvent());
Expand Down
8 changes: 8 additions & 0 deletions bulla-contracts/tests/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export const MOCK_INSTANT_PAYMENT_ADDRESS = Address.fromString("0xf1f41946c28824
export const MOCK_SAFE_ADDRESS = Address.fromString("0x2270B1f2996327eB772351ee8c5dbF98f9FD2FcF");
export const MOCK_SAFE_MODULE_ADDRESS = Address.fromString("0x70b841D46d227D458D9396e0c90A961e2B9D7a63");
export const MOCK_BULLA_TOKEN_ADDRESS = Address.fromString("0x90104Ff9aCd8EDB22BD5D030a11A1c2c66d95142");
export const MOCK_BULLA_FACTORING_ADDRESS = Address.fromString("0xd33abDe96F344FDe00B65650c8f68875D4c9e18A");
export const ADDRESS_ZERO = Address.fromString(addressZeroString);
export const ADDRESS_1 = Address.fromString("0xb8c18E036d46c5FB94d7DeBaAeD92aFabe65EE61");
export const ADDRESS_2 = Address.fromString("0xe2B28b58cc5d34872794E861fd1ba1982122B907");
Expand All @@ -49,6 +50,13 @@ export const setupContracts = (): void => {

/** setup BullaManager */
createMockedFunction(MOCK_MANAGER_ADDRESS, "description", "description():(bytes32)").returns([ethereum.Value.fromBytes(DESCRIPTION_BYTES)]);

/** setup BullaFactoring */
createMockedFunction(MOCK_BULLA_FACTORING_ADDRESS, "pricePerShare", "pricePerShare():(uint256)").returns([ethereum.Value.fromUnsignedBigInt(BigInt.fromI32(1000000))]);
};

export const updatePricePerShareMock = (newPrice: BigInt): void => {
createMockedFunction(MOCK_BULLA_FACTORING_ADDRESS, "pricePerShare", "pricePerShare():(uint256)").returns([ethereum.Value.fromUnsignedBigInt(newPrice)]);
};

export const afterEach = (): void => {
Expand Down
Loading