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

Multiple collections per seller #592

Merged
merged 18 commits into from
Jul 6, 2023
Merged

Multiple collections per seller #592

merged 18 commits into from
Jul 6, 2023

Conversation

zajck
Copy link
Member

@zajck zajck commented Mar 28, 2023

PR implements #590.

  • In contracts/domain/BosonTypes.sol:
    • added new type Collection which contains collection address and its external id
    • collectionIndex is added to Offer struct
  • in contracts/interfaces/handlers/IBosonAccountHandler.sol and contracts/protocol/facets/SellerHandlerFacet.sol two methods are added:
    • createNewCollection that creates an additional collection for the seller
    • getSellersCollections which returns default boson voucher address and list of additional collections
  • in contracts/protocol/facets/ExchangeHandlerFacet.sol,
    • all methods that previously interacted with clone address now get the correct clone address, based on collectionIndex, stored as the part of the offer
  • VoucherClone initializeVoucher is changed to accept _collectionIndex and add it as part of the name and symbol. Might still be changed: Multiple collections per seller BPIPs#15 (comment)
  • added a new event CollectionCreated which is emitted when a new collection is created
  • added/updated domain script and tests for Collection and Offer
  • added unit tests for use cases with collections

@zajck zajck self-assigned this Mar 28, 2023
@zajck zajck added enhancement New feature or request v2.3.0 labels Mar 28, 2023
@zajck zajck marked this pull request as ready for review May 16, 2023 10:05
@zajck zajck requested review from mischat and anajuliabit June 1, 2023 05:44
@coveralls
Copy link

coveralls commented Jun 5, 2023

Coverage Status

coverage: 99.679% (+0.003%) from 99.676% when pulling bd773d9 on multiple-collections into ad78b61 on main.

Copy link
Contributor

@anajuliabit anajuliabit left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks really good.

Just some thoughts

contracts/protocol/bases/ProtocolBase.sol Show resolved Hide resolved
contracts/protocol/bases/SellerBase.sol Outdated Show resolved Hide resolved
Comment on lines 1824 to 1853
it("should work on an additional collection", async function () {
const externalId = `Brand1`;
const contractURI = `https://brand1.com`;

// Create a new collection
await accountHandler.connect(assistant).createNewCollection(externalId, contractURI);

offer.collectionIndex = 1;
offer.id = await offerHandler.getNextOfferId();
exchange.id = await exchangeHandler.getNextExchangeId();
const tokenId = deriveTokenId(offer.id, exchange.id);

// Create the offer
await offerHandler
.connect(assistant)
.createOffer(offer, offerDates, offerDurations, disputeResolverId, agentId);

// Commit to offer, creating a new exchange
await exchangeHandler.connect(buyer).commitToOffer(buyer.address, offer.id, { value: price });

// expected address of the first additional collection
const additionalCollectionAddress = calculateContractAddress(accountHandler.address, "2");
const additionalCollection = await ethers.getContractAt("BosonVoucher", additionalCollectionAddress);

// Revoke the voucher, expecting event
await expect(exchangeHandler.connect(assistant).revokeVoucher(exchange.id))
.to.emit(additionalCollection, "Transfer")
.withArgs(buyer.address, ethers.constants.AddressZero, tokenId);
});

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose it would be more logical if we organized test contexts based on previous steps required instead of always grouping them by function. This way, we could avoid repeating a lot of pre-test setups. Sometimes I also feel that our test organization leads to test duplication. For example, if we want to test a code block in commitToOfferInternal, we end up repeating the same test at least three times because we have three functions that call commitToOfferInternal (commitToOffer, commitToPreMintedOffer, and more recently commitToConditionalOffer).

I'm not saying that you should do this in this PR, just wanted to bring this topic up for future discussions

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that some test files are a bit out of hand, and would benefit from some refactoring.

But I'm not sure that the different grouping actually generally solves the duplication, it just turns the code around (it requires that some other part is duplicated).

For example, consider these two organizations:
opt 1:

context A
    setup A
    ... other tests with setup A ...
    test D with an additional setup D

context B
   setup B
   ... other tests with setup B ...
   test D with an additional setup D

opt 2:

context D
    setup D
    test D with an additional setup A
    test D with an additional setup B

context XY
   setup XY
   ...
   test X with setup A
   test Y with setup B

In both cases the test D is the test that is a "duplicate", except that tested functions A and B are different (let's say commitToOffer, commitToPreMintedOffer). Test D requires a setup that is a combination of setups for A and D or B and D.

Opt 1 is similar to what we have now, so the top context is based on the function and we later duplicated the code for test D.
Now if we turn this around and group it by test D, we still need two tests, where one includes A specific setup and the other has B specific setup. We sure can do that. But there will still exist other contexts that will require either setup A or setup B. So instead of setup D being duplicated across contexts, now contexts A and B will be duplicated.

And in some cases, opt 2 is indeed better (for example, if setup D is long compared to setup A/B). So if we just wanted to optimize the tests we could regroup them. And that would lead to scenario-based contexts. We had that in v1 and I can tell you it was a nightmare to maintain. When some feature was added/removed it was sometimes even hard to accurately pinpoint into which scenario(s) we should add it.

Also, I think it makes sense to stick to the same option across all tests. And if I'm choosing between what have now and setup-based contexts, I'm sticking with the function based.

But I agree a lot of parts could be refactored to reuse the same code. Because now, if we make a change that affects a "duplicate" test, we need to go and find all affected instances. Ideally, the duplicated part would be a sort of util function (can be on a file level if other tests don't need it) and the test would simply invoke that.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Utility functions make sense to me. We can start migrating to functions when we need to add or refactor a test. A separate file would be better IMO, as we could reuse it in different facets, such as ExchangeHandlerTest and OrchestrationHandlerTest. I believe this would help make the codebase more legible, as our test files are currently too large.

anajuliabit
anajuliabit previously approved these changes Jun 6, 2023
Copy link
Contributor

@anajuliabit anajuliabit left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@zajck zajck marked this pull request as draft June 29, 2023 14:49
@zajck zajck marked this pull request as ready for review July 4, 2023 07:44
Copy link
Member

@mischat mischat left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good to me !

*/
function getSellersCollections(
uint256 _sellerId
) external view returns (address defaultVoucherAddress, BosonTypes.Collection[] memory additionalCollections);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we worry about the Collection[] being too big ? Do we need something like a getCollection(CollectionID) or something ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

even if this is a good idea, i wouldn't block on it ...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also think is a good idea, nice catch.
I create an issue so this doesn't get loss
#709

@mischat mischat requested a review from anajuliabit July 6, 2023 16:30
Copy link
Contributor

@anajuliabit anajuliabit left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

*/
function getSellersCollections(
uint256 _sellerId
) external view returns (address defaultVoucherAddress, BosonTypes.Collection[] memory additionalCollections);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also think is a good idea, nice catch.
I create an issue so this doesn't get loss
#709

@anajuliabit anajuliabit merged commit 6cdc94a into main Jul 6, 2023
9 checks passed
@anajuliabit anajuliabit deleted the multiple-collections branch July 6, 2023 17:10
@mischat
Copy link
Member

mischat commented Jul 6, 2023

@anajuliabit thanks for creating the issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request v2.3.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants