diff --git a/bulla-contracts/abis/BullaFactoring.json b/bulla-contracts/abis/BullaFactoring.json index 178e66c..7f914f0 100644 --- a/bulla-contracts/abis/BullaFactoring.json +++ b/bulla-contracts/abis/BullaFactoring.json @@ -307,6 +307,11 @@ "name": "ImpairReserveMustBeGreater", "type": "error" }, + { + "inputs": [], + "name": "ImpairReserveNotSet", + "type": "error" + }, { "inputs": [], "name": "InvalidAddress", @@ -332,6 +337,11 @@ "name": "InvoiceCanceled", "type": "error" }, + { + "inputs": [], + "name": "InvoiceCannotBePaid", + "type": "error" + }, { "inputs": [], "name": "InvoiceCreditorChanged", @@ -526,6 +536,43 @@ "name": "ApprovalDurationChanged", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "withdrawer", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "assets", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "shares", + "type": "uint256" + } + ], + "name": "AssetsWithdrawn", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -826,6 +873,55 @@ "name": "InvoiceKickbackAmountSent", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "invoiceId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "trueInterest", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "trueProtocolFee", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "adminFee", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "fundedAmountNet", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "kickbackAmount", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "originalCreditor", + "type": "address" + } + ], + "name": "InvoicePaid", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -1379,15 +1475,15 @@ "name": "fundedAmountNet", "type": "uint256" }, - { - "internalType": "uint256", - "name": "adminFee", - "type": "uint256" - }, { "internalType": "uint16", "name": "minDaysInterestApplied", "type": "uint16" + }, + { + "internalType": "uint256", + "name": "trueFaceValue", + "type": "uint256" } ], "stateMutability": "view", @@ -1464,6 +1560,19 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "calculateAccruedProfits", + "outputs": [ + { + "internalType": "uint256", + "name": "accruedProfits", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "calculateCapitalAccount", @@ -1504,7 +1613,7 @@ }, { "internalType": "uint256", - "name": "taxAmount", + "name": "trueAdminFee", "type": "uint256" } ], @@ -1568,25 +1677,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "calculateTax", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [ { @@ -2450,19 +2540,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [ - { - "internalType": "contract IInvoiceProviderAdapter", - "name": "_newInvoiceProviderAdapter", - "type": "address" - } - ], - "name": "setInvoiceProviderAdapter", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, { "inputs": [ { @@ -2515,6 +2592,19 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [], + "name": "sumTargetFeesForActiveInvoices", + "outputs": [ + { + "internalType": "uint256", + "name": "targetFees", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "symbol", @@ -2720,17 +2810,17 @@ "inputs": [ { "internalType": "uint256", - "name": "", + "name": "assets", "type": "uint256" }, { "internalType": "address", - "name": "", + "name": "receiver", "type": "address" }, { "internalType": "address", - "name": "", + "name": "owner", "type": "address" } ], @@ -2742,7 +2832,7 @@ "type": "uint256" } ], - "stateMutability": "pure", + "stateMutability": "nonpayable", "type": "function" }, { diff --git a/bulla-contracts/schema.graphql b/bulla-contracts/schema.graphql index b62aadd..d5cb3d4 100644 --- a/bulla-contracts/schema.graphql +++ b/bulla-contracts/schema.graphql @@ -199,6 +199,25 @@ type InvoiceKickbackAmountSentEvent implements IEventLog & IPoolTransaction @ent claim: Claim! } +type InvoicePaidEvent implements IEventLog & IPoolTransaction @entity { + id: ID! + invoiceId: String! + fundedAmount: BigInt! + kickbackAmount: BigInt! + trueInterest: BigInt! + trueProtocolFee: BigInt! + trueAdminFee: BigInt! + originalCreditor: Bytes! #address + eventName: String! + blockNumber: BigInt! + transactionHash: Bytes! + logIndex: BigInt! + timestamp: BigInt! + poolAddress: Bytes! + priceAfterTransaction: BigInt! + claim: Claim! +} + type InvoiceUnfactoredEvent implements IEventLog & IPoolTransaction @entity { id: ID! invoiceId: String! diff --git a/bulla-contracts/src/functions/BullaFactoring.ts b/bulla-contracts/src/functions/BullaFactoring.ts index b0c5987..118cdff 100644 --- a/bulla-contracts/src/functions/BullaFactoring.ts +++ b/bulla-contracts/src/functions/BullaFactoring.ts @@ -1,9 +1,10 @@ -import { Address, BigInt, ethereum } from "@graphprotocol/graph-ts"; +import { BigInt, ethereum } from "@graphprotocol/graph-ts"; import { DepositMadeEvent, DepositMadeWithAttachmentEvent, InvoiceFundedEvent, InvoiceKickbackAmountSentEvent, + InvoicePaidEvent, InvoiceUnfactoredEvent, SharesRedeemedEvent, SharesRedeemedWithAttachmentEvent @@ -13,11 +14,11 @@ import { DepositMadeWithAttachment, InvoiceFunded, InvoiceKickbackAmountSent, + InvoicePaid, InvoiceUnfactored, SharesRedeemed, SharesRedeemedWithAttachment } from "../../generated/BullaFactoring/BullaFactoring"; -import { getOrCreatePricePerShare } from "./common"; export const getInvoiceFundedEventId = (underlyingClaimId: BigInt, event: ethereum.Event): string => "InvoiceFunded-" + underlyingClaimId.toString() + "-" + event.transaction.hash.toHexString() + "-" + event.logIndex.toString(); @@ -32,6 +33,12 @@ export const getInvoiceKickbackAmountSentEventId = (underlyingClaimId: BigInt, e export const createInvoiceKickbackAmountSentEvent = (underlyingTokenId: BigInt, event: InvoiceKickbackAmountSent): InvoiceKickbackAmountSentEvent => new InvoiceKickbackAmountSentEvent(getInvoiceKickbackAmountSentEventId(underlyingTokenId, event)); +export const getInvoicePaidEventId = (underlyingClaimId: BigInt, event: ethereum.Event): string => + "InvoicePaid-" + underlyingClaimId.toString() + "-" + event.transaction.hash.toHexString() + "-" + event.logIndex.toString(); + +export const createInvoicePaidEvent = (underlyingTokenId: BigInt, event: InvoicePaid): InvoicePaidEvent => + new InvoicePaidEvent(getInvoicePaidEventId(underlyingTokenId, event)); + export const getInvoiceUnfactoredEventId = (underlyingClaimId: BigInt, event: ethereum.Event): string => "InvoiceUnfactored-" + underlyingClaimId.toString() + "-" + event.transaction.hash.toHexString() + "-" + event.logIndex.toString(); diff --git a/bulla-contracts/src/mappings/BullaFactoring.ts b/bulla-contracts/src/mappings/BullaFactoring.ts index 02af46c..486aaf0 100644 --- a/bulla-contracts/src/mappings/BullaFactoring.ts +++ b/bulla-contracts/src/mappings/BullaFactoring.ts @@ -4,6 +4,8 @@ import { DepositMadeWithAttachment, InvoiceFunded, InvoiceKickbackAmountSent, + InvoicePaid, + InvoicePaid__Params, InvoiceUnfactored, SharesRedeemed, SharesRedeemedWithAttachment @@ -14,6 +16,7 @@ import { createDepositMadeWithAttachmentEvent, createInvoiceFundedEvent, createInvoiceKickbackAmountSentEvent, + createInvoicePaidEvent, createInvoiceUnfactoredEvent, createSharesRedeemedEvent, createSharesRedeemedWithAttachmentEvent @@ -98,6 +101,45 @@ export function handleInvoiceKickbackAmountSent(event: InvoiceKickbackAmountSent historical_factoring_statistics.save(); } +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); + + InvoicePaidEvent.invoiceId = underlyingClaim.id; + InvoicePaidEvent.fundedAmount = ev.fundedAmountNet; + InvoicePaidEvent.kickbackAmount = ev.kickbackAmount; + // issue: Ethereum value is not an int or uint. + InvoicePaidEvent.trueAdminFee = ev.adminFee; + InvoicePaidEvent.trueInterest = ev.trueInterest; + InvoicePaidEvent.trueProtocolFee = ev.trueProtocolFee; + // issue: index out of range + // InvoicePaidEvent.originalCreditor = ev.originalCreditor; + // const original_creditor = getOrCreateUser(ev.originalCreditor); + const price_per_share = getOrCreatePricePerShare(event); + const latestPrice = getLatestPrice(event); + const historical_factoring_statistics = getOrCreateHistoricalFactoringStatistics(event); + + InvoicePaidEvent.eventName = "InvoicePaid"; + InvoicePaidEvent.blockNumber = event.block.number; + InvoicePaidEvent.transactionHash = event.transaction.hash; + InvoicePaidEvent.logIndex = event.logIndex; + InvoicePaidEvent.timestamp = event.block.timestamp; + InvoicePaidEvent.poolAddress = event.address; + InvoicePaidEvent.priceAfterTransaction = latestPrice; + InvoicePaidEvent.claim = underlyingClaim.id; + + // original_creditor.factoringEvents = original_creditor.factoringEvents ? original_creditor.factoringEvents.concat([InvoicePaidEvent.id]) : [InvoicePaidEvent.id]; + + InvoicePaidEvent.save(); + // original_creditor.save(); + price_per_share.save(); + historical_factoring_statistics.save(); +} + export function handleInvoiceUnfactored(event: InvoiceUnfactored): void { const ev = event.params; const originatingClaimId = ev.invoiceId; diff --git a/bulla-contracts/template.yaml b/bulla-contracts/template.yaml index 1acb745..95e2bed 100644 --- a/bulla-contracts/template.yaml +++ b/bulla-contracts/template.yaml @@ -243,6 +243,7 @@ dataSources: entities: - InvoiceFundedEvent - InvoiceKickbackAmountSentEvent + - InvoicePaidEvent - InvoiceUnfactoredEvent - DepositMadeEvent - DepositMadeWithAttachmentEvent @@ -256,6 +257,8 @@ dataSources: handler: handleInvoiceFunded - event: InvoiceKickbackAmountSent(indexed uint256,uint256,indexed address) handler: handleInvoiceKickbackAmountSent + - event: InvoicePaid(indexed uint256,uint256,uint256,uint256,uint256,uint256,indexed address) + handler: handleInvoicePaid - event: InvoiceUnfactored(indexed uint256,address,uint256,uint256) handler: handleInvoiceUnfactored - event: DepositMade(indexed address,uint256,uint256) diff --git a/bulla-contracts/tests/BullaFactoring.test.ts b/bulla-contracts/tests/BullaFactoring.test.ts index d809c48..21f28bb 100644 --- a/bulla-contracts/tests/BullaFactoring.test.ts +++ b/bulla-contracts/tests/BullaFactoring.test.ts @@ -7,6 +7,7 @@ import { handleDepositMadeWithAttachment, handleInvoiceFunded, handleInvoiceKickbackAmountSent, + handleInvoicePaid, handleInvoiceUnfactored, handleSharesRedeemed, handleSharesRedeemedWithAttachment @@ -28,6 +29,7 @@ import { newDepositMadeWithAttachmentEvent, newInvoiceFundedEvent, newInvoiceKickbackAmountSentEvent, + newInvoicePaidEvent, newInvoiceUnfactoredEvent, newSharesRedeemedEvent, newSharesRedeemedWithAttachmentEvent @@ -254,6 +256,34 @@ test("it handles BullaFactoring events", () => { afterEach(); }); +test("it handles InvoicePaid event", () => { + setupContracts(); + + const claimId = BigInt.fromI32(3); + const fundedAmount = BigInt.fromI32(10000); + const originalCreditor = ADDRESS_1; + + const timestamp = BigInt.fromI32(100); + const blockNum = BigInt.fromI32(100); + + const claimCreatedEvent = newClaimCreatedEvent(claimId.toU32(), CLAIM_TYPE_INVOICE); + claimCreatedEvent.block.timestamp = timestamp; + claimCreatedEvent.block.number = blockNum; + + handleClaimCreated(claimCreatedEvent); + + const kickbackAmount = BigInt.fromI32(2000); + const trueInterest = BigInt.fromI32(1000); + const trueAdminFee = BigInt.fromI32(1000); + const trueProtocolFee = BigInt.fromI32(1000); + + const invoicePaidEvent = newInvoicePaidEvent(claimId, fundedAmount, kickbackAmount, originalCreditor, trueInterest, trueAdminFee, trueProtocolFee); + + handleInvoicePaid(invoicePaidEvent); + + afterEach(); +}); + test("it handles BullaFactoring events and stores price history", () => { setupContracts(); @@ -313,4 +343,4 @@ test("it handles BullaFactoring events and stores price history", () => { }); // exporting for test coverage -export { handleInvoiceFunded, handleClaimCreated, handleInvoiceKickbackAmountSent, handleInvoiceUnfactored }; +export { handleInvoiceFunded, handleClaimCreated, handleInvoiceKickbackAmountSent, handleInvoiceUnfactored, handleInvoicePaid }; diff --git a/bulla-contracts/tests/functions/BullaFactoring.testtools.ts b/bulla-contracts/tests/functions/BullaFactoring.testtools.ts index 4238575..30bd016 100644 --- a/bulla-contracts/tests/functions/BullaFactoring.testtools.ts +++ b/bulla-contracts/tests/functions/BullaFactoring.testtools.ts @@ -5,6 +5,7 @@ import { DepositMadeWithAttachment, InvoiceFunded, InvoiceKickbackAmountSent, + InvoicePaid, InvoiceUnfactored, SharesRedeemed, SharesRedeemedWithAttachment @@ -61,6 +62,50 @@ export const newInvoiceKickbackAmountSentEvent = (originatingClaimId: BigInt, ki return InvoiceKickbackAmountSentEvent; }; +export const newInvoicePaidEvent = ( + originatingClaimId: BigInt, + fundedAmount: BigInt, + kickbackAmount: BigInt, + originalCreditor: Address, + trueInterest: BigInt, + trueAdminFee: BigInt, + trueProtocolFee: BigInt +): InvoicePaid => { + const mockEvent = newMockEvent(); + + const InvoicePaidEvent = new InvoicePaid( + mockEvent.address, + mockEvent.logIndex, + mockEvent.transactionLogIndex, + mockEvent.logType, + mockEvent.block, + mockEvent.transaction, + mockEvent.parameters, + mockEvent.receipt + ); + + InvoicePaidEvent.address = MOCK_BULLA_FACTORING_ADDRESS; + InvoicePaidEvent.parameters = new Array(); + + const invoiceId = new ethereum.EventParam("invoiceId", toUint256(originatingClaimId)); + const fundedAmountParam = new ethereum.EventParam("fundedAmount", toUint256(fundedAmount)); + const kickbackAmountParam = new ethereum.EventParam("kickbackAmount", toUint256(kickbackAmount)); + const originalCreditorParam = new ethereum.EventParam("originalCreditor", toEthAddress(originalCreditor)); + const trueInterestParam = new ethereum.EventParam("trueInterest", toUint256(trueInterest)); + const trueAdminFeeParam = new ethereum.EventParam("trueAdminFee", toUint256(trueAdminFee)); + const trueProtocolFeeParam = new ethereum.EventParam("trueProtocolFee", toUint256(trueProtocolFee)); + + InvoicePaidEvent.parameters.push(invoiceId); + InvoicePaidEvent.parameters.push(fundedAmountParam); + InvoicePaidEvent.parameters.push(kickbackAmountParam); + InvoicePaidEvent.parameters.push(originalCreditorParam); + InvoicePaidEvent.parameters.push(trueInterestParam); + InvoicePaidEvent.parameters.push(trueAdminFeeParam); + InvoicePaidEvent.parameters.push(trueProtocolFeeParam); + + return InvoicePaidEvent; +}; + export function newInvoiceUnfactoredEvent(originatingClaimId: BigInt, originalCreditor: Address, totalRefundAmount: BigInt, interestToCharge: BigInt): InvoiceUnfactored { const mockEvent = newMockEvent(); const invoiceUnfactoredEvent = new InvoiceUnfactored(