From ad49a79c491d428a3cff8fb688eb062a75a24378 Mon Sep 17 00:00:00 2001 From: Ludovic Levalleux Date: Tue, 28 Nov 2023 15:06:55 +0000 Subject: [PATCH] fix: do not create an offer when the seller does not exist (#614) * fix: do not create an offer when the seller does not exist * fix subgraph tests * fix subgraph test --- .../subgraph/src/mappings/account-handler.ts | 7 +++ .../subgraph/src/mappings/offer-handler.ts | 19 +++++++- .../subgraph/tests/account-handler.test.ts | 46 +++++++------------ packages/subgraph/tests/funds-handler.test.ts | 31 ++++--------- packages/subgraph/tests/mocks.ts | 30 +++++++++++- packages/subgraph/tests/offer-handler.test.ts | 25 ++++++++++ 6 files changed, 104 insertions(+), 54 deletions(-) diff --git a/packages/subgraph/src/mappings/account-handler.ts b/packages/subgraph/src/mappings/account-handler.ts index 4d2be2b93..0d7a1bfe0 100644 --- a/packages/subgraph/src/mappings/account-handler.ts +++ b/packages/subgraph/src/mappings/account-handler.ts @@ -1,3 +1,5 @@ +/* eslint-disable @typescript-eslint/ban-types */ +import { BigInt } from "@graphprotocol/graph-ts"; import { SellerCreated, SellerUpdatePending, @@ -36,6 +38,11 @@ import { saveAccountEventLog } from "../entities/event-log"; import { saveSellerMetadata } from "../entities/metadata/handler"; import { getSellerMetadataEntityId } from "../entities/metadata/seller"; +export function checkSellerExist(sellerId: BigInt): boolean { + const seller = Seller.load(sellerId.toString()); + return !!seller; +} + export function handleSellerCreatedEventWithoutMetadataUri( event: SellerCreatedLegacy ): void { diff --git a/packages/subgraph/src/mappings/offer-handler.ts b/packages/subgraph/src/mappings/offer-handler.ts index 966e2d4f2..ffb46085e 100644 --- a/packages/subgraph/src/mappings/offer-handler.ts +++ b/packages/subgraph/src/mappings/offer-handler.ts @@ -1,4 +1,4 @@ -import { BigInt } from "@graphprotocol/graph-ts"; +import { BigInt, log } from "@graphprotocol/graph-ts"; import { OfferCreated, OfferVoided, @@ -17,6 +17,7 @@ import { saveDisputeResolutionTermsLegacy } from "../entities/dispute-resolution"; import { saveOfferEventLog } from "../entities/event-log"; +import { checkSellerExist } from "./account-handler"; export function handleOfferCreatedEvent(event: OfferCreated): void { const offerId = event.params.offerId; @@ -30,6 +31,14 @@ export function handleOfferCreatedEvent(event: OfferCreated): void { const offerFeesStruct = event.params.offerFees; const disputeResolutionTermsStruct = event.params.disputeResolutionTerms; + if (!checkSellerExist(offerStruct.sellerId)) { + log.warning( + "Offer '{}' won't be created because seller '{}' does not exist", + [offerId.toString(), offerStruct.sellerId.toString()] + ); + return; + } + offer = new Offer(offerId.toString()); offer.createdAt = event.block.timestamp; offer.price = offerStruct.price; @@ -97,6 +106,14 @@ export function handleOfferCreatedEventLegacy(event: OfferCreatedLegacy): void { const offerFeesStruct = event.params.offerFees; const disputeResolutionTermsStruct = event.params.disputeResolutionTerms; + if (!checkSellerExist(offerStruct.sellerId)) { + log.warning( + "Offer '{}' won't be created because seller '{}' does not exist", + [offerId.toString(), offerStruct.sellerId.toString()] + ); + return; + } + offer = new Offer(offerId.toString()); offer.createdAt = event.block.timestamp; offer.price = offerStruct.price; diff --git a/packages/subgraph/tests/account-handler.test.ts b/packages/subgraph/tests/account-handler.test.ts index 2d3f38eb5..b4733ef2a 100644 --- a/packages/subgraph/tests/account-handler.test.ts +++ b/packages/subgraph/tests/account-handler.test.ts @@ -7,20 +7,19 @@ import { mockIpfsFile } from "matchstick-as/assembly/index"; import { - handleSellerCreatedEvent, handleSellerUpdatedEvent, handleBuyerCreatedEvent, handleSellerCreatedEventWithoutMetadataUri, handleSellerUpdateAppliedEvent } from "../src/mappings/account-handler"; import { - createSellerCreatedEvent, createSellerUpdatedEvent, createBuyerCreatedEvent, mockBosonVoucherContractCalls, createSellerCreatedEventLegacy, createSellerUpdateAppliedEvent, - mockCreateProduct + mockCreateProduct, + createSeller } from "./mocks"; import { getSellerMetadataEntityId } from "../src/entities/metadata/seller"; import { @@ -31,7 +30,6 @@ import { Offer, ProductV1Product, SalesChannel, - SalesChannelDeployment, SellerMetadata } from "../generated/schema"; import { getMetadataEntityId } from "../src/entities/metadata/utils"; @@ -76,30 +74,6 @@ test("handle legacy SellerCreatedEvent", () => { ); }); -function createSeller( - sellerId: i32, - sellerAddress: string, - sellerMetadataFilepath: string -): string { - mockBosonVoucherContractCalls(voucherCloneAddress, "ipfs://", 0); - mockIpfsFile(sellerMetadataHash, sellerMetadataFilepath); - const sellerCreatedEvent = createSellerCreatedEvent( - sellerId, - sellerAddress, - sellerAddress, - sellerAddress, - sellerAddress, - voucherCloneAddress, - 0, - 0, - sellerAddress, - "ipfs://" + sellerMetadataHash - ); - - handleSellerCreatedEvent(sellerCreatedEvent); - return sellerId.toString(); -} - function updateSellerMetadata( sellerId: i32, sellerMetadataFilepath: string @@ -123,7 +97,13 @@ function updateSellerMetadata( } test("handle SellerCreatedEvent", () => { - const sellerId = createSeller(1, sellerAddress, "tests/metadata/seller.json"); + const sellerId = createSeller( + 1, + sellerAddress, + "tests/metadata/seller.json", + voucherCloneAddress, + sellerMetadataHash + ); assert.fieldEquals("Seller", sellerId, "id", sellerId); assert.fieldEquals( @@ -229,7 +209,13 @@ test("handle BuyerCreatedEvent", () => { }); test("add/remove product salesChannels", () => { - const sellerId = createSeller(1, sellerAddress, "tests/metadata/seller.json"); + const sellerId = createSeller( + 1, + sellerAddress, + "tests/metadata/seller.json", + voucherCloneAddress, + sellerMetadataHash + ); // mock creation of ProductV1Product for Product_A and Product_B let productA = mockCreateProduct(sellerId, "Product_A", 1); diff --git a/packages/subgraph/tests/funds-handler.test.ts b/packages/subgraph/tests/funds-handler.test.ts index 832e4bc5a..1c6f34099 100644 --- a/packages/subgraph/tests/funds-handler.test.ts +++ b/packages/subgraph/tests/funds-handler.test.ts @@ -2,8 +2,7 @@ import { beforeEach, test, assert, - clearStore, - mockIpfsFile + clearStore } from "matchstick-as/assembly/index"; import { handleFundsDepositedEvent, @@ -11,16 +10,13 @@ import { handleFundsEncumberedEvent, handleFundsReleasedEvent } from "../src/mappings/funds-handler"; -import { - handleSellerCreatedEvent, - handleSellerCreatedEventWithoutMetadataUri -} from "../src/mappings/account-handler"; +import { handleSellerCreatedEventWithoutMetadataUri } from "../src/mappings/account-handler"; import { createFundsDepositedEvent, createFundsEncumberedEvent, createFundsReleasedEvent, createFundsWithdrawnEvent, - createSellerCreatedEvent, + createSeller, createSellerCreatedEventLegacy, mockBosonVoucherContractCalls } from "./mocks"; @@ -109,21 +105,12 @@ test("handle legacy FundsEncumberedEvent", () => { }); test("handle FundsEncumberedEvent", () => { - mockBosonVoucherContractCalls(voucherCloneAddress, "ipfs://", 1); - mockIpfsFile(sellerMetadataHash, "tests/metadata/seller.json"); - handleSellerCreatedEvent( - createSellerCreatedEvent( - sellerId, - sellerAddress, - sellerAddress, - sellerAddress, - sellerAddress, - voucherCloneAddress, - 0, - 0, - sellerAddress, - "ipfs://" + sellerMetadataHash - ) + createSeller( + sellerId, + sellerAddress, + "tests/metadata/seller.json", + voucherCloneAddress, + sellerMetadataHash ); const fundsDepositedEvent = createFundsDepositedEvent( sellerId, diff --git a/packages/subgraph/tests/mocks.ts b/packages/subgraph/tests/mocks.ts index a1a1c7719..57aef14cc 100644 --- a/packages/subgraph/tests/mocks.ts +++ b/packages/subgraph/tests/mocks.ts @@ -28,7 +28,8 @@ import { } from "../generated/BosonFundsHandler/IBosonFundsHandler"; import { newMockEvent, - createMockedFunction + createMockedFunction, + mockIpfsFile } from "matchstick-as/assembly/index"; import { ethereum, Address, BigInt } from "@graphprotocol/graph-ts"; import { @@ -39,6 +40,7 @@ import { import { SellerUpdateApplied } from "../generated/BosonAccountHandler/IBosonAccountHandler"; import { getProductId } from "../src/entities/metadata/product-v1/product"; import { ProductV1Media, ProductV1Product } from "../generated/schema"; +import { handleSellerCreatedEvent } from "../src/mappings/account-handler"; export function createOfferCreatedEvent( offerId: i32, @@ -887,3 +889,29 @@ export function mockCreateProduct( product.save(); return product; } + +export function createSeller( + sellerId: i32, + sellerAddress: string, + sellerMetadataFilepath: string, + voucherCloneAddress: string, + sellerMetadataHash: string +): string { + mockBosonVoucherContractCalls(voucherCloneAddress, "ipfs://", 0); + mockIpfsFile(sellerMetadataHash, sellerMetadataFilepath); + const sellerCreatedEvent = createSellerCreatedEvent( + sellerId, + sellerAddress, + sellerAddress, + sellerAddress, + sellerAddress, + voucherCloneAddress, + 0, + 0, + sellerAddress, + "ipfs://" + sellerMetadataHash + ); + + handleSellerCreatedEvent(sellerCreatedEvent); + return sellerId.toString(); +} diff --git a/packages/subgraph/tests/offer-handler.test.ts b/packages/subgraph/tests/offer-handler.test.ts index 4cf269d0b..05a262ea5 100644 --- a/packages/subgraph/tests/offer-handler.test.ts +++ b/packages/subgraph/tests/offer-handler.test.ts @@ -12,6 +12,7 @@ import { import { createOfferCreatedEvent, createOfferVoidedEvent, + createSeller, mockExchangeTokenContractCalls } from "./mocks"; @@ -24,6 +25,9 @@ const metadataHash = "QmPK1s3pNYLi9ERiq3BDxKa4XosgWwFRQUydHUtz4YgpqB"; const offerId = 1; const sellerId = 1; +const sellerAddress = "0x89205A3A3b2A69De6Dbf7f01ED13B2108B2c43e7"; +const voucherCloneAddress = "0x123456789a123456789a123456789a123456789a"; +const sellerMetadataHash = "QmZffs1Uv6pmf4649UpMqinDord9QBerJaWcwRgdenAto1"; const price = 1; const sellerDeposit = 1; const protocolFee = 1; @@ -86,6 +90,13 @@ test("handle OfferCreatedEvent with BASE metadata", () => { exchangeTokenSymbol ); mockIpfsFile(metadataHash, "tests/metadata/base.json"); + createSeller( + 1, + sellerAddress, + "tests/metadata/seller.json", + voucherCloneAddress, + sellerMetadataHash + ); handleOfferCreatedEvent(offerCreatedEvent); @@ -119,6 +130,13 @@ test("handle OfferCreatedEvent with PRODUCT_V1 metadata", () => { exchangeTokenSymbol ); mockIpfsFile(metadataHash, "tests/metadata/product-v1-full.json"); + createSeller( + 1, + sellerAddress, + "tests/metadata/seller.json", + voucherCloneAddress, + sellerMetadataHash + ); handleOfferCreatedEvent(offerCreatedEvent); @@ -157,6 +175,13 @@ test("handle OfferVoidedEvent", () => { exchangeTokenSymbol ); mockIpfsFile(metadataHash, "tests/metadata/base.json"); + createSeller( + 1, + sellerAddress, + "tests/metadata/seller.json", + voucherCloneAddress, + sellerMetadataHash + ); handleOfferCreatedEvent(offerCreatedEvent); const offerVoidedEvent = createOfferVoidedEvent(1, 1, exchangeTokenAddress);