Skip to content

Commit

Permalink
feat: added Bundle price distribution
Browse files Browse the repository at this point in the history
  • Loading branch information
capedcrusader21 committed Jul 12, 2024
1 parent f069820 commit 5d23368
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 8 deletions.
14 changes: 12 additions & 2 deletions packages/marketplace/contracts/ExchangeCore.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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
),
Expand Down
71 changes: 65 additions & 6 deletions packages/marketplace/contracts/TransferManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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
);
}
}

Expand All @@ -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;
}
Expand All @@ -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;
Expand Down
42 changes: 42 additions & 0 deletions packages/marketplace/contracts/libraries/LibAsset.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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 =
Expand Down Expand Up @@ -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;
}
}

0 comments on commit 5d23368

Please sign in to comment.