From 7cdc4e74231b433f7fe6f7ba518acaa35310a348 Mon Sep 17 00:00:00 2001 From: Ayush Tiwari Date: Wed, 11 Sep 2024 16:16:58 +0530 Subject: [PATCH] feat: removed bundledERC20 and added logic to exchange multiple bundles with ERC1155s --- .../marketplace/contracts/ExchangeCore.sol | 4 +- .../marketplace/contracts/OrderValidator.sol | 5 +- .../marketplace/contracts/TransferManager.sol | 33 +- .../contracts/libraries/LibAsset.sol | 21 +- .../test/exchange/Bundle.behavior.ts | 1380 +++++++---------- packages/marketplace/test/utils/assets.ts | 6 +- 6 files changed, 624 insertions(+), 825 deletions(-) diff --git a/packages/marketplace/contracts/ExchangeCore.sol b/packages/marketplace/contracts/ExchangeCore.sol index 65dde56d98..fce712761c 100644 --- a/packages/marketplace/contracts/ExchangeCore.sol +++ b/packages/marketplace/contracts/ExchangeCore.sol @@ -173,10 +173,10 @@ abstract contract ExchangeCore is Initializable, ITransferManager { orderRight.makeAsset.assetType ); - LibAsset.verifyPriceDistribution(orderLeft.takeAsset, orderRight.takeAsset); - LibOrder.FillResult memory newFill = _parseOrdersSetFillEmitMatch(sender, orderLeft, orderRight); + LibAsset.verifyPriceDistribution(orderLeft.takeAsset, newFill); + doTransfers( ITransferManager.DealSide(LibAsset.Asset(makeMatch, newFill.leftValue), orderLeft.maker), ITransferManager.DealSide(LibAsset.Asset(takeMatch, newFill.rightValue), orderRight.maker), diff --git a/packages/marketplace/contracts/OrderValidator.sol b/packages/marketplace/contracts/OrderValidator.sol index a8adb97a0d..b292955ad3 100644 --- a/packages/marketplace/contracts/OrderValidator.sol +++ b/packages/marketplace/contracts/OrderValidator.sol @@ -84,10 +84,7 @@ contract OrderValidator is IOrderValidator, Initializable, EIP712Upgradeable, ER address makeToken; if (asset.assetType.assetClass == LibAsset.AssetClass.BUNDLE) { LibAsset.Bundle memory bundle = LibAsset.decodeBundle(asset.assetType); - for (uint256 i; i < bundle.bundledERC20.length; i++) { - makeToken = bundle.bundledERC20[i].erc20Address; - _verifyWhitelistsRoles(makeToken); - } + // TODO add token verification in M-02 audit fix } else makeToken = LibAsset.decodeAddress(asset.assetType); if (asset.assetType.assetClass == LibAsset.AssetClass.ERC20) { _verifyWhitelistsRoles(makeToken); diff --git a/packages/marketplace/contracts/TransferManager.sol b/packages/marketplace/contracts/TransferManager.sol index a358c4410c..e62b8d73cf 100644 --- a/packages/marketplace/contracts/TransferManager.sol +++ b/packages/marketplace/contracts/TransferManager.sol @@ -114,7 +114,15 @@ abstract contract TransferManager is Initializable, ITransferManager { (address paymentSideRecipient, address nftSideRecipient) = _getRecipients(paymentSide, nftSide); // Transfer NFT or left side if FeeSide.NONE - _transfer(nftSide.asset, nftSide.account, paymentSideRecipient); + // NFT transfer when exchanging more than one bundle of ERC1155s + if (nftSide.asset.assetType.assetClass == LibAsset.AssetClass.BUNDLE && nftSide.asset.value > 1) { + for (uint256 i = 0; i < nftSide.asset.value; i++) { + _transfer(nftSide.asset, nftSide.account, paymentSideRecipient); + } + } else { + _transfer(nftSide.asset, nftSide.account, paymentSideRecipient); + } + // Transfer ERC20 or right side if FeeSide.NONE if (feeSide == LibAsset.FeeSide.NONE || _mustSkipFees(nftSide.account)) { _transfer(paymentSide.asset, paymentSide.account, nftSideRecipient); @@ -267,13 +275,17 @@ abstract contract TransferManager is Initializable, ITransferManager { token, bundle.bundledERC1155[i].ids[j] ); - remainder = _applyRoyalties( - remainder, - paymentSide, - bundle.priceDistribution.erc1155Prices[i][j], - royalties, - nftSideRecipient - ); + + // royalty transfer when exchanging one or more than one bundle of ERC1155s + for (uint256 k; k < nftSide.asset.value; k++) { + remainder = _applyRoyalties( + remainder, + paymentSide, + bundle.priceDistribution.erc1155Prices[i][j], + royalties, + nftSideRecipient + ); + } } } @@ -403,15 +415,10 @@ abstract contract TransferManager is Initializable, ITransferManager { _transferERC1155(token, from, to, tokenId, asset.value); } else if (asset.assetType.assetClass == LibAsset.AssetClass.BUNDLE) { LibAsset.Bundle memory bundle = LibAsset.decodeBundle(asset.assetType); - uint256 erc20Length = bundle.bundledERC20.length; uint256 erc721Length = bundle.bundledERC721.length; uint256 erc1155Length = bundle.bundledERC1155.length; uint256 quadsLength = bundle.quads.xs.length; if (erc721Length > 0 || quadsLength > 0) require(asset.value == 1, "bundle value error"); - for (uint256 i; i < erc20Length; i++) { - address token = bundle.bundledERC20[i].erc20Address; - _transferERC20(token, from, to, bundle.bundledERC20[i].value); - } for (uint256 i; i < erc721Length; i++) { address token = bundle.bundledERC721[i].erc721Address; uint256 idLength = bundle.bundledERC721[i].ids.length; diff --git a/packages/marketplace/contracts/libraries/LibAsset.sol b/packages/marketplace/contracts/libraries/LibAsset.sol index 0b0ad4a156..c94dccabeb 100644 --- a/packages/marketplace/contracts/libraries/LibAsset.sol +++ b/packages/marketplace/contracts/libraries/LibAsset.sol @@ -1,6 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.23; +import {LibOrder} from "./LibOrder.sol"; /// @author The Sandbox /// @title LibAsset: A library for handling different types of Ethereum assets. @@ -36,12 +37,6 @@ library LibAsset { uint256 value; // The amount or value of the asset. } - /// @dev Represents a group (i.e. bundle) of ERC20 asset. - struct BundledERC20 { - address erc20Address; - uint256 value; - } - /// @dev Represents a group (i.e. bundle) of ERC721 assets. struct BundledERC721 { address erc721Address; @@ -65,7 +60,6 @@ library LibAsset { /// @dev Represents a group (i.e. bundle) of assets with its types and values. struct Bundle { - BundledERC20[] bundledERC20; BundledERC721[] bundledERC721; BundledERC1155[] bundledERC1155; Quads quads; @@ -74,7 +68,6 @@ library LibAsset { /// @dev Represents the price of each asset in a bundle. struct PriceDistribution { - uint256[] erc20Prices; uint256[][] erc721Prices; uint256[][] erc1155Prices; uint256[] quadPrices; @@ -159,19 +152,13 @@ library LibAsset { /// @dev function to verify if the order is a bundle and validate the bundle price /// @param leftAsset The left asset. - /// @param rightAsset The right asset. - function verifyPriceDistribution(Asset memory leftAsset, Asset memory rightAsset) internal pure { + /// @param fill The fill. + function verifyPriceDistribution(Asset memory leftAsset, LibOrder.FillResult memory fill) internal pure { if (leftAsset.assetType.assetClass == AssetClass.BUNDLE) { - uint256 bundlePrice = rightAsset.value; // bundle price provided by seller Bundle memory bundle = LibAsset.decodeBundle(leftAsset.assetType); PriceDistribution memory priceDistribution = bundle.priceDistribution; uint256 collectiveBundlePrice = 0; - // total price of all bundled ERC20 assets - for (uint256 i = 0; i < priceDistribution.erc20Prices.length; i++) { - collectiveBundlePrice += priceDistribution.erc20Prices[i]; - } - // total price of all bundled ERC721 assets for (uint256 i = 0; i < priceDistribution.erc721Prices.length; i++) { for (uint256 j = 0; j < priceDistribution.erc721Prices[i].length; j++) @@ -192,7 +179,7 @@ library LibAsset { collectiveBundlePrice += priceDistribution.quadPrices[i]; } - require(bundlePrice == collectiveBundlePrice, "Bundle price mismatch"); + require(fill.rightValue == collectiveBundlePrice * fill.leftValue, "Bundle price mismatch"); } } diff --git a/packages/marketplace/test/exchange/Bundle.behavior.ts b/packages/marketplace/test/exchange/Bundle.behavior.ts index dc155f0dfe..e5d9098b7a 100644 --- a/packages/marketplace/test/exchange/Bundle.behavior.ts +++ b/packages/marketplace/test/exchange/Bundle.behavior.ts @@ -20,7 +20,6 @@ export function shouldMatchOrdersForBundle() { OrderValidatorAsAdmin: Contract, RoyaltiesRegistryAsDeployer: Contract, ERC20Contract: Contract, - ERC20Contract2: Contract, ERC721Contract: Contract, ERC1155Contract: Contract, LandContract: Contract, @@ -41,8 +40,6 @@ export function shouldMatchOrdersForBundle() { priceDistribution: PriceDistribution, // TODO: types // eslint-disable-next-line @typescript-eslint/no-explicit-any - bundledERC20: any, - // eslint-disable-next-line @typescript-eslint/no-explicit-any bundledERC721: any, // eslint-disable-next-line @typescript-eslint/no-explicit-any bundledERC1155: any, @@ -56,14 +53,13 @@ export function shouldMatchOrdersForBundle() { takerSig: string, landAdmin: Signer; - describe('ERC20 x Bundle', function () { + describe('Bundle x ERC20', function () { beforeEach(async function () { ({ ExchangeContractAsUser, OrderValidatorAsAdmin, RoyaltiesRegistryAsDeployer, ERC20Contract, - ERC20Contract2, ERC721Contract, ERC1155Contract, protocolFeeSecondary, @@ -73,51 +69,27 @@ export function shouldMatchOrdersForBundle() { } = await loadFixture(deployFixtures)); priceDistribution = { - erc20Prices: [2000000000], - erc721Prices: [[3000000000]], - erc1155Prices: [[500000000]], + erc721Prices: [[4000000000]], + erc1155Prices: [[600000000]], quadPrices: [], }; - // Set up ERC20 for maker - await ERC20Contract.mint(await maker.getAddress(), 30000000000); - await ERC20Contract.connect(maker).approve( - await ExchangeContractAsUser.getAddress(), - 30000000000 - ); - - // Construct makerAsset - makerAsset = await AssetERC20(ERC20Contract, 10000000000); - - // Set up ERC20 for taker - await ERC20Contract2.mint(await taker.getAddress(), 40000000000); - await ERC20Contract2.connect(taker).approve( - await ExchangeContractAsUser.getAddress(), - 40000000000 - ); - - // Set up ERC721 for taker - await ERC721Contract.mint(await taker.getAddress(), 1); - await ERC721Contract.connect(taker).approve( + // Set up ERC721 for maker + await ERC721Contract.mint(await maker.getAddress(), 1); + await ERC721Contract.connect(maker).approve( await ExchangeContractAsUser.getAddress(), 1 ); - // Set up ERC1155 for taker - await ERC1155Contract.mint(await taker.getAddress(), 1, 50); + // Set up ERC1155 for maker + await ERC1155Contract.mint(await maker.getAddress(), 1, 50); - await ERC1155Contract.connect(taker).setApprovalForAll( + await ERC1155Contract.connect(maker).setApprovalForAll( await ExchangeContractAsUser.getAddress(), true ); - // Construct takerAsset bundle - bundledERC20 = [ - { - erc20Address: ERC20Contract2.target, - value: 20000000000, - }, - ]; + // Construct makerAsset bundle bundledERC721 = [ { erc721Address: ERC721Contract.target, @@ -140,50 +112,57 @@ export function shouldMatchOrdersForBundle() { data: '0x', }; // empty quads - // Create bundle for passing as right order + // Create bundle for passing as left order bundleData = { - bundledERC20, bundledERC721, bundledERC1155, quads, priceDistribution, }; - takerAsset = await AssetBundle(bundleData, 1); // there can only ever be 1 copy of a bundle that contains ERC721 + makerAsset = await AssetBundle(bundleData, 1); // there can only ever be 1 copy of a bundle that contains ERC721 + + // Set up ERC20 for taker + await ERC20Contract.mint(await taker.getAddress(), 30000000000); + await ERC20Contract.connect(taker).approve( + await ExchangeContractAsUser.getAddress(), + 30000000000 + ); + + // Construct takerAsset + takerAsset = await AssetERC20(ERC20Contract, 10000000000); }); - it('should not execute match order between ERC20 tokens and Bundle if bundle price is not equal to collective bundle price', async function () { + it('should not execute match order between Bundle and ERC20 tokens if bundle price is not equal to collective bundle price', async function () { priceDistribution = { - erc20Prices: [0], erc721Prices: [[0]], erc1155Prices: [[0]], quadPrices: [], }; bundleData = { - bundledERC20, bundledERC721, bundledERC1155, quads, priceDistribution, }; - takerAsset = await AssetBundle(bundleData, 1); + makerAsset = await AssetBundle(bundleData, 1); orderLeft = await OrderDefault( - maker, // ERC20 - makerAsset, + maker, + makerAsset, // Bundle ZeroAddress, - takerAsset, // Bundle + takerAsset, // ERC20 1, 0, 0 ); orderRight = await OrderDefault( taker, - takerAsset, // Bundle + takerAsset, // ERC20 ZeroAddress, - makerAsset, // ERC20 + makerAsset, // Bundle 1, 0, 0 @@ -195,26 +174,22 @@ export function shouldMatchOrdersForBundle() { const makerAddress = await maker.getAddress(); const takerAddress = await taker.getAddress(); - expect(await ERC20Contract.balanceOf(makerAddress)).to.be.equal( + expect(await ERC20Contract.balanceOf(makerAddress)).to.be.equal(0); + expect(await ERC20Contract.balanceOf(takerAddress)).to.be.equal( 30000000000 ); - expect(await ERC20Contract.balanceOf(takerAddress)).to.be.equal(0); - expect(await ERC20Contract2.balanceOf(makerAddress)).to.be.equal(0); - expect(await ERC20Contract2.balanceOf(takerAddress)).to.be.equal( - 40000000000 - ); - expect(await ERC721Contract.ownerOf(1)).to.be.equal(takerAddress); - expect(await ERC1155Contract.balanceOf(takerAddress, 1)).to.be.equal( + expect(await ERC721Contract.ownerOf(1)).to.be.equal(makerAddress); + expect(await ERC1155Contract.balanceOf(makerAddress, 1)).to.be.equal( 50 ); - expect(await ERC1155Contract.balanceOf(makerAddress, 1)).to.be.equal(0); + expect(await ERC1155Contract.balanceOf(takerAddress, 1)).to.be.equal(0); await expect( ExchangeContractAsUser.matchOrders([ { - orderLeft, // passing ERC20 as left order + orderLeft, // passing Bundle as left order signatureLeft: makerSig, - orderRight, // passing Bundle as right order + orderRight, // passing ERC20 as right order signatureRight: takerSig, }, ]) @@ -247,78 +222,88 @@ export function shouldMatchOrdersForBundle() { const makerAddress = await maker.getAddress(); const takerAddress = await taker.getAddress(); - expect(await ERC20Contract.balanceOf(makerAddress)).to.be.equal( + expect(await ERC20Contract.balanceOf(makerAddress)).to.be.equal(0); + expect(await ERC20Contract.balanceOf(takerAddress)).to.be.equal( 30000000000 ); - expect(await ERC20Contract.balanceOf(takerAddress)).to.be.equal(0); - expect(await ERC20Contract2.balanceOf(makerAddress)).to.be.equal(0); - expect(await ERC20Contract2.balanceOf(takerAddress)).to.be.equal( - 40000000000 - ); - expect(await ERC721Contract.ownerOf(1)).to.be.equal(takerAddress); - expect(await ERC1155Contract.balanceOf(takerAddress, 1)).to.be.equal( + expect(await ERC721Contract.ownerOf(1)).to.be.equal(makerAddress); + expect(await ERC1155Contract.balanceOf(makerAddress, 1)).to.be.equal( 50 ); - expect(await ERC1155Contract.balanceOf(makerAddress, 1)).to.be.equal(0); + expect(await ERC1155Contract.balanceOf(takerAddress, 1)).to.be.equal(0); await ExchangeContractAsUser.matchOrders([ { - orderLeft, // passing ERC20 as left order + orderLeft, // passing Bundle as left order signatureLeft: makerSig, - orderRight, // passing Bundle as right order + orderRight, // passing ERC20 as right order signatureRight: takerSig, }, ]); + expect(await ERC721Contract.ownerOf(1)).to.be.equal(takerAddress); expect(await ERC1155Contract.balanceOf(makerAddress, 1)).to.be.equal( - 10 + 40 ); - expect(await ERC721Contract.ownerOf(1)).to.be.equal(makerAddress); expect(await ERC1155Contract.balanceOf(takerAddress, 1)).to.be.equal( - 40 + 10 ); expect( await ExchangeContractAsUser.fills(hashKey(orderLeft)) - ).to.be.equal(1); + ).to.be.equal(10000000000); expect( await ExchangeContractAsUser.fills(hashKey(orderRight)) - ).to.be.equal(10000000000); + ).to.be.equal(1); - expect(await ERC20Contract.balanceOf(takerAddress)).to.be.equal( + expect(await ERC20Contract.balanceOf(makerAddress)).to.be.equal( 9750000000 // 10000000000 - protocolFee ); - expect(await ERC20Contract.balanceOf(maker)).to.be.equal(20000000000); - expect(await ERC20Contract2.balanceOf(maker)).to.be.equal(20000000000); - expect(await ERC20Contract2.balanceOf(taker)).to.be.equal(20000000000); + expect(await ERC20Contract.balanceOf(takerAddress)).to.be.equal( + 20000000000 + ); // check protocol fee -> 250 * 10000000000 / 10000 = 250000000 expect( await ERC20Contract.balanceOf(defaultFeeReceiver.getAddress()) ).to.be.equal( - (Number(protocolFeeSecondary) * Number(makerAsset.value)) / 10000 + (Number(protocolFeeSecondary) * Number(takerAsset.value)) / 10000 ); // TODO: royalties checks for tokens }); it('should not allow asset bundle value > 1 if there are ERC721 contained in the bundle, since ERC721 are unique', async function () { - takerAsset = await AssetBundle(bundleData, 2); + // to bypass price distribution check as fill.leftValue = 2 + priceDistribution = { + erc721Prices: [[2000000000]], + erc1155Prices: [[300000000]], + quadPrices: [], + }; + + bundleData = { + bundledERC721, + bundledERC1155, + quads, + priceDistribution, + }; + + makerAsset = await AssetBundle(bundleData, 2); orderLeft = await OrderDefault( - maker, // ERC20 - makerAsset, + maker, + makerAsset, // Bundle ZeroAddress, - takerAsset, // Bundle + takerAsset, // ERC20 1, 0, 0 ); orderRight = await OrderDefault( taker, - takerAsset, // Bundle + takerAsset, // ERC20 ZeroAddress, - makerAsset, // ERC20 + makerAsset, // Bundle 1, 0, 0 @@ -330,26 +315,22 @@ export function shouldMatchOrdersForBundle() { const makerAddress = await maker.getAddress(); const takerAddress = await taker.getAddress(); - expect(await ERC20Contract.balanceOf(makerAddress)).to.be.equal( + expect(await ERC20Contract.balanceOf(makerAddress)).to.be.equal(0); + expect(await ERC20Contract.balanceOf(takerAddress)).to.be.equal( 30000000000 ); - expect(await ERC20Contract.balanceOf(takerAddress)).to.be.equal(0); - expect(await ERC20Contract2.balanceOf(makerAddress)).to.be.equal(0); - expect(await ERC20Contract2.balanceOf(takerAddress)).to.be.equal( - 40000000000 - ); - expect(await ERC721Contract.ownerOf(1)).to.be.equal(takerAddress); - expect(await ERC1155Contract.balanceOf(takerAddress, 1)).to.be.equal( + expect(await ERC721Contract.ownerOf(1)).to.be.equal(makerAddress); + expect(await ERC1155Contract.balanceOf(makerAddress, 1)).to.be.equal( 50 ); - expect(await ERC1155Contract.balanceOf(makerAddress, 1)).to.be.equal(0); + expect(await ERC1155Contract.balanceOf(takerAddress, 1)).to.be.equal(0); await expect( ExchangeContractAsUser.matchOrders([ { - orderLeft, // passing ERC20 as left order + orderLeft, // passing Bundle as left order signatureLeft: makerSig, - orderRight, // passing Bundle as right order + orderRight, // passing ERC20 as right order signatureRight: takerSig, }, ]) @@ -357,7 +338,7 @@ export function shouldMatchOrdersForBundle() { }); it('should partially fill orders using matchOrders between ERC20 and BUNDLE', async function () { - // Seller (taker - left) has 5 copies of a Bundle type; buyer (maker - right) just wants to buy 1 of these + // Seller (maker - right) has 5 copies of a Bundle type; buyer (taker - left) just wants to buy 1 of these const ERC20AssetForLeftOrder = await AssetERC20( ERC20Contract, 50000000000 @@ -372,14 +353,12 @@ export function shouldMatchOrdersForBundle() { bundledERC721 = []; priceDistribution = { - erc20Prices: [5000000000], erc721Prices: [[]], // price distribution without ERC721 - erc1155Prices: [[500000000]], + erc1155Prices: [[1000000000]], quadPrices: [], }; const bundleAsset = { - bundledERC20, bundledERC721, bundledERC1155, quads, @@ -394,9 +373,10 @@ export function shouldMatchOrdersForBundle() { // left order for partial fill orderLeft = await OrderDefault( maker, - ERC20AssetForLeftOrder, // makeAsset + bundleWithoutERC721Left, // makeAsset ZeroAddress, - bundleWithoutERC721Left, // takeAsset + + ERC20AssetForLeftOrder, // takeAsset 1, 0, 0 @@ -404,9 +384,10 @@ export function shouldMatchOrdersForBundle() { // right order for partial fill orderRight = await OrderDefault( taker, - bundleWithoutERC721Right, // makeAsset + ERC20AssetForRightOrder, // makeAsset ZeroAddress, - ERC20AssetForRightOrder, // takeAsset + + bundleWithoutERC721Right, // takeAsset 1, 0, 0 @@ -418,18 +399,14 @@ export function shouldMatchOrdersForBundle() { const makerAddress = await maker.getAddress(); const takerAddress = await taker.getAddress(); - expect(await ERC20Contract.balanceOf(makerAddress)).to.be.equal( + expect(await ERC20Contract.balanceOf(makerAddress)).to.be.equal(0); + expect(await ERC20Contract.balanceOf(takerAddress)).to.be.equal( 30000000000 ); - expect(await ERC20Contract.balanceOf(takerAddress)).to.be.equal(0); - expect(await ERC20Contract2.balanceOf(makerAddress)).to.be.equal(0); - expect(await ERC20Contract2.balanceOf(takerAddress)).to.be.equal( - 40000000000 - ); - expect(await ERC1155Contract.balanceOf(takerAddress, 1)).to.be.equal( + expect(await ERC1155Contract.balanceOf(makerAddress, 1)).to.be.equal( 50 ); - expect(await ERC1155Contract.balanceOf(makerAddress, 1)).to.be.equal(0); + expect(await ERC1155Contract.balanceOf(takerAddress, 1)).to.be.equal(0); expect( await ExchangeContractAsUser.fills(hashKey(orderLeft)) ).to.be.equal(0); @@ -448,18 +425,16 @@ export function shouldMatchOrdersForBundle() { expect( await ExchangeContractAsUser.fills(hashKey(orderLeft)) // newFill.rightValue - ).to.be.equal(1); + ).to.be.equal(10000000000); expect( await ExchangeContractAsUser.fills(hashKey(orderRight)) // newFill.leftValue - ).to.be.equal(10000000000); + ).to.be.equal(1); - expect(await ERC20Contract.balanceOf(takerAddress)).to.be.equal( + expect(await ERC20Contract.balanceOf(makerAddress)).to.be.equal( 9750000000 ); - expect(await ERC20Contract.balanceOf(maker)).to.be.equal(20000000000); - expect(await ERC20Contract2.balanceOf(maker)).to.be.equal(20000000000); - expect(await ERC20Contract2.balanceOf(taker)).to.be.equal(20000000000); + expect(await ERC20Contract.balanceOf(taker)).to.be.equal(20000000000); expect( await ERC20Contract.balanceOf(defaultFeeReceiver.getAddress()) @@ -470,16 +445,16 @@ export function shouldMatchOrdersForBundle() { ); expect(await ERC1155Contract.balanceOf(makerAddress, 1)).to.be.equal( - 10 + 40 ); expect(await ERC1155Contract.balanceOf(takerAddress, 1)).to.be.equal( - 40 + 10 ); // TODO: royalties checks for tokens }); it('should not allow signature reuse for partially filling orders using matchOrders between ERC20 and BUNDLE', async function () { - // Seller (taker - left) has 5 copies of a Bundle type; buyer (maker - right) just wants to buy 1 of these + // Seller (maker - right) has 5 copies of a Bundle type; buyer (taker - left) just wants to buy 1 of these const ERC20AssetForLeftOrder = await AssetERC20( ERC20Contract, 50000000000 @@ -494,14 +469,12 @@ export function shouldMatchOrdersForBundle() { bundledERC721 = []; priceDistribution = { - erc20Prices: [5000000000], erc721Prices: [[]], // price distribution without ERC721 - erc1155Prices: [[500000000]], + erc1155Prices: [[1000000000]], quadPrices: [], }; const bundleAsset = { - bundledERC20, bundledERC721, bundledERC1155, quads, @@ -516,9 +489,10 @@ export function shouldMatchOrdersForBundle() { // left order for partial fill orderLeft = await OrderDefault( maker, - ERC20AssetForLeftOrder, // makeAsset + bundleWithoutERC721Left, // makeAsset ZeroAddress, - bundleWithoutERC721Left, // takeAsset + + ERC20AssetForLeftOrder, // takeAsset 1, 0, 0 @@ -526,9 +500,9 @@ export function shouldMatchOrdersForBundle() { // right order for partial fill orderRight = await OrderDefault( taker, - bundleWithoutERC721Right, // makeAsset + ERC20AssetForRightOrder, // makeAsset ZeroAddress, - ERC20AssetForRightOrder, // takeAsset + bundleWithoutERC721Right, // takeAsset 1, 0, 0 @@ -559,7 +533,7 @@ export function shouldMatchOrdersForBundle() { }); it('should partially fill orders using matchOrders between ERC20 and BUNDLE - increase bundle right order value', async function () { - // Seller (taker - left) has 5 copies of a Bundle type; buyer (maker - right) just wants to buy 1 of these + // Seller (taker - right) has 5 copies of a Bundle type; buyer (taker - left) wants to buy 2 of these const ERC20AssetForLeftOrder = await AssetERC20( ERC20Contract, 50000000000 @@ -574,14 +548,12 @@ export function shouldMatchOrdersForBundle() { bundledERC721 = []; priceDistribution = { - erc20Prices: [10000000000], erc721Prices: [[]], // price distribution without ERC721 erc1155Prices: [[1000000000]], quadPrices: [], }; const bundleAsset = { - bundledERC20, bundledERC721, bundledERC1155, quads, @@ -596,9 +568,9 @@ export function shouldMatchOrdersForBundle() { // left order for partial fill orderLeft = await OrderDefault( maker, - ERC20AssetForLeftOrder, // makeAsset + bundleWithoutERC721Left, // makeAsset ZeroAddress, - bundleWithoutERC721Left, // takeAsset + ERC20AssetForLeftOrder, // takeAsset 1, 0, 0 @@ -606,9 +578,9 @@ export function shouldMatchOrdersForBundle() { // right order for partial fill orderRight = await OrderDefault( taker, - bundleWithoutERC721Right, // makeAsset + ERC20AssetForRightOrder, // makeAsset ZeroAddress, - ERC20AssetForRightOrder, // takeAsset + bundleWithoutERC721Right, // takeAsset 1, 0, 0 @@ -620,18 +592,14 @@ export function shouldMatchOrdersForBundle() { const makerAddress = await maker.getAddress(); const takerAddress = await taker.getAddress(); - expect(await ERC20Contract.balanceOf(makerAddress)).to.be.equal( + expect(await ERC20Contract.balanceOf(makerAddress)).to.be.equal(0); + expect(await ERC20Contract.balanceOf(takerAddress)).to.be.equal( 30000000000 ); - expect(await ERC20Contract.balanceOf(takerAddress)).to.be.equal(0); - expect(await ERC20Contract2.balanceOf(makerAddress)).to.be.equal(0); - expect(await ERC20Contract2.balanceOf(takerAddress)).to.be.equal( - 40000000000 - ); - expect(await ERC1155Contract.balanceOf(takerAddress, 1)).to.be.equal( + expect(await ERC1155Contract.balanceOf(takerAddress, 1)).to.be.equal(0); + expect(await ERC1155Contract.balanceOf(makerAddress, 1)).to.be.equal( 50 ); - expect(await ERC1155Contract.balanceOf(makerAddress, 1)).to.be.equal(0); expect( await ExchangeContractAsUser.fills(hashKey(orderLeft)) ).to.be.equal(0); @@ -650,17 +618,15 @@ export function shouldMatchOrdersForBundle() { expect( await ExchangeContractAsUser.fills(hashKey(orderLeft)) // newFill.rightValue - ).to.be.equal(2); + ).to.be.equal(20000000000); expect( await ExchangeContractAsUser.fills(hashKey(orderRight)) // newFill.leftValue - ).to.be.equal(20000000000); + ).to.be.equal(2); expect(await ERC20Contract.balanceOf(takerAddress)).to.be.equal( - 19500000000 + 10000000000 ); - expect(await ERC20Contract.balanceOf(maker)).to.be.equal(10000000000); - expect(await ERC20Contract2.balanceOf(maker)).to.be.equal(20000000000); - expect(await ERC20Contract2.balanceOf(taker)).to.be.equal(20000000000); + expect(await ERC20Contract.balanceOf(maker)).to.be.equal(19500000000); expect( await ERC20Contract.balanceOf(defaultFeeReceiver.getAddress()) @@ -671,16 +637,15 @@ export function shouldMatchOrdersForBundle() { ); expect(await ERC1155Contract.balanceOf(makerAddress, 1)).to.be.equal( - 10 + 30 ); expect(await ERC1155Contract.balanceOf(takerAddress, 1)).to.be.equal( - 40 + 20 ); - // TODO: royalties checks for tokens }); it('should fully fill an order using partial matches between ERC20 and BUNDLE', async function () { - // Seller (taker - left) has 5 copies of a Bundle type; buyer (maker - right) wants to buy 1 of these, then another in a second tx + // Seller (maker - right) has 5 copies of a Bundle type; buyer (taker - left) wants to buy 1 of these, then another in a second tx const ERC20AssetForLeftOrder = await AssetERC20( ERC20Contract, 50000000000 @@ -695,14 +660,12 @@ export function shouldMatchOrdersForBundle() { bundledERC721 = []; priceDistribution = { - erc20Prices: [5000000000], erc721Prices: [[]], // price distribution without ERC721 - erc1155Prices: [[500000000]], + erc1155Prices: [[1000000000]], quadPrices: [], }; const bundleAsset = { - bundledERC20, bundledERC721, bundledERC1155, quads, @@ -717,9 +680,10 @@ export function shouldMatchOrdersForBundle() { // left order for partial fill orderLeft = await OrderDefault( maker, - ERC20AssetForLeftOrder, // makeAsset + bundleWithoutERC721Left, // makeAsset ZeroAddress, - bundleWithoutERC721Left, // takeAsset + + ERC20AssetForLeftOrder, // takeAsset 1, 0, 0 @@ -727,9 +691,9 @@ export function shouldMatchOrdersForBundle() { // right order for first partial fill const rightOrderForFirstMatch = await OrderDefault( taker, - bundleWithoutERC721Right, // makeAsset + ERC20AssetForRightOrder, // makeAsset ZeroAddress, - ERC20AssetForRightOrder, // takeAsset + bundleWithoutERC721Right, // takeAsset 1, 0, 0 @@ -757,17 +721,15 @@ export function shouldMatchOrdersForBundle() { expect( await ExchangeContractAsUser.fills(hashKey(orderLeft)) // newFill.rightValue - ).to.be.equal(1); + ).to.be.equal(10000000000); expect( await ExchangeContractAsUser.fills(hashKey(rightOrderForFirstMatch)) // newFill.leftValue - ).to.be.equal(10000000000); + ).to.be.equal(1); - expect(await ERC20Contract.balanceOf(takerAddress)).to.be.equal( + expect(await ERC20Contract.balanceOf(makerAddress)).to.be.equal( 9750000000 ); - expect(await ERC20Contract.balanceOf(maker)).to.be.equal(20000000000); - expect(await ERC20Contract2.balanceOf(maker)).to.be.equal(20000000000); - expect(await ERC20Contract2.balanceOf(taker)).to.be.equal(20000000000); + expect(await ERC20Contract.balanceOf(taker)).to.be.equal(20000000000); expect( await ERC20Contract.balanceOf(defaultFeeReceiver.getAddress()) @@ -778,18 +740,18 @@ export function shouldMatchOrdersForBundle() { ); // 1 * partial fills => 1 * fee taken expect(await ERC1155Contract.balanceOf(makerAddress, 1)).to.be.equal( - 10 + 40 ); expect(await ERC1155Contract.balanceOf(takerAddress, 1)).to.be.equal( - 40 + 10 ); // right order for second partial fill const rightOrderForSecondMatch = await OrderDefault( taker, - bundleWithoutERC721Right, // makeAsset + ERC20AssetForRightOrder, // makeAsset ZeroAddress, - ERC20AssetForRightOrder, // takeAsset + bundleWithoutERC721Right, // takeAsset 2, 0, 0 @@ -812,17 +774,16 @@ export function shouldMatchOrdersForBundle() { expect( await ExchangeContractAsUser.fills(hashKey(orderLeft)) // newFill.rightValue - ).to.be.equal(2); + ).to.be.equal(20000000000); expect( await ExchangeContractAsUser.fills(hashKey(rightOrderForSecondMatch)) // newFill.leftValue - ).to.be.equal(10000000000); + ).to.be.equal(1); - expect(await ERC20Contract.balanceOf(takerAddress)).to.be.equal( + expect(await ERC20Contract.balanceOf(makerAddress)).to.be.equal( 19500000000 ); - expect(await ERC20Contract.balanceOf(maker)).to.be.equal(10000000000); - expect(await ERC20Contract2.balanceOf(maker)).to.be.equal(40000000000); - expect(await ERC20Contract2.balanceOf(taker)).to.be.equal(0); + expect(await ERC20Contract.balanceOf(taker)).to.be.equal(10000000000); + 0; expect( await ERC20Contract.balanceOf(defaultFeeReceiver.getAddress()) @@ -834,53 +795,39 @@ export function shouldMatchOrdersForBundle() { ); // 2 * partial fills => 2 * fee taken expect(await ERC1155Contract.balanceOf(makerAddress, 1)).to.be.equal( - 20 + 30 ); expect(await ERC1155Contract.balanceOf(takerAddress, 1)).to.be.equal( - 30 + 20 ); }); }); - describe('Bundle x ERC20 token', function () { + describe('ERC20 x Bundle with Quads', function () { beforeEach(async function () { ({ ExchangeContractAsUser, + ExchangeContractAsAdmin, OrderValidatorAsAdmin, ERC20Contract, - ERC20Contract2, ERC721Contract, ERC1155Contract, protocolFeeSecondary, defaultFeeReceiver, user1: maker, user2: taker, + deployer: royaltyReceiver, + LandContract, + LandAsAdmin, + landAdmin, } = await loadFixture(deployFixtures)); priceDistribution = { - erc20Prices: [2000000000], - erc721Prices: [[3000000000]], + erc721Prices: [[4000000000]], // price distribution without ERC721 erc1155Prices: [[500000000]], - quadPrices: [], + quadPrices: [500000000, 500000000], }; - // Set up ERC20 for taker - await ERC20Contract.mint(await taker.getAddress(), 30000000000); - await ERC20Contract.connect(taker).approve( - await ExchangeContractAsUser.getAddress(), - 30000000000 - ); - - // Construct takerAsset - takerAsset = await AssetERC20(ERC20Contract, 10000000000); - - // Set up ERC20 for maker - await ERC20Contract2.mint(await maker.getAddress(), 40000000000); - await ERC20Contract2.connect(maker).approve( - await ExchangeContractAsUser.getAddress(), - 40000000000 - ); - // Set up ERC721 for maker await ERC721Contract.mint(await maker.getAddress(), 1); await ERC721Contract.connect(maker).approve( @@ -896,13 +843,32 @@ export function shouldMatchOrdersForBundle() { true ); + // Make sure the land contract address is set on the Exchange + const landContractAddress = await LandContract.getAddress(); + await ExchangeContractAsAdmin.setLandContract(landContractAddress); + + // Land contract setup for maker ------------------------------------------------------------- + + // Set a minter + await LandAsAdmin.setMinter(await landAdmin.getAddress(), true); + + // Ensure that the marketplace contract is an approved operator for mock land contract + await LandContract.connect(maker).setApprovalForAllWithOutFilter( + await ExchangeContractAsUser.getAddress(), + true + ); + + await LandAsAdmin.mintQuad(await maker.getAddress(), 3, 0, 0, '0x'); + await LandAsAdmin.mintQuad(await maker.getAddress(), 3, 0, 3, '0x'); + await LandAsAdmin.mintQuad(await maker.getAddress(), 3, 3, 0, '0x'); + await LandAsAdmin.mintQuad(await maker.getAddress(), 3, 3, 3, '0x'); + expect( + await LandContract.balanceOf(await maker.getAddress()) + ).to.be.equal(36); + + // End land setup for maker ------------------------------------------------------------------ + // Construct makerAsset bundle - bundledERC20 = [ - { - erc20Address: ERC20Contract2.target, - value: 20000000000, - }, - ]; bundledERC721 = [ { erc721Address: ERC721Contract.target, @@ -919,15 +885,14 @@ export function shouldMatchOrdersForBundle() { ]; quads = { - sizes: [], - xs: [], - ys: [], + sizes: [3, 3], // 3x3, 3x3 = 9+9 lands total + xs: [3, 0], + ys: [0, 3], data: '0x', - }; // empty quads + }; // Create bundle for passing as right order bundleData = { - bundledERC20, bundledERC721, bundledERC1155, quads, @@ -935,12 +900,22 @@ export function shouldMatchOrdersForBundle() { }; makerAsset = await AssetBundle(bundleData, 1); // there can only ever be 1 copy of a bundle that contains ERC721 + + // Set up ERC20 for taker + await ERC20Contract.mint(await taker.getAddress(), 30000000000); + await ERC20Contract.connect(taker).approve( + await ExchangeContractAsUser.getAddress(), + 30000000000 + ); + + // Construct takerAsset + takerAsset = await AssetERC20(ERC20Contract, 10000000000); }); - it('should execute a complete match order between ERC20 tokens and Bundle containing ERC20, ERC721 and ERC1155', async function () { + it('should execute a complete match order between ERC20 tokens and Bundle containing ERC20, ERC721, ERC1155 and Quads', async function () { orderLeft = await OrderDefault( - maker, // Bundle - makerAsset, + maker, + makerAsset, // Bundle ZeroAddress, takerAsset, // ERC20 1, @@ -963,14 +938,10 @@ export function shouldMatchOrdersForBundle() { const makerAddress = await maker.getAddress(); const takerAddress = await taker.getAddress(); + expect(await ERC20Contract.balanceOf(makerAddress)).to.be.equal(0); expect(await ERC20Contract.balanceOf(takerAddress)).to.be.equal( 30000000000 ); - expect(await ERC20Contract.balanceOf(makerAddress)).to.be.equal(0); - expect(await ERC20Contract2.balanceOf(takerAddress)).to.be.equal(0); - expect(await ERC20Contract2.balanceOf(makerAddress)).to.be.equal( - 40000000000 - ); expect(await ERC721Contract.ownerOf(1)).to.be.equal(makerAddress); expect(await ERC1155Contract.balanceOf(makerAddress, 1)).to.be.equal( 50 @@ -985,13 +956,14 @@ export function shouldMatchOrdersForBundle() { signatureRight: takerSig, }, ]); - expect(await ERC1155Contract.balanceOf(takerAddress, 1)).to.be.equal( - 10 - ); + expect(await ERC721Contract.ownerOf(1)).to.be.equal(takerAddress); expect(await ERC1155Contract.balanceOf(makerAddress, 1)).to.be.equal( 40 ); + expect(await ERC1155Contract.balanceOf(takerAddress, 1)).to.be.equal( + 10 + ); expect( await ExchangeContractAsUser.fills(hashKey(orderLeft)) @@ -1004,227 +976,16 @@ export function shouldMatchOrdersForBundle() { 9750000000 // 10000000000 - protocolFee ); - expect(await ERC20Contract.balanceOf(taker)).to.be.equal(20000000000); - expect(await ERC20Contract2.balanceOf(taker)).to.be.equal(20000000000); - expect(await ERC20Contract2.balanceOf(maker)).to.be.equal(20000000000); + expect(await ERC20Contract.balanceOf(takerAddress)).to.be.equal( + 20000000000 + ); // check protocol fee -> 250 * 10000000000 / 10000 = 250000000 expect( - await ERC20Contract.balanceOf(defaultFeeReceiver.getAddress()) + await ERC20Contract.balanceOf(await defaultFeeReceiver.getAddress()) ).to.be.equal( (Number(protocolFeeSecondary) * Number(takerAsset.value)) / 10000 ); - }); - }); - - describe('ERC20 x Bundle with Quads', function () { - beforeEach(async function () { - ({ - ExchangeContractAsUser, - ExchangeContractAsAdmin, - OrderValidatorAsAdmin, - ERC20Contract, - ERC20Contract2, - ERC721Contract, - ERC1155Contract, - protocolFeeSecondary, - defaultFeeReceiver, - user1: maker, - user2: taker, - deployer: royaltyReceiver, - LandContract, - LandAsAdmin, - landAdmin, - } = await loadFixture(deployFixtures)); - - priceDistribution = { - erc20Prices: [3000000000], - erc721Prices: [[1000000000]], // price distribution without ERC721 - erc1155Prices: [[500000000]], - quadPrices: [500000000, 500000000], - }; - - // Set up ERC20 for maker - await ERC20Contract.mint(await maker.getAddress(), 30000000000); - await ERC20Contract.connect(maker).approve( - await ExchangeContractAsUser.getAddress(), - 30000000000 - ); - - // Construct makerAsset - makerAsset = await AssetERC20(ERC20Contract, 10000000000); - - // Set up ERC20 for taker - await ERC20Contract2.mint(await taker.getAddress(), 40000000000); - await ERC20Contract2.connect(taker).approve( - await ExchangeContractAsUser.getAddress(), - 40000000000 - ); - - // Set up ERC721 for taker - await ERC721Contract.mint(await taker.getAddress(), 1); - await ERC721Contract.connect(taker).approve( - await ExchangeContractAsUser.getAddress(), - 1 - ); - - // Set up ERC1155 for taker - await ERC1155Contract.mint(await taker.getAddress(), 1, 50); - - await ERC1155Contract.connect(taker).setApprovalForAll( - await ExchangeContractAsUser.getAddress(), - true - ); - - // Make sure the land contract address is set on the Exchange - const landContractAddress = await LandContract.getAddress(); - await ExchangeContractAsAdmin.setLandContract(landContractAddress); - - // Land contract setup for taker ------------------------------------------------------------- - - // Set a minter - await LandAsAdmin.setMinter(await landAdmin.getAddress(), true); - - // Ensure that the marketplace contract is an approved operator for mock land contract - await LandContract.connect(taker).setApprovalForAllWithOutFilter( - await ExchangeContractAsUser.getAddress(), - true - ); - - await LandAsAdmin.mintQuad(await taker.getAddress(), 3, 0, 0, '0x'); - await LandAsAdmin.mintQuad(await taker.getAddress(), 3, 0, 3, '0x'); - await LandAsAdmin.mintQuad(await taker.getAddress(), 3, 3, 0, '0x'); - await LandAsAdmin.mintQuad(await taker.getAddress(), 3, 3, 3, '0x'); - expect( - await LandContract.balanceOf(await taker.getAddress()) - ).to.be.equal(36); - - // End land setup for taker ------------------------------------------------------------------ - - // Construct takerAsset bundle - bundledERC20 = [ - { - erc20Address: ERC20Contract2.target, - value: 20000000000, - }, - ]; - bundledERC721 = [ - { - erc721Address: ERC721Contract.target, - ids: [1], - }, - ]; - - bundledERC1155 = [ - { - erc1155Address: ERC1155Contract.target, - ids: [1], - supplies: [10], - }, - ]; - - quads = { - sizes: [3, 3], // 3x3, 3x3 = 9+9 lands total - xs: [3, 0], - ys: [0, 3], - data: '0x', - }; - - // Create bundle for passing as right order - bundleData = { - bundledERC20, - bundledERC721, - bundledERC1155, - quads, - priceDistribution, - }; - - takerAsset = await AssetBundle(bundleData, 1); // there can only ever be 1 copy of a bundle that contains ERC721 - }); - - it('should execute a complete match order between ERC20 tokens and Bundle containing ERC20, ERC721, ERC1155 and Quads', async function () { - orderLeft = await OrderDefault( - maker, // ERC20 - makerAsset, - ZeroAddress, - takerAsset, // Bundle - 1, - 0, - 0 - ); - orderRight = await OrderDefault( - taker, - takerAsset, // Bundle - ZeroAddress, - makerAsset, // ERC20 - 1, - 0, - 0 - ); - - makerSig = await signOrder(orderLeft, maker, OrderValidatorAsAdmin); - takerSig = await signOrder(orderRight, taker, OrderValidatorAsAdmin); - - const makerAddress = await maker.getAddress(); - const takerAddress = await taker.getAddress(); - - expect(await ERC20Contract.balanceOf(makerAddress)).to.be.equal( - 30000000000 - ); - expect(await ERC20Contract.balanceOf(takerAddress)).to.be.equal(0); - expect(await ERC20Contract2.balanceOf(makerAddress)).to.be.equal(0); - expect(await ERC20Contract2.balanceOf(takerAddress)).to.be.equal( - 40000000000 - ); - expect(await ERC721Contract.ownerOf(1)).to.be.equal(takerAddress); - expect(await ERC1155Contract.balanceOf(takerAddress, 1)).to.be.equal( - 50 - ); - expect(await ERC1155Contract.balanceOf(makerAddress, 1)).to.be.equal(0); - - await ExchangeContractAsUser.matchOrders([ - { - orderLeft, // passing ERC20 as left order - signatureLeft: makerSig, - orderRight, // passing Bundle as right order - signatureRight: takerSig, - }, - ]); - expect(await ERC1155Contract.balanceOf(makerAddress, 1)).to.be.equal( - 10 - ); - expect(await ERC721Contract.ownerOf(1)).to.be.equal(makerAddress); - expect(await ERC1155Contract.balanceOf(takerAddress, 1)).to.be.equal( - 40 - ); - - expect( - await ExchangeContractAsUser.fills(hashKey(orderLeft)) - ).to.be.equal(1); - expect( - await ExchangeContractAsUser.fills(hashKey(orderRight)) - ).to.be.equal(10000000000); - - expect(await ERC20Contract.balanceOf(takerAddress)).to.be.equal( - 9750000000 // 10000000000 - protocolFee - ); - - expect(await ERC20Contract.balanceOf(makerAddress)).to.be.equal( - 20000000000 - ); - expect(await ERC20Contract2.balanceOf(makerAddress)).to.be.equal( - 20000000000 - ); - expect(await ERC20Contract2.balanceOf(takerAddress)).to.be.equal( - 20000000000 - ); - - // check protocol fee -> 250 * 10000000000 / 10000 = 250000000 - expect( - await ERC20Contract.balanceOf(await defaultFeeReceiver.getAddress()) - ).to.be.equal( - (Number(protocolFeeSecondary) * Number(makerAsset.value)) / 10000 - ); // check maker received quads expect(await LandContract.balanceOf(takerAddress)).to.be.equal(18); @@ -1240,7 +1001,6 @@ export function shouldMatchOrdersForBundle() { OrderValidatorAsAdmin, RoyaltiesRegistryAsDeployer, ERC20Contract, - ERC20Contract2, ERC721Contract, ERC1155Contract, RoyaltiesProvider, @@ -1258,46 +1018,28 @@ export function shouldMatchOrdersForBundle() { } = await loadFixture(deployFixtures)); priceDistribution = { - erc20Prices: [4000000000], - erc721Prices: [[1000000000]], - erc1155Prices: [[500000000]], + erc721Prices: [[4000000000]], + erc1155Prices: [[600000000]], quadPrices: [], }; - // Set up ERC20 for maker - await ERC20Contract.mint(await maker.getAddress(), 30000000000); - await ERC20Contract.connect(maker).approve( - await ExchangeContractAsUser.getAddress(), - 30000000000 - ); - - // Construct makerAsset - makerAsset = await AssetERC20(ERC20Contract, 10000000000); - - // Set up ERC20 for taker - await ERC20Contract2.mint(await taker.getAddress(), 40000000000); - await ERC20Contract2.connect(taker).approve( - await ExchangeContractAsUser.getAddress(), - 40000000000 - ); - - // Set up ERC721 for taker - await ERC721Contract.mint(await taker.getAddress(), 1); - await ERC721Contract.connect(taker).approve( + // Set up ERC721 for maker + await ERC721Contract.mint(await maker.getAddress(), 1); + await ERC721Contract.connect(maker).approve( await ExchangeContractAsUser.getAddress(), 1 ); - await ERC721Contract.mint(await taker.getAddress(), 2); - await ERC721Contract.connect(taker).approve( + await ERC721Contract.mint(await maker.getAddress(), 2); + await ERC721Contract.connect(maker).approve( await ExchangeContractAsUser.getAddress(), 2 ); - // Set up ERC1155 for taker - await ERC1155Contract.mint(await taker.getAddress(), 1, 50); - await ERC1155Contract.mint(await taker.getAddress(), 2, 50); + // Set up ERC1155 for maker + await ERC1155Contract.mint(await maker.getAddress(), 1, 50); + await ERC1155Contract.mint(await maker.getAddress(), 2, 50); - await ERC1155Contract.connect(taker).setApprovalForAll( + await ERC1155Contract.connect(maker).setApprovalForAll( await ExchangeContractAsUser.getAddress(), true ); @@ -1306,34 +1048,28 @@ export function shouldMatchOrdersForBundle() { const landContractAddress = await LandContract.getAddress(); await ExchangeContractAsAdmin.setLandContract(landContractAddress); - // Land contract setup for taker ------------------------------------------------------------- + // Land contract setup for maker ------------------------------------------------------------- // Set a minter await LandAsAdmin.setMinter(await landAdmin.getAddress(), true); // Ensure that the marketplace contract is an approved operator for mock land contract - await LandContract.connect(taker).setApprovalForAllWithOutFilter( + await LandContract.connect(maker).setApprovalForAllWithOutFilter( await ExchangeContractAsUser.getAddress(), true ); - await LandAsAdmin.mintQuad(await taker.getAddress(), 3, 0, 0, '0x'); - await LandAsAdmin.mintQuad(await taker.getAddress(), 3, 0, 3, '0x'); - await LandAsAdmin.mintQuad(await taker.getAddress(), 3, 3, 0, '0x'); - await LandAsAdmin.mintQuad(await taker.getAddress(), 3, 3, 3, '0x'); + await LandAsAdmin.mintQuad(await maker.getAddress(), 3, 0, 0, '0x'); + await LandAsAdmin.mintQuad(await maker.getAddress(), 3, 0, 3, '0x'); + await LandAsAdmin.mintQuad(await maker.getAddress(), 3, 3, 0, '0x'); + await LandAsAdmin.mintQuad(await maker.getAddress(), 3, 3, 3, '0x'); expect( - await LandContract.balanceOf(await taker.getAddress()) + await LandContract.balanceOf(await maker.getAddress()) ).to.be.equal(36); - // End land setup for taker ------------------------------------------------------------------ + // End land setup for maker ------------------------------------------------------------------ - // Construct takerAsset bundle - bundledERC20 = [ - { - erc20Address: ERC20Contract2.target, - value: 20000000000, - }, - ]; + // Construct makerAsset bundle bundledERC721 = [ { erc721Address: ERC721Contract.target, @@ -1358,14 +1094,23 @@ export function shouldMatchOrdersForBundle() { // Create bundle for passing as right order bundleData = { - bundledERC20, bundledERC721, bundledERC1155, quads, priceDistribution, }; - takerAsset = await AssetBundle(bundleData, 1); // there can only ever be 1 copy of a bundle that contains ERC721 + makerAsset = await AssetBundle(bundleData, 1); // there can only ever be 1 copy of a bundle that contains ERC721 + + // Set up ERC20 for taker + await ERC20Contract.mint(await taker.getAddress(), 30000000000); + await ERC20Contract.connect(taker).approve( + await ExchangeContractAsUser.getAddress(), + 30000000000 + ); + + // Construct takerAsset + takerAsset = await AssetERC20(ERC20Contract, 10000000000); }); it('should not execute match order for bundle if royalties are > 50% for ERC721 token', async function () { @@ -1376,19 +1121,19 @@ export function shouldMatchOrdersForBundle() { ); orderLeft = await OrderDefault( - maker, // ERC20 - makerAsset, + maker, + makerAsset, // Bundle ZeroAddress, - takerAsset, // Bundle + takerAsset, // ERC20 1, 0, 0 ); orderRight = await OrderDefault( taker, - takerAsset, // Bundle + takerAsset, // ERC20 ZeroAddress, - makerAsset, // ERC20 + makerAsset, // Bundle 1, 0, 0 @@ -1400,26 +1145,22 @@ export function shouldMatchOrdersForBundle() { const makerAddress = await maker.getAddress(); const takerAddress = await taker.getAddress(); - expect(await ERC20Contract.balanceOf(makerAddress)).to.be.equal( + expect(await ERC20Contract.balanceOf(makerAddress)).to.be.equal(0); + expect(await ERC20Contract.balanceOf(takerAddress)).to.be.equal( 30000000000 ); - expect(await ERC20Contract.balanceOf(takerAddress)).to.be.equal(0); - expect(await ERC20Contract2.balanceOf(makerAddress)).to.be.equal(0); - expect(await ERC20Contract2.balanceOf(takerAddress)).to.be.equal( - 40000000000 - ); - expect(await ERC721Contract.ownerOf(1)).to.be.equal(takerAddress); - expect(await ERC1155Contract.balanceOf(takerAddress, 1)).to.be.equal( + expect(await ERC721Contract.ownerOf(1)).to.be.equal(makerAddress); + expect(await ERC1155Contract.balanceOf(makerAddress, 1)).to.be.equal( 50 ); - expect(await ERC1155Contract.balanceOf(makerAddress, 1)).to.be.equal(0); + expect(await ERC1155Contract.balanceOf(takerAddress, 1)).to.be.equal(0); await expect( ExchangeContractAsUser.matchOrders([ { - orderLeft, // passing ERC20 as left order + orderLeft, // passing Bundle as left order signatureLeft: makerSig, - orderRight, // passing Bundle as right order + orderRight, // passing ERC20 as right order signatureRight: takerSig, }, ]) @@ -1434,86 +1175,83 @@ export function shouldMatchOrdersForBundle() { ); orderLeft = await OrderDefault( - maker, // ERC20 - makerAsset, + maker, + makerAsset, // Bundle ZeroAddress, - takerAsset, // Bundle + takerAsset, // ERC20 1, 0, 0 ); orderRight = await OrderDefault( taker, - takerAsset, // Bundle + takerAsset, // ERC20 ZeroAddress, - makerAsset, // ERC20 + makerAsset, // Bundle 1, 0, 0 ); - 8000000000; + makerSig = await signOrder(orderLeft, maker, OrderValidatorAsAdmin); takerSig = await signOrder(orderRight, taker, OrderValidatorAsAdmin); const makerAddress = await maker.getAddress(); const takerAddress = await taker.getAddress(); - expect(await ERC20Contract.balanceOf(makerAddress)).to.be.equal( + expect(await ERC20Contract.balanceOf(makerAddress)).to.be.equal(0); + expect(await ERC20Contract.balanceOf(takerAddress)).to.be.equal( 30000000000 ); - expect(await ERC20Contract.balanceOf(takerAddress)).to.be.equal(0); - expect(await ERC20Contract2.balanceOf(makerAddress)).to.be.equal(0); - expect(await ERC20Contract2.balanceOf(takerAddress)).to.be.equal( - 40000000000 - ); - expect(await ERC721Contract.ownerOf(1)).to.be.equal(takerAddress); - expect(await ERC1155Contract.balanceOf(takerAddress, 1)).to.be.equal( + + expect(await ERC721Contract.ownerOf(1)).to.be.equal(makerAddress); + expect(await ERC1155Contract.balanceOf(makerAddress, 1)).to.be.equal( 50 ); - expect(await ERC1155Contract.balanceOf(makerAddress, 1)).to.be.equal(0); + expect(await ERC1155Contract.balanceOf(takerAddress, 1)).to.be.equal(0); await ExchangeContractAsUser.matchOrders([ { - orderLeft, // passing ERC20 as left order + orderLeft, // passing Bundle as left order signatureLeft: makerSig, - orderRight, // passing Bundle as right order + orderRight, // passing ERC20 as right order signatureRight: takerSig, }, ]); + expect(await ERC721Contract.ownerOf(1)).to.be.equal(takerAddress); expect(await ERC1155Contract.balanceOf(makerAddress, 1)).to.be.equal( - 10 + 40 ); - expect(await ERC721Contract.ownerOf(1)).to.be.equal(makerAddress); expect(await ERC1155Contract.balanceOf(takerAddress, 1)).to.be.equal( - 40 + 10 ); expect( await ExchangeContractAsUser.fills(hashKey(orderLeft)) - ).to.be.equal(1); + ).to.be.equal(10000000000); expect( await ExchangeContractAsUser.fills(hashKey(orderRight)) - ).to.be.equal(10000000000); + ).to.be.equal(1); - expect(await ERC20Contract.balanceOf(takerAddress)).to.be.equal( - 9550000000 // 10000000000 - royalty - protocolFee + expect(await ERC20Contract.balanceOf(makerAddress)).to.be.equal( + 8950000000 // 10000000000 - royalty - protocolFee ); - expect(await ERC20Contract.balanceOf(maker)).to.be.equal(20000000000); - expect(await ERC20Contract2.balanceOf(maker)).to.be.equal(20000000000); - expect(await ERC20Contract2.balanceOf(taker)).to.be.equal(20000000000); + expect(await ERC20Contract.balanceOf(takerAddress)).to.be.equal( + 20000000000 + ); // check paid royalty expect( await ERC20Contract.balanceOf(royaltyReceiver.getAddress()) - ).to.be.equal(200000000); // 10% of asset price for ERC721 token + ).to.be.equal(800000000); // 20% of asset price for ERC721 token // check protocol fee -> 250 * 10000000000 / 10000 = 250000000 expect( await ERC20Contract.balanceOf(defaultFeeReceiver.getAddress()) ).to.be.equal( - (Number(protocolFeeSecondary) * Number(makerAsset.value)) / 10000 + (Number(protocolFeeSecondary) * Number(takerAsset.value)) / 10000 ); }); @@ -1526,21 +1264,19 @@ export function shouldMatchOrdersForBundle() { ]; priceDistribution = { - erc20Prices: [4000000000], - erc721Prices: [[400000000, 600000000]], + erc721Prices: [[2000000000, 3000000000]], erc1155Prices: [[500000000]], quadPrices: [], }; bundleData = { - bundledERC20, bundledERC721, bundledERC1155, quads, priceDistribution, }; - takerAsset = await AssetBundle(bundleData, 1); + makerAsset = await AssetBundle(bundleData, 1); // configuring royalties await RoyaltiesProvider.initializeProvider( @@ -1559,19 +1295,19 @@ export function shouldMatchOrdersForBundle() { ); orderLeft = await OrderDefault( - maker, // ERC20 - makerAsset, + maker, + makerAsset, // Bundle ZeroAddress, - takerAsset, // Bundle + takerAsset, // ERC20 1, 0, 0 ); orderRight = await OrderDefault( taker, - takerAsset, // Bundle + takerAsset, // ERC20 ZeroAddress, - makerAsset, // ERC20 + makerAsset, // Bundle 1, 0, 0 @@ -1583,65 +1319,60 @@ export function shouldMatchOrdersForBundle() { const makerAddress = await maker.getAddress(); const takerAddress = await taker.getAddress(); - expect(await ERC20Contract.balanceOf(makerAddress)).to.be.equal( + expect(await ERC20Contract.balanceOf(makerAddress)).to.be.equal(0); + expect(await ERC20Contract.balanceOf(takerAddress)).to.be.equal( 30000000000 ); - expect(await ERC20Contract.balanceOf(takerAddress)).to.be.equal(0); - expect(await ERC20Contract2.balanceOf(makerAddress)).to.be.equal(0); - expect(await ERC20Contract2.balanceOf(takerAddress)).to.be.equal( - 40000000000 - ); - expect(await ERC721Contract.ownerOf(1)).to.be.equal(takerAddress); - expect(await ERC1155Contract.balanceOf(takerAddress, 1)).to.be.equal( + expect(await ERC721Contract.ownerOf(1)).to.be.equal(makerAddress); + expect(await ERC1155Contract.balanceOf(makerAddress, 1)).to.be.equal( 50 ); - expect(await ERC1155Contract.balanceOf(makerAddress, 1)).to.be.equal(0); + expect(await ERC1155Contract.balanceOf(takerAddress, 1)).to.be.equal(0); await ExchangeContractAsUser.matchOrders([ { - orderLeft, // passing ERC20 as left order + orderLeft, // passing Bundle as left order signatureLeft: makerSig, - orderRight, // passing Bundle as right order + orderRight, // passing ERC20 as right order signatureRight: takerSig, }, ]); + expect(await ERC721Contract.ownerOf(1)).to.be.equal(takerAddress); expect(await ERC1155Contract.balanceOf(makerAddress, 1)).to.be.equal( - 10 + 40 ); - expect(await ERC721Contract.ownerOf(1)).to.be.equal(makerAddress); expect(await ERC1155Contract.balanceOf(takerAddress, 1)).to.be.equal( - 40 + 10 ); expect( await ExchangeContractAsUser.fills(hashKey(orderLeft)) - ).to.be.equal(1); + ).to.be.equal(10000000000); expect( await ExchangeContractAsUser.fills(hashKey(orderRight)) - ).to.be.equal(10000000000); + ).to.be.equal(1); + expect(await ERC20Contract.balanceOf(makerAddress)).to.be.equal( + 8950000000 // 10000000000 - royalty - protocolFee + ); expect(await ERC20Contract.balanceOf(takerAddress)).to.be.equal( - 9590000000 // 10000000000 - royalty - protocolFee + 20000000000 ); - expect(await ERC20Contract.balanceOf(maker)).to.be.equal(20000000000); - expect(await ERC20Contract2.balanceOf(maker)).to.be.equal(20000000000); - expect(await ERC20Contract2.balanceOf(taker)).to.be.equal(20000000000); - // check paid royalty expect( await ERC20Contract.balanceOf(royaltyReceiver.getAddress()) - ).to.be.equal(40000000); // 10% of asset price for ERC721 token with id:1 + ).to.be.equal(200000000); // 10% of asset price for ERC721 token with id:1 expect( await ERC20Contract.balanceOf(royaltyReceiver2.getAddress()) - ).to.be.equal(120000000); // 20% of asset price for ERC721 token with id:2 + ).to.be.equal(600000000); // 20% of asset price for ERC721 token with id:2 // check protocol fee -> 250 * 10000000000 / 10000 = 250000000 expect( await ERC20Contract.balanceOf(defaultFeeReceiver.getAddress()) ).to.be.equal( - (Number(protocolFeeSecondary) * Number(makerAsset.value)) / 10000 + (Number(protocolFeeSecondary) * Number(takerAsset.value)) / 10000 ); }); @@ -1655,14 +1386,13 @@ export function shouldMatchOrdersForBundle() { ]; bundleData = { - bundledERC20, bundledERC721, bundledERC1155, quads, priceDistribution, }; - takerAsset = await AssetBundle(bundleData, 1); + makerAsset = await AssetBundle(bundleData, 1); // configuring royalties await RoyaltiesProvider.initializeProvider( @@ -1676,19 +1406,19 @@ export function shouldMatchOrdersForBundle() { ); orderLeft = await OrderDefault( - maker, // ERC20 - makerAsset, + maker, + makerAsset, // Bundle ZeroAddress, - takerAsset, // Bundle + takerAsset, // ERC20 1, 0, 0 ); orderRight = await OrderDefault( taker, - takerAsset, // Bundle + takerAsset, // ERC20 ZeroAddress, - makerAsset, // ERC20 + makerAsset, // Bundle 1, 0, 0 @@ -1700,26 +1430,22 @@ export function shouldMatchOrdersForBundle() { const makerAddress = await maker.getAddress(); const takerAddress = await taker.getAddress(); - expect(await ERC20Contract.balanceOf(makerAddress)).to.be.equal( + expect(await ERC20Contract.balanceOf(makerAddress)).to.be.equal(0); + expect(await ERC20Contract.balanceOf(takerAddress)).to.be.equal( 30000000000 ); - expect(await ERC20Contract.balanceOf(takerAddress)).to.be.equal(0); - expect(await ERC20Contract2.balanceOf(makerAddress)).to.be.equal(0); - expect(await ERC20Contract2.balanceOf(takerAddress)).to.be.equal( - 40000000000 - ); - expect(await ERC721Contract.ownerOf(1)).to.be.equal(takerAddress); - expect(await ERC1155Contract.balanceOf(takerAddress, 1)).to.be.equal( + expect(await ERC721Contract.ownerOf(1)).to.be.equal(makerAddress); + expect(await ERC1155Contract.balanceOf(makerAddress, 1)).to.be.equal( 50 ); - expect(await ERC1155Contract.balanceOf(makerAddress, 1)).to.be.equal(0); + expect(await ERC1155Contract.balanceOf(takerAddress, 1)).to.be.equal(0); await expect( ExchangeContractAsUser.matchOrders([ { - orderLeft, // passing ERC20 as left order + orderLeft, // passing Bundle as left order signatureLeft: makerSig, - orderRight, // passing Bundle as right order + orderRight, // passing ERC20 as right order signatureRight: takerSig, }, ]) @@ -1728,14 +1454,13 @@ export function shouldMatchOrdersForBundle() { it('should execute complete match order for bundle with royalty on ERC1155 token', async function () { bundleData = { - bundledERC20, bundledERC721, bundledERC1155, quads, priceDistribution, }; - takerAsset = await AssetBundle(bundleData, 1); + makerAsset = await AssetBundle(bundleData, 1); // configuring royalties await RoyaltiesProvider.initializeProvider( @@ -1750,19 +1475,19 @@ export function shouldMatchOrdersForBundle() { ); orderLeft = await OrderDefault( - maker, // ERC20 - makerAsset, + maker, + makerAsset, // Bundle ZeroAddress, - takerAsset, // Bundle + takerAsset, // ERC20 1, 0, 0 ); orderRight = await OrderDefault( taker, - takerAsset, // Bundle + takerAsset, // ERC20 ZeroAddress, - makerAsset, // ERC20 + makerAsset, // Bundle 1, 0, 0 @@ -1774,121 +1499,252 @@ export function shouldMatchOrdersForBundle() { const makerAddress = await maker.getAddress(); const takerAddress = await taker.getAddress(); - expect(await ERC20Contract.balanceOf(makerAddress)).to.be.equal( + expect(await ERC20Contract.balanceOf(makerAddress)).to.be.equal(0); + expect(await ERC20Contract.balanceOf(takerAddress)).to.be.equal( 30000000000 ); - expect(await ERC20Contract.balanceOf(takerAddress)).to.be.equal(0); - expect(await ERC20Contract2.balanceOf(makerAddress)).to.be.equal(0); - expect(await ERC20Contract2.balanceOf(takerAddress)).to.be.equal( - 40000000000 + expect(await ERC721Contract.ownerOf(1)).to.be.equal(makerAddress); + expect(await ERC1155Contract.balanceOf(makerAddress, 1)).to.be.equal( + 50 ); + expect(await ERC1155Contract.balanceOf(takerAddress, 1)).to.be.equal(0); + + await ExchangeContractAsUser.matchOrders([ + { + orderLeft, // passing Bundle as left order + signatureLeft: makerSig, + orderRight, // passing ERC20 as right order + signatureRight: takerSig, + }, + ]); + expect(await ERC721Contract.ownerOf(1)).to.be.equal(takerAddress); + expect(await ERC1155Contract.balanceOf(makerAddress, 1)).to.be.equal( + 40 + ); expect(await ERC1155Contract.balanceOf(takerAddress, 1)).to.be.equal( + 10 + ); + + expect( + await ExchangeContractAsUser.fills(hashKey(orderLeft)) + ).to.be.equal(10000000000); + expect( + await ExchangeContractAsUser.fills(hashKey(orderRight)) + ).to.be.equal(1); + + expect(await ERC20Contract.balanceOf(makerAddress)).to.be.equal( + 9720000000 // 10000000000 - royalty - protocolFee + ); + expect(await ERC20Contract.balanceOf(takerAddress)).to.be.equal( + 20000000000 + ); + + // check paid royalty + expect( + await ERC20Contract.balanceOf(royaltyReceiver.getAddress()) + ).to.be.equal(30000000); // 5% of asset price for ERC1155 token with id:1 + + // check protocol fee -> 250 * 10000000000 / 10000 = 250000000 + expect( + await ERC20Contract.balanceOf(defaultFeeReceiver.getAddress()) + ).to.be.equal( + (Number(protocolFeeSecondary) * Number(takerAsset.value)) / 10000 + ); + }); + + it('should execute complete match order for bundle with multiple royalty receivers on ERC1155 token', async function () { + bundledERC1155 = [ + { + erc1155Address: ERC1155Contract.target, + ids: [1, 2], + supplies: [10, 5], + }, + ]; + + priceDistribution = { + erc721Prices: [[5000000000]], + erc1155Prices: [[300000000, 400000000]], + quadPrices: [], + }; + + bundleData = { + bundledERC721, + bundledERC1155, + quads, + priceDistribution, + }; + + makerAsset = await AssetBundle(bundleData, 1); + + // configuring royalties + await RoyaltiesProvider.initializeProvider( + await ERC1155Contract.getAddress(), + 1, + [await LibPartData(royaltyReceiver, 500)] // 5% royalty for ERC1155 token with id:1 + ); + await RoyaltiesProvider.initializeProvider( + await ERC1155Contract.getAddress(), + 2, + [await LibPartData(royaltyReceiver2, 1000)] // 10% royalty for ERC1155 token with id:2 + ); + await RoyaltiesRegistryAsDeployer.setProviderByToken( + await ERC1155Contract.getAddress(), + RoyaltiesProvider.getAddress() + ); + + orderLeft = await OrderDefault( + maker, + makerAsset, // Bundle + ZeroAddress, + takerAsset, // ERC20 + 1, + 0, + 0 + ); + orderRight = await OrderDefault( + taker, + takerAsset, // ERC20 + ZeroAddress, + makerAsset, // Bundle + 1, + 0, + 0 + ); + + makerSig = await signOrder(orderLeft, maker, OrderValidatorAsAdmin); + takerSig = await signOrder(orderRight, taker, OrderValidatorAsAdmin); + + const makerAddress = await maker.getAddress(); + const takerAddress = await taker.getAddress(); + + expect(await ERC20Contract.balanceOf(makerAddress)).to.be.equal(0); + expect(await ERC20Contract.balanceOf(takerAddress)).to.be.equal( + 30000000000 + ); + expect(await ERC721Contract.ownerOf(1)).to.be.equal(makerAddress); + expect(await ERC1155Contract.balanceOf(makerAddress, 1)).to.be.equal( + 50 + ); + expect(await ERC1155Contract.balanceOf(makerAddress, 2)).to.be.equal( 50 ); - expect(await ERC1155Contract.balanceOf(makerAddress, 1)).to.be.equal(0); + expect(await ERC1155Contract.balanceOf(takerAddress, 1)).to.be.equal(0); + expect(await ERC1155Contract.balanceOf(takerAddress, 2)).to.be.equal(0); await ExchangeContractAsUser.matchOrders([ { - orderLeft, // passing ERC20 as left order + orderLeft, // passing Bundle as left order signatureLeft: makerSig, - orderRight, // passing Bundle as right order + orderRight, // passing ERC20 as right order signatureRight: takerSig, }, ]); + expect(await ERC721Contract.ownerOf(1)).to.be.equal(takerAddress); expect(await ERC1155Contract.balanceOf(makerAddress, 1)).to.be.equal( - 10 + 40 + ); + expect(await ERC1155Contract.balanceOf(makerAddress, 2)).to.be.equal( + 45 ); - expect(await ERC721Contract.ownerOf(1)).to.be.equal(makerAddress); expect(await ERC1155Contract.balanceOf(takerAddress, 1)).to.be.equal( - 40 + 10 ); + expect(await ERC1155Contract.balanceOf(takerAddress, 2)).to.be.equal(5); expect( await ExchangeContractAsUser.fills(hashKey(orderLeft)) - ).to.be.equal(1); + ).to.be.equal(10000000000); expect( await ExchangeContractAsUser.fills(hashKey(orderRight)) - ).to.be.equal(10000000000); + ).to.be.equal(1); - expect(await ERC20Contract.balanceOf(takerAddress)).to.be.equal( - 9725000000 // 10000000000 - royalty - protocolFee + expect(await ERC20Contract.balanceOf(makerAddress)).to.be.equal( + 9695000000 // 10000000000 - royalty - protocolFee ); - expect(await ERC20Contract.balanceOf(maker)).to.be.equal(20000000000); - expect(await ERC20Contract2.balanceOf(maker)).to.be.equal(20000000000); - expect(await ERC20Contract2.balanceOf(taker)).to.be.equal(20000000000); + expect(await ERC20Contract.balanceOf(takerAddress)).to.be.equal( + 20000000000 + ); // check paid royalty expect( await ERC20Contract.balanceOf(royaltyReceiver.getAddress()) - ).to.be.equal(25000000); // 5% of asset price for ERC1155 token with id:1 + ).to.be.equal(15000000); // 5% of asset price for ERC1155 token with id:1 + expect( + await ERC20Contract.balanceOf(royaltyReceiver2.getAddress()) + ).to.be.equal(40000000); // 10% of asset price for ERC1155 token with id:2 // check protocol fee -> 250 * 10000000000 / 10000 = 250000000 expect( await ERC20Contract.balanceOf(defaultFeeReceiver.getAddress()) ).to.be.equal( - (Number(protocolFeeSecondary) * Number(makerAsset.value)) / 10000 + (Number(protocolFeeSecondary) * Number(takerAsset.value)) / 10000 ); }); - it('should execute complete match order for bundle with multiple royalty receivers on ERC1155 token', async function () { - bundledERC1155 = [ - { - erc1155Address: ERC1155Contract.target, - ids: [1, 2], - supplies: [10, 5], - }, - ]; + it('should partially fill orders using matchOrders between ERC20 and ERC1155 BUNDLE with order value >1', async function () { + // Seller (taker - right) has 5 copies of a Bundle type; buyer (taker - left) just wants to buy 1 of these + const ERC20AssetForLeftOrder = await AssetERC20( + ERC20Contract, + 50000000000 + ); + + // ERC20Asset for partial fill + const ERC20AssetForRightOrder = await AssetERC20( + ERC20Contract, + 20000000000 + ); + + bundledERC721 = []; priceDistribution = { - erc20Prices: [4000000000], - erc721Prices: [[1000000000]], - erc1155Prices: [[300000000, 400000000]], + erc721Prices: [[]], // price distribution without ERC721 + erc1155Prices: [[1000000000]], quadPrices: [], }; - bundleData = { - bundledERC20, + const bundleAsset = { bundledERC721, bundledERC1155, quads, priceDistribution, }; - takerAsset = await AssetBundle(bundleData, 1); - // configuring royalties await RoyaltiesProvider.initializeProvider( await ERC1155Contract.getAddress(), 1, - [await LibPartData(royaltyReceiver, 500)] // 5% royalty for ERC1155 token with id:1 - ); - await RoyaltiesProvider.initializeProvider( - await ERC1155Contract.getAddress(), - 2, - [await LibPartData(royaltyReceiver2, 1000)] // 10% royalty for ERC1155 token with id:2 + [await LibPartData(royaltyReceiver, 1000)] // 10% royalty for ERC1155 token with id:1 ); + await RoyaltiesRegistryAsDeployer.setProviderByToken( await ERC1155Contract.getAddress(), RoyaltiesProvider.getAddress() ); + // ERC1155Asset for partial fill + bundleWithoutERC721Left = await AssetBundle(bundleAsset, 5); + + bundleWithoutERC721Right = await AssetBundle(bundleAsset, 2); + + // left order for partial fill orderLeft = await OrderDefault( - maker, // ERC20 - makerAsset, + maker, + bundleWithoutERC721Left, // makeAsset ZeroAddress, - takerAsset, // Bundle + ERC20AssetForLeftOrder, // takeAsset 1, 0, 0 ); + // right order for partial fill orderRight = await OrderDefault( taker, - takerAsset, // Bundle + ERC20AssetForRightOrder, // makeAsset ZeroAddress, - makerAsset, // ERC20 + bundleWithoutERC721Right, // takeAsset 1, 0, 0 @@ -1900,74 +1756,64 @@ export function shouldMatchOrdersForBundle() { const makerAddress = await maker.getAddress(); const takerAddress = await taker.getAddress(); - expect(await ERC20Contract.balanceOf(makerAddress)).to.be.equal( + expect(await ERC20Contract.balanceOf(makerAddress)).to.be.equal(0); + expect(await ERC20Contract.balanceOf(takerAddress)).to.be.equal( 30000000000 ); - expect(await ERC20Contract.balanceOf(takerAddress)).to.be.equal(0); - expect(await ERC20Contract2.balanceOf(makerAddress)).to.be.equal(0); - expect(await ERC20Contract2.balanceOf(takerAddress)).to.be.equal( - 40000000000 - ); - expect(await ERC721Contract.ownerOf(1)).to.be.equal(takerAddress); - expect(await ERC1155Contract.balanceOf(takerAddress, 1)).to.be.equal( - 50 - ); - expect(await ERC1155Contract.balanceOf(takerAddress, 2)).to.be.equal( + expect(await ERC1155Contract.balanceOf(takerAddress, 1)).to.be.equal(0); + expect(await ERC1155Contract.balanceOf(makerAddress, 1)).to.be.equal( 50 ); - expect(await ERC1155Contract.balanceOf(makerAddress, 1)).to.be.equal(0); - expect(await ERC1155Contract.balanceOf(makerAddress, 2)).to.be.equal(0); + expect( + await ExchangeContractAsUser.fills(hashKey(orderLeft)) + ).to.be.equal(0); + expect( + await ExchangeContractAsUser.fills(hashKey(orderRight)) + ).to.be.equal(0); await ExchangeContractAsUser.matchOrders([ { - orderLeft, // passing ERC20 as left order + orderLeft, signatureLeft: makerSig, - orderRight, // passing Bundle as right order + orderRight, signatureRight: takerSig, }, ]); - expect(await ERC1155Contract.balanceOf(makerAddress, 1)).to.be.equal( - 10 - ); - expect(await ERC1155Contract.balanceOf(makerAddress, 2)).to.be.equal(5); - expect(await ERC721Contract.ownerOf(1)).to.be.equal(makerAddress); - expect(await ERC1155Contract.balanceOf(takerAddress, 1)).to.be.equal( - 40 - ); - expect(await ERC1155Contract.balanceOf(takerAddress, 2)).to.be.equal( - 45 - ); - expect( - await ExchangeContractAsUser.fills(hashKey(orderLeft)) - ).to.be.equal(1); + await ExchangeContractAsUser.fills(hashKey(orderLeft)) // newFill.rightValue + ).to.be.equal(20000000000); expect( - await ExchangeContractAsUser.fills(hashKey(orderRight)) - ).to.be.equal(10000000000); + await ExchangeContractAsUser.fills(hashKey(orderRight)) // newFill.leftValue + ).to.be.equal(2); + expect(await ERC20Contract.balanceOf(makerAddress)).to.be.equal( + 19300000000 // 10000000000 - royalty - protocolFee + ); expect(await ERC20Contract.balanceOf(takerAddress)).to.be.equal( - 9695000000 // 10000000000 - royalty - protocolFee + 10000000000 ); - - expect(await ERC20Contract.balanceOf(maker)).to.be.equal(20000000000); - expect(await ERC20Contract2.balanceOf(maker)).to.be.equal(20000000000); - expect(await ERC20Contract2.balanceOf(taker)).to.be.equal(20000000000); - + 100000000; // check paid royalty expect( await ERC20Contract.balanceOf(royaltyReceiver.getAddress()) - ).to.be.equal(15000000); // 5% of asset price for ERC1155 token with id:1 - expect( - await ERC20Contract.balanceOf(royaltyReceiver2.getAddress()) - ).to.be.equal(40000000); // 10% of asset price for ERC1155 token with id:2 + ).to.be.equal(200000000); // 10% of asset price for ERC1155 token with id:1 for 2 bundles - // check protocol fee -> 250 * 10000000000 / 10000 = 250000000 expect( await ERC20Contract.balanceOf(defaultFeeReceiver.getAddress()) ).to.be.equal( - (Number(protocolFeeSecondary) * Number(makerAsset.value)) / 10000 + (Number(protocolFeeSecondary) * + Number(ERC20AssetForRightOrder.value)) / + 10000 ); + + expect(await ERC1155Contract.balanceOf(makerAddress, 1)).to.be.equal( + 30 + ); + expect(await ERC1155Contract.balanceOf(takerAddress, 1)).to.be.equal( + 20 + ); + // TODO: royalties checks for tokens }); it('should execute complete match order for bundle with royalty on Quads', async function () { @@ -1979,22 +1825,20 @@ export function shouldMatchOrdersForBundle() { }; priceDistribution = { - erc20Prices: [3000000000], - erc721Prices: [[1000000000]], + erc721Prices: [[4000000000]], erc1155Prices: [[500000000]], quadPrices: [400000000, 600000000], }; // Create bundle for passing as right order bundleData = { - bundledERC20, bundledERC721, bundledERC1155, quads, priceDistribution, }; - takerAsset = await AssetBundle(bundleData, 1); + makerAsset = await AssetBundle(bundleData, 1); // set up royalties by token await RoyaltiesRegistryAsDeployer.setRoyaltiesByToken( @@ -2003,19 +1847,19 @@ export function shouldMatchOrdersForBundle() { ); orderLeft = await OrderDefault( - maker, // ERC20 - makerAsset, + maker, + makerAsset, // Bundle ZeroAddress, - takerAsset, // Bundle + takerAsset, // ERC20 1, 0, 0 ); orderRight = await OrderDefault( taker, - takerAsset, // Bundle + takerAsset, // ERC20 ZeroAddress, - makerAsset, // ERC20 + makerAsset, // Bundle 1, 0, 0 @@ -2027,54 +1871,46 @@ export function shouldMatchOrdersForBundle() { const makerAddress = await maker.getAddress(); const takerAddress = await taker.getAddress(); - expect(await ERC20Contract.balanceOf(makerAddress)).to.be.equal( + expect(await ERC721Contract.ownerOf(1)).to.be.equal(makerAddress); + expect(await ERC20Contract.balanceOf(makerAddress)).to.be.equal(0); + expect(await ERC20Contract.balanceOf(takerAddress)).to.be.equal( 30000000000 ); - expect(await ERC20Contract.balanceOf(takerAddress)).to.be.equal(0); - expect(await ERC20Contract2.balanceOf(makerAddress)).to.be.equal(0); - expect(await ERC20Contract2.balanceOf(takerAddress)).to.be.equal( - 40000000000 - ); - expect(await ERC721Contract.ownerOf(1)).to.be.equal(takerAddress); - expect(await ERC1155Contract.balanceOf(takerAddress, 1)).to.be.equal( + + expect(await ERC1155Contract.balanceOf(makerAddress, 1)).to.be.equal( 50 ); - expect(await ERC1155Contract.balanceOf(makerAddress, 1)).to.be.equal(0); + expect(await ERC1155Contract.balanceOf(takerAddress, 1)).to.be.equal(0); await ExchangeContractAsUser.matchOrders([ { - orderLeft, // passing ERC20 as left order + orderLeft, // passing Bundle as left order signatureLeft: makerSig, - orderRight, // passing Bundle as right order + orderRight, // passing ERC20 as right order signatureRight: takerSig, }, ]); + + expect(await ERC721Contract.ownerOf(1)).to.be.equal(takerAddress); expect(await ERC1155Contract.balanceOf(makerAddress, 1)).to.be.equal( - 10 + 40 ); - expect(await ERC721Contract.ownerOf(1)).to.be.equal(makerAddress); expect(await ERC1155Contract.balanceOf(takerAddress, 1)).to.be.equal( - 40 + 10 ); expect( await ExchangeContractAsUser.fills(hashKey(orderLeft)) - ).to.be.equal(1); + ).to.be.equal(10000000000); expect( await ExchangeContractAsUser.fills(hashKey(orderRight)) - ).to.be.equal(10000000000); + ).to.be.equal(1); - expect(await ERC20Contract.balanceOf(takerAddress)).to.be.equal( + expect(await ERC20Contract.balanceOf(makerAddress)).to.be.equal( 9650000000 // 10000000000 - protocolFee - royalty ); - expect(await ERC20Contract.balanceOf(makerAddress)).to.be.equal( - 20000000000 - ); - expect(await ERC20Contract2.balanceOf(makerAddress)).to.be.equal( - 20000000000 - ); - expect(await ERC20Contract2.balanceOf(takerAddress)).to.be.equal( + expect(await ERC20Contract.balanceOf(takerAddress)).to.be.equal( 20000000000 ); @@ -2087,7 +1923,7 @@ export function shouldMatchOrdersForBundle() { expect( await ERC20Contract.balanceOf(await defaultFeeReceiver.getAddress()) ).to.be.equal( - (Number(protocolFeeSecondary) * Number(makerAsset.value)) / 10000 + (Number(protocolFeeSecondary) * Number(takerAsset.value)) / 10000 ); // check maker received quads @@ -2104,22 +1940,20 @@ export function shouldMatchOrdersForBundle() { }; priceDistribution = { - erc20Prices: [3000000000], - erc721Prices: [[1000000000]], + erc721Prices: [[4000000000]], erc1155Prices: [[500000000]], quadPrices: [400000000, 600000000], }; // Create bundle for passing as right order bundleData = { - bundledERC20, bundledERC721, bundledERC1155, quads, priceDistribution, }; - takerAsset = await AssetBundle(bundleData, 1); + makerAsset = await AssetBundle(bundleData, 1); // configuring royalties for (let i = 0; i < 9; i++) { @@ -2144,19 +1978,19 @@ export function shouldMatchOrdersForBundle() { ); orderLeft = await OrderDefault( - maker, // ERC20 - makerAsset, + maker, + makerAsset, // Bundle ZeroAddress, - takerAsset, // Bundle + takerAsset, // ERC20 1, 0, 0 ); orderRight = await OrderDefault( taker, - takerAsset, // Bundle + takerAsset, // ERC20 ZeroAddress, - makerAsset, // ERC20 + makerAsset, // Bundle 1, 0, 0 @@ -2168,54 +2002,44 @@ export function shouldMatchOrdersForBundle() { const makerAddress = await maker.getAddress(); const takerAddress = await taker.getAddress(); - expect(await ERC20Contract.balanceOf(makerAddress)).to.be.equal( + expect(await ERC20Contract.balanceOf(makerAddress)).to.be.equal(0); + expect(await ERC20Contract.balanceOf(takerAddress)).to.be.equal( 30000000000 ); - expect(await ERC20Contract.balanceOf(takerAddress)).to.be.equal(0); - expect(await ERC20Contract2.balanceOf(makerAddress)).to.be.equal(0); - expect(await ERC20Contract2.balanceOf(takerAddress)).to.be.equal( - 40000000000 - ); - expect(await ERC721Contract.ownerOf(1)).to.be.equal(takerAddress); - expect(await ERC1155Contract.balanceOf(takerAddress, 1)).to.be.equal( + expect(await ERC721Contract.ownerOf(1)).to.be.equal(makerAddress); + expect(await ERC1155Contract.balanceOf(makerAddress, 1)).to.be.equal( 50 ); - expect(await ERC1155Contract.balanceOf(makerAddress, 1)).to.be.equal(0); + expect(await ERC1155Contract.balanceOf(takerAddress, 1)).to.be.equal(0); await ExchangeContractAsUser.matchOrders([ { - orderLeft, // passing ERC20 as left order + orderLeft, // passing Bundle as left order signatureLeft: makerSig, - orderRight, // passing Bundle as right order + orderRight, // passing ERC20 as right order signatureRight: takerSig, }, ]); + + expect(await ERC721Contract.ownerOf(1)).to.be.equal(takerAddress); expect(await ERC1155Contract.balanceOf(makerAddress, 1)).to.be.equal( - 10 + 40 ); - expect(await ERC721Contract.ownerOf(1)).to.be.equal(makerAddress); expect(await ERC1155Contract.balanceOf(takerAddress, 1)).to.be.equal( - 40 + 10 ); expect( await ExchangeContractAsUser.fills(hashKey(orderLeft)) - ).to.be.equal(1); + ).to.be.equal(10000000000); expect( await ExchangeContractAsUser.fills(hashKey(orderRight)) - ).to.be.equal(10000000000); - - expect(await ERC20Contract.balanceOf(takerAddress)).to.be.equal( - 9590000000 // 10000000000 - protocolFee - royalty - ); + ).to.be.equal(1); expect(await ERC20Contract.balanceOf(makerAddress)).to.be.equal( - 20000000000 - ); - expect(await ERC20Contract2.balanceOf(makerAddress)).to.be.equal( - 20000000000 + 9590000000 // 10000000000 - protocolFee - royalty ); - expect(await ERC20Contract2.balanceOf(takerAddress)).to.be.equal( + expect(await ERC20Contract.balanceOf(takerAddress)).to.be.equal( 20000000000 ); @@ -2231,7 +2055,7 @@ export function shouldMatchOrdersForBundle() { expect( await ERC20Contract.balanceOf(await defaultFeeReceiver.getAddress()) ).to.be.equal( - (Number(protocolFeeSecondary) * Number(makerAsset.value)) / 10000 + (Number(protocolFeeSecondary) * Number(takerAsset.value)) / 10000 ); // check maker received quads @@ -2248,22 +2072,20 @@ export function shouldMatchOrdersForBundle() { }; priceDistribution = { - erc20Prices: [3000000000], erc721Prices: [[1000000000]], erc1155Prices: [[500000000]], - quadPrices: [400000000, 600000000], + quadPrices: [1000000000, 3000000000], }; // Create bundle for passing as right order bundleData = { - bundledERC20, bundledERC721, bundledERC1155, quads, priceDistribution, }; - takerAsset = await AssetBundle(bundleData, 1); + makerAsset = await AssetBundle(bundleData, 1); // set up royalties by token for ERC721 token await RoyaltiesRegistryAsDeployer.setRoyaltiesByToken( @@ -2289,19 +2111,19 @@ export function shouldMatchOrdersForBundle() { ); orderLeft = await OrderDefault( - maker, // ERC20 - makerAsset, + maker, + makerAsset, // Bundle ZeroAddress, - takerAsset, // Bundle + takerAsset, // ERC20 1, 0, 0 ); orderRight = await OrderDefault( taker, - takerAsset, // Bundle + takerAsset, // ERC20 ZeroAddress, - makerAsset, // ERC20 + makerAsset, // Bundle 1, 0, 0 @@ -2313,54 +2135,44 @@ export function shouldMatchOrdersForBundle() { const makerAddress = await maker.getAddress(); const takerAddress = await taker.getAddress(); - expect(await ERC20Contract.balanceOf(makerAddress)).to.be.equal( + expect(await ERC20Contract.balanceOf(makerAddress)).to.be.equal(0); + expect(await ERC20Contract.balanceOf(takerAddress)).to.be.equal( 30000000000 ); - expect(await ERC20Contract.balanceOf(takerAddress)).to.be.equal(0); - expect(await ERC20Contract2.balanceOf(makerAddress)).to.be.equal(0); - expect(await ERC20Contract2.balanceOf(takerAddress)).to.be.equal( - 40000000000 - ); - expect(await ERC721Contract.ownerOf(1)).to.be.equal(takerAddress); - expect(await ERC1155Contract.balanceOf(takerAddress, 1)).to.be.equal( + expect(await ERC721Contract.ownerOf(1)).to.be.equal(makerAddress); + expect(await ERC1155Contract.balanceOf(makerAddress, 1)).to.be.equal( 50 ); - expect(await ERC1155Contract.balanceOf(makerAddress, 1)).to.be.equal(0); + expect(await ERC1155Contract.balanceOf(takerAddress, 1)).to.be.equal(0); await ExchangeContractAsUser.matchOrders([ { - orderLeft, // passing ERC20 as left order + orderLeft, // passing Bundle as left order signatureLeft: makerSig, - orderRight, // passing Bundle as right order + orderRight, // passing ERC20 as right order signatureRight: takerSig, }, ]); + + expect(await ERC721Contract.ownerOf(1)).to.be.equal(takerAddress); expect(await ERC1155Contract.balanceOf(makerAddress, 1)).to.be.equal( - 10 + 40 ); - expect(await ERC721Contract.ownerOf(1)).to.be.equal(makerAddress); expect(await ERC1155Contract.balanceOf(takerAddress, 1)).to.be.equal( - 40 + 10 ); expect( await ExchangeContractAsUser.fills(hashKey(orderLeft)) - ).to.be.equal(1); + ).to.be.equal(10000000000); expect( await ExchangeContractAsUser.fills(hashKey(orderRight)) - ).to.be.equal(10000000000); - - expect(await ERC20Contract.balanceOf(takerAddress)).to.be.equal( - 9500000000 // 10000000000 - protocolFee - royalty - ); + ).to.be.equal(1); expect(await ERC20Contract.balanceOf(makerAddress)).to.be.equal( - 20000000000 - ); - expect(await ERC20Contract2.balanceOf(makerAddress)).to.be.equal( - 20000000000 + 9200000000 // 10000000000 - protocolFee - royalty ); - expect(await ERC20Contract2.balanceOf(takerAddress)).to.be.equal( + expect(await ERC20Contract.balanceOf(takerAddress)).to.be.equal( 20000000000 ); @@ -2373,13 +2185,13 @@ export function shouldMatchOrdersForBundle() { ).to.be.equal(50000000); // 10% of asset price for ERC1155 token with id:1 expect( await ERC20Contract.balanceOf(royaltyReceiver3.getAddress()) - ).to.be.equal(100000000); // 10% of asset price for quad (3,0) & (0,3) + ).to.be.equal(400000000); // 10% of asset price for quad (3,0) & (0,3) // check protocol fee -> 250 * 10000000000 / 10000 = 250000000 expect( await ERC20Contract.balanceOf(await defaultFeeReceiver.getAddress()) ).to.be.equal( - (Number(protocolFeeSecondary) * Number(makerAsset.value)) / 10000 + (Number(protocolFeeSecondary) * Number(takerAsset.value)) / 10000 ); // check maker received quads diff --git a/packages/marketplace/test/utils/assets.ts b/packages/marketplace/test/utils/assets.ts index 85a6b733eb..12ece0ad7b 100644 --- a/packages/marketplace/test/utils/assets.ts +++ b/packages/marketplace/test/utils/assets.ts @@ -44,7 +44,6 @@ export type AssetType = { }; export type PriceDistribution = { - erc20Prices: Numeric[]; erc721Prices: Numeric[][]; erc1155Prices: Numeric[][]; quadPrices: Numeric[]; @@ -86,9 +85,6 @@ export const AssetERC20 = async ( baseValues.push(recipient); } - // console.log(baseParams); - // console.log(baseValues); - return { assetType: { assetClass: AssetClassType.ERC20_ASSET_CLASS, @@ -173,7 +169,7 @@ export const AssetBundle = async ( assetClass: AssetClassType.BUNDLE_ASSET_CLASS, data: AbiCoder.defaultAbiCoder().encode( [ - 'tuple(tuple(address erc20Address, uint256 value)[] bundledERC20, tuple(address erc721Address, uint256[] ids)[] bundledERC721, tuple(address erc1155Address, uint256[] ids, uint256[] supplies)[] bundledERC1155, tuple(uint256[] sizes, uint256[] xs, uint256[] ys, bytes data) quads, tuple(uint256[] erc20Prices, uint256[][] erc721Prices, uint256[][] erc1155Prices, uint256[] quadPrices) priceDistribution)', + 'tuple(tuple(address erc721Address, uint256[] ids)[] bundledERC721, tuple(address erc1155Address, uint256[] ids, uint256[] supplies)[] bundledERC1155, tuple(uint256[] sizes, uint256[] xs, uint256[] ys, bytes data) quads, tuple(uint256[][] erc721Prices, uint256[][] erc1155Prices, uint256[] quadPrices) priceDistribution)', ], [bundleInformation] ),