Skip to content

Commit

Permalink
feat: added contracts from sandbox-marketplace-repo and modified depe…
Browse files Browse the repository at this point in the history
…ndencies
  • Loading branch information
capedcrusader21 committed Sep 11, 2023
1 parent ad4eeab commit ae66e6b
Show file tree
Hide file tree
Showing 103 changed files with 4,823 additions and 0 deletions.
14 changes: 14 additions & 0 deletions packages/marketplace/src/exchange/AssetMatcher.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#### Features

`matchAssets` function should calculate if Asset types match with each other.

Simple asset types match if they are equal, for example, ERC-20 token with address `address1` match to ERC-20 token with address `address1`, but doesn't match any ERC-721 token or ERC-20 token with `address2`.

There can be asset types which can't be compared to other asset types directly. For example, imagine Asset type `any Decentraland Land`. This asset type is not equal `Decentraland Land X` (with specific tokenId), but new `IAssetMatcher` (see [here](./IAssetMatcher.sol)) can be registered in this contract.

New registered `IAssetMatcher` will be responsible for matching `any Decentraland Land` with `Decentraland Land X`.

Assets match if
- it's a simple asset and it equals asset from the other side
- registered IAssetMatcher returns match
- otherwise assets match if asset classes match and their data matches (we calculate hash and compare hashes)
101 changes: 101 additions & 0 deletions packages/marketplace/src/exchange/AssetMatcher.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
// SPDX-License-Identifier: MIT

pragma solidity 0.8.19;

import {IAssetMatcher} from "../interfaces/IAssetMatcher.sol";
import {LibAsset} from "../lib-asset/LibAsset.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";

/// @title AssetMatcher contract
/// @notice matchAssets function should calculate if Asset types match with each other
contract AssetMatcher is Ownable, IAssetMatcher {
bytes internal constant EMPTY = "";
mapping(bytes4 => address) internal matchers;

/// @notice event emitted when an AssetMacher is set
/// @param assetType represented by bytes4
/// @param matcher address of the matcher
event MatcherChange(bytes4 indexed assetType, address indexed matcher);

/// @notice set AssetMacher
/// @param assetType to be matched by the matcher contract
/// @param matcher address of the matcher
function setAssetMatcher(bytes4 assetType, address matcher) external onlyOwner {
matchers[assetType] = matcher;
emit MatcherChange(assetType, matcher);
}

/// @notice calculate if Asset types match with each other
/// @param leftAssetType to be matched with rightAssetType
/// @param rightAssetType to be matched with leftAssetType
/// @return AssetType of the match
function matchAssets(
LibAsset.AssetType memory leftAssetType,
LibAsset.AssetType memory rightAssetType
) external view returns (LibAsset.AssetType memory) {
LibAsset.AssetType memory result = matchAssetOneSide(leftAssetType, rightAssetType);
if (result.assetClass == 0) {
return matchAssetOneSide(rightAssetType, leftAssetType);
} else {
return result;
}
}

function matchAssetOneSide(
LibAsset.AssetType memory leftAssetType,
LibAsset.AssetType memory rightAssetType
) private view returns (LibAsset.AssetType memory) {
bytes4 classLeft = leftAssetType.assetClass;
bytes4 classRight = rightAssetType.assetClass;
if (classLeft == LibAsset.ETH_ASSET_CLASS) {
if (classRight == LibAsset.ETH_ASSET_CLASS) {
return leftAssetType;
}
return LibAsset.AssetType(0, EMPTY);
}
if (classLeft == LibAsset.ERC20_ASSET_CLASS) {
if (classRight == LibAsset.ERC20_ASSET_CLASS) {
return simpleMatch(leftAssetType, rightAssetType);
}
return LibAsset.AssetType(0, EMPTY);
}
if (classLeft == LibAsset.ERC721_ASSET_CLASS) {
if (classRight == LibAsset.ERC721_ASSET_CLASS) {
return simpleMatch(leftAssetType, rightAssetType);
}
return LibAsset.AssetType(0, EMPTY);
}
if (classLeft == LibAsset.ERC1155_ASSET_CLASS) {
if (classRight == LibAsset.ERC1155_ASSET_CLASS) {
return simpleMatch(leftAssetType, rightAssetType);
}
return LibAsset.AssetType(0, EMPTY);
}
if (classLeft == LibAsset.BUNDLE) {
if (classRight == LibAsset.BUNDLE) {
return simpleMatch(leftAssetType, rightAssetType);
}
return LibAsset.AssetType(0, EMPTY);
}
address matcher = matchers[classLeft];
if (matcher != address(0)) {
return IAssetMatcher(matcher).matchAssets(leftAssetType, rightAssetType);
}
if (classLeft == classRight) {
return simpleMatch(leftAssetType, rightAssetType);
}
revert("not found IAssetMatcher");
}

function simpleMatch(
LibAsset.AssetType memory leftAssetType,
LibAsset.AssetType memory rightAssetType
) private pure returns (LibAsset.AssetType memory) {
bytes32 leftHash = keccak256(leftAssetType.data);
bytes32 rightHash = keccak256(rightAssetType.data);
if (leftHash == rightHash) {
return leftAssetType;
}
return LibAsset.AssetType(0, EMPTY);
}
}
39 changes: 39 additions & 0 deletions packages/marketplace/src/exchange/Exchange.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// SPDX-License-Identifier: MIT

pragma solidity 0.8.19;

import {ExchangeCore} from "./ExchangeCore.sol";
import {TransferManager, IRoyaltiesProvider} from "../transfer-manager/TransferManager.sol";

/// @title Exchange contract
/// @notice Used to exchange assets, that is, tokens.
/// @dev Main functions are in ExchangeCore
/// @dev TransferManager is used to execute token transfers
contract Exchange is ExchangeCore, TransferManager {
/// @notice Exchange contract initializer
/// @param newProtocolFeePrimary protocol fee applied for primary markets
/// @param newProtocolFeeSecondary protocol fee applied for secondary markets
/// @param newDefaultFeeReceiver market fee receiver
/// @param newRoyaltiesProvider registry for the different types of royalties
/// @param orderValidatorAdress address of the OrderValidator contract, that validates orders
/// @param newNativeOrder bool to indicate of the contract accepts or doesn't native tokens, i.e. ETH or Matic
/// @param newMetaNative same as =nativeOrder but for metaTransactions
function __Exchange_init(
uint256 newProtocolFeePrimary,
uint256 newProtocolFeeSecondary,
address newDefaultFeeReceiver,
IRoyaltiesProvider newRoyaltiesProvider,
address orderValidatorAdress,
bool newNativeOrder,
bool newMetaNative
) external initializer {
__Ownable_init();
__ExchangeCoreInitialize(newNativeOrder, newMetaNative, orderValidatorAdress);
__TransferManager_init_unchained(
newProtocolFeePrimary,
newProtocolFeeSecondary,
newDefaultFeeReceiver,
newRoyaltiesProvider
);
}
}
28 changes: 28 additions & 0 deletions packages/marketplace/src/exchange/ExchangeCore.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#### Features

The file contains a list of widely used functions: `cancel`, `matchOrders`, `directPurchase`, `directAcceptBid`.

##### Algorithm `cancel(Order order)`

Two main requirements for function are:
- If msg sender is `order.maker`,
- Order.salt not equal to 0.

`Order` hash is calculated using [EIP-712](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md). Value equal to max uint256 value is set to map `fills` with key == `Order` hash.

##### Algorithm `matchOrders(Order orderLeft, bytes signatureLeft, Order orderRight, bytes signatureRight)`

Orders are being validated by `validateOrders()` internal function, if error is find, function being reverted.

Next step is `matchAssets` function, should calculate if Asset types match with each other.

Next step is parsing `Order.data`. After that function `setFillEmitMatch()` calculates fills for the matched orders and set them in "fills" mapping. Finally `doTransfers()` function is called.

##### Algorithm `directPurchase(Purchase direct)` or `directAcceptBid(AcceptBid direct)`

We recommend use `directPurchase` and `directAcceptBid` methods for reducing the gas consumption. Data from the structures `Purchase` and `AcceptBid` form purchase and sell Orders. Orders are being validated by `validateOrders()` internal function. Further Orders serve as parameters of the function `matchAndTransfer()`.

##### Contract relationship

For better understanding how contracts interconnect and what functions are used, see picture:
![Relationship1](documents/diagram-13983673345763902680.png)
Loading

0 comments on commit ae66e6b

Please sign in to comment.