From 5d23368b885377bb113576f572c9631ec7b04dca Mon Sep 17 00:00:00 2001 From: Ayush Tiwari Date: Fri, 12 Jul 2024 19:54:19 +0530 Subject: [PATCH] feat: added Bundle price distribution --- .../marketplace/contracts/ExchangeCore.sol | 14 +++- .../marketplace/contracts/TransferManager.sol | 71 +++++++++++++++++-- .../contracts/libraries/LibAsset.sol | 42 +++++++++++ 3 files changed, 119 insertions(+), 8 deletions(-) diff --git a/packages/marketplace/contracts/ExchangeCore.sol b/packages/marketplace/contracts/ExchangeCore.sol index af0d853035..10d6784ba0 100644 --- a/packages/marketplace/contracts/ExchangeCore.sol +++ b/packages/marketplace/contracts/ExchangeCore.sol @@ -173,16 +173,26 @@ abstract contract ExchangeCore is Initializable, ITransferManager { orderRight.makeAsset.assetType ); + // Check if the order is a bundle and validate the bundle price + if (makeMatch.assetClass == LibAsset.AssetClass.BUNDLE) { + uint256 bundlePrice = orderRight.makeAsset.value; // colllective price provided by buyer + LibAsset.Bundle memory bundle = LibAsset.decodeBundle(makeMatch); + require( + bundlePrice == LibAsset.computeBundlePrice(bundle, orderLeft.makeAsset.bundlePriceDistribution), + "Bundle price mismatch" + ); + } + LibOrder.FillResult memory newFill = _parseOrdersSetFillEmitMatch(sender, orderLeft, orderRight); doTransfers( ITransferManager.DealSide( - LibAsset.Asset(makeMatch, newFill.leftValue), + LibAsset.Asset(makeMatch, newFill.leftValue, orderLeft.makeAsset.bundlePriceDistribution), orderLeft.maker, orderLeft.makeRecipient ), ITransferManager.DealSide( - LibAsset.Asset(takeMatch, newFill.rightValue), + LibAsset.Asset(takeMatch, newFill.rightValue, orderRight.makeAsset.bundlePriceDistribution), orderRight.maker, orderRight.makeRecipient ), diff --git a/packages/marketplace/contracts/TransferManager.sol b/packages/marketplace/contracts/TransferManager.sol index 6d1beead08..fe6d2ec363 100644 --- a/packages/marketplace/contracts/TransferManager.sol +++ b/packages/marketplace/contracts/TransferManager.sol @@ -177,7 +177,11 @@ abstract contract TransferManager is Initializable, ITransferManager { remainder = _transferPercentage(remainder, paymentSide, defaultFeeReceiver, fees, PROTOCOL_FEE_MULTIPLIER); } if (remainder > 0) { - _transfer(LibAsset.Asset(paymentSide.asset.assetType, remainder), paymentSide.account, nftSide.recipient); + _transfer( + LibAsset.Asset(paymentSide.asset.assetType, remainder, paymentSide.asset.bundlePriceDistribution), + paymentSide.account, + nftSide.recipient + ); } } @@ -199,14 +203,65 @@ abstract contract TransferManager is Initializable, ITransferManager { DealSide memory paymentSide, DealSide memory nftSide ) internal returns (uint256) { - (address token, uint256 tokenId) = LibAsset.decodeToken(nftSide.asset.assetType); - IRoyaltiesProvider.Part[] memory royalties = royaltiesRegistry.getRoyalties(token, tokenId); + // code to decode for bundle: done + // for bundle royalty is calc for loop // for a same creator club royalties + // royalties are getting fetched + // decode royalties + //trasfer royalties + if (paymentSide.asset.assetType.assetClass == LibAsset.AssetClass.BUNDLE) { + LibAsset.Bundle memory bundle = LibAsset.decodeBundle(nftSide.asset.assetType); + + uint256 erc721Length = bundle.bundledERC721.length; + uint256 erc1155Length = bundle.bundledERC1155.length; + uint256 quadsLength = bundle.quads.xs.length; + + for (uint256 i; i < erc721Length; i++) { + address token = bundle.bundledERC721[i].erc721Address; + uint256 idLength = bundle.bundledERC721[i].ids.length; + for (uint256 j; j < idLength; j++) { + uint256 tokenId = bundle.bundledERC721[i].ids[j]; + IRoyaltiesProvider.Part[] memory royalties = royaltiesRegistry.getRoyalties(token, tokenId); + remainder = _applyRoyalties(remainder, paymentSide, royalties, nftSide.recipient); + } + } + + for (uint256 i; i < erc1155Length; i++) { + address token = bundle.bundledERC1155[i].erc1155Address; + uint256 idLength = bundle.bundledERC1155[i].ids.length; + require(idLength == bundle.bundledERC1155[i].supplies.length, "ERC1155 array error"); + for (uint256 j; j < idLength; j++) { + uint256 tokenId = bundle.bundledERC1155[i].ids[j]; + uint256 supply = bundle.bundledERC1155[i].supplies[j]; + IRoyaltiesProvider.Part[] memory royalties = royaltiesRegistry.getRoyalties(token, tokenId); + remainder = _applyRoyalties(remainder, paymentSide, royalties, nftSide.recipient); + } + } + + if (quadsLength > 0) { + address landTokenAddress = address(landContract); + + // TODO: fetch tokenId and call _applyRoyalties + } + } else { + (address token, uint256 tokenId) = LibAsset.decodeToken(nftSide.asset.assetType); + IRoyaltiesProvider.Part[] memory royalties = royaltiesRegistry.getRoyalties(token, tokenId); + remainder = _applyRoyalties(remainder, paymentSide, royalties, nftSide.recipient); + } + return remainder; + } + + function _applyRoyalties( + uint256 remainder, + DealSide memory paymentSide, + IRoyaltiesProvider.Part[] memory royalties, + address recipient + ) internal returns (uint256) { uint256 totalRoyalties; uint256 len = royalties.length; for (uint256 i; i < len; i++) { IRoyaltiesProvider.Part memory r = royalties[i]; - totalRoyalties = totalRoyalties + r.basisPoints; - if (r.account == nftSide.recipient) { + totalRoyalties += r.basisPoints; + if (r.account == recipient) { // We just skip the transfer because the nftSide will get the full payment anyway. continue; } @@ -230,7 +285,11 @@ abstract contract TransferManager is Initializable, ITransferManager { uint256 percentage, uint256 multiplier ) internal returns (uint256) { - LibAsset.Asset memory payment = LibAsset.Asset(paymentSide.asset.assetType, 0); + LibAsset.Asset memory payment = LibAsset.Asset( + paymentSide.asset.assetType, + 0, + paymentSide.asset.bundlePriceDistribution + ); uint256 fee = (paymentSide.asset.value * percentage) / multiplier; if (remainder > fee) { remainder = remainder - fee; diff --git a/packages/marketplace/contracts/libraries/LibAsset.sol b/packages/marketplace/contracts/libraries/LibAsset.sol index 2fce456acc..0d8ab45c08 100644 --- a/packages/marketplace/contracts/libraries/LibAsset.sol +++ b/packages/marketplace/contracts/libraries/LibAsset.sol @@ -34,6 +34,7 @@ library LibAsset { struct Asset { AssetType assetType; // The type of the asset. uint256 value; // The amount or value of the asset. + BundlePriceDistribution bundlePriceDistribution; // The price distribution for individual assets in bundle. } /// @dev Represents a group (i.e. bundle) of ERC20 assets on the Ethereum blockchain. @@ -71,6 +72,14 @@ library LibAsset { Quads quads; } + /// @dev Represents the price of each asset in a bundle. + struct BundlePriceDistribution { + uint256[] erc20Prices; + uint256[][] erc721Prices; + uint256[][] erc1155Prices; + uint256 quadPrice; + } + bytes32 internal constant ASSET_TYPE_TYPEHASH = keccak256("AssetType(uint256 assetClass,bytes data)"); bytes32 internal constant ASSET_TYPEHASH = @@ -147,4 +156,37 @@ library LibAsset { function decodeBundle(AssetType memory assetType) internal pure returns (Bundle memory) { return abi.decode(assetType.data, (Bundle)); } + + /// @dev function to compute the total of individual prices in bundle. + /// @param bundle The bundle. + /// @param bundlePriceDistribution The bundle price details. + /// @return The total price of the bundle. + function computeBundlePrice( + Bundle memory bundle, + BundlePriceDistribution memory bundlePriceDistribution + ) internal pure returns (uint256) { + uint256 totalPrice = 0; + + // total price of all bundled ERC20 assets + for (uint256 i = 0; i < bundlePriceDistribution.erc20Prices.length; i++) { + totalPrice += bundlePriceDistribution.erc20Prices[i]; + } + + // calculate the total price of all bundled ERC721 assets + for (uint256 i = 0; i < bundlePriceDistribution.erc721Prices.length; i++) { + for (uint256 j = 0; j < bundlePriceDistribution.erc721Prices[i].length; j++) + totalPrice += bundlePriceDistribution.erc721Prices[i][j]; + } + + // calculate the total price of all bundled ERC1155 assets + for (uint256 i = 0; i < bundlePriceDistribution.erc1155Prices.length; i++) { + for (uint256 j = 0; j < bundlePriceDistribution.erc1155Prices[i].length; j++) { + totalPrice += bundle.bundledERC1155[i].supplies[j] * bundlePriceDistribution.erc1155Prices[i][j]; + } + } + + totalPrice += bundlePriceDistribution.quadPrice; + + return totalPrice; + } }