diff --git a/packages/deploy/deploy/marketplace/03_deploy_asset_matcher.ts b/packages/deploy/deploy/marketplace/03_deploy_asset_matcher.ts deleted file mode 100644 index 12c6fae7f4..0000000000 --- a/packages/deploy/deploy/marketplace/03_deploy_asset_matcher.ts +++ /dev/null @@ -1,18 +0,0 @@ -import {HardhatRuntimeEnvironment} from 'hardhat/types'; -import {DeployFunction} from 'hardhat-deploy/types'; - -const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { - const {deployments, getNamedAccounts} = hre; - const {deploy} = deployments; - const {deployer} = await getNamedAccounts(); - - await deploy('AssetMatcher', { - from: deployer, - contract: - '@sandbox-smart-contracts/marketplace/contracts/exchange/AssetMatcher.sol:AssetMatcher', - log: true, - skipIfAlreadyDeployed: true, - }); -}; -export default func; -func.tags = ['AssetMatcher', 'AssetMatcher_deploy']; diff --git a/packages/deploy/deploy/marketplace/10_deploy_exchange.ts b/packages/deploy/deploy/marketplace/10_deploy_exchange.ts index 7b18a0943f..0cf865cca9 100644 --- a/packages/deploy/deploy/marketplace/10_deploy_exchange.ts +++ b/packages/deploy/deploy/marketplace/10_deploy_exchange.ts @@ -17,7 +17,6 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { } const orderValidator = await deployments.get('OrderValidator'); const royaltiesRegistry = await deployments.get('RoyaltiesRegistry'); - const assetMatcher = await deployments.get('AssetMatcher'); const newProtocolFeePrimary = 0; const newProtocolFeeSecondary = 250; @@ -38,7 +37,6 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { exchangeFeeRecipient, royaltiesRegistry.address, orderValidator.address, - assetMatcher.address, ], }, upgradeIndex: 0, @@ -49,8 +47,4 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { }; export default func; func.tags = ['Exchange', 'Exchange_deploy']; -func.dependencies = [ - 'RoyaltiesRegistry_deploy', - 'OrderValidator_deploy', - 'AssetMatcher_deploy', -]; +func.dependencies = ['RoyaltiesRegistry_deploy', 'OrderValidator_deploy']; diff --git a/packages/deploy/hardhat.config.ts b/packages/deploy/hardhat.config.ts index d3a3c64e31..cb378f2cc8 100644 --- a/packages/deploy/hardhat.config.ts +++ b/packages/deploy/hardhat.config.ts @@ -13,7 +13,6 @@ const importedPackages = { 'contracts/royalties-registry/RoyaltiesRegistry.sol', 'contracts/exchange/OrderValidator.sol', 'contracts/exchange/Exchange.sol', - 'contracts/exchange/AssetMatcher.sol', ], }; diff --git a/packages/marketplace/contracts/exchange/AssetMatcher.md b/packages/marketplace/contracts/exchange/AssetMatcher.md deleted file mode 100644 index 01898dec50..0000000000 --- a/packages/marketplace/contracts/exchange/AssetMatcher.md +++ /dev/null @@ -1,14 +0,0 @@ -#### 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) \ No newline at end of file diff --git a/packages/marketplace/contracts/exchange/AssetMatcher.sol b/packages/marketplace/contracts/exchange/AssetMatcher.sol deleted file mode 100644 index 247834e6e1..0000000000 --- a/packages/marketplace/contracts/exchange/AssetMatcher.sol +++ /dev/null @@ -1,41 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity 0.8.21; - -import {IAssetMatcher, LibAsset} from "../interfaces/IAssetMatcher.sol"; - -/// @title AssetMatcher contract -/// @notice matchAssets function should calculate if Asset types match with each other -contract AssetMatcher is IAssetMatcher { - bytes internal constant EMPTY = ""; - - /// @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 pure returns (LibAsset.AssetType memory) { - LibAsset.AssetClassType classLeft = leftAssetType.assetClass; - LibAsset.AssetClassType classRight = rightAssetType.assetClass; - require(classLeft != LibAsset.AssetClassType.INVALID_ASSET_CLASS, "not found IAssetMatcher"); - require(classRight != LibAsset.AssetClassType.INVALID_ASSET_CLASS, "not found IAssetMatcher"); - if (classLeft == classRight) { - return simpleMatch(leftAssetType, rightAssetType); - } - return LibAsset.AssetType(LibAsset.AssetClassType.INVALID_ASSET_CLASS, EMPTY); - } - - 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(LibAsset.AssetClassType.INVALID_ASSET_CLASS, EMPTY); - } -} diff --git a/packages/marketplace/contracts/exchange/Exchange.sol b/packages/marketplace/contracts/exchange/Exchange.sol index d7a3531e11..95cc48bc8c 100644 --- a/packages/marketplace/contracts/exchange/Exchange.sol +++ b/packages/marketplace/contracts/exchange/Exchange.sol @@ -9,7 +9,6 @@ import {ContextUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/Cont import {ERC165Upgradeable} from "@openzeppelin/contracts-upgradeable/utils/introspection/ERC165Upgradeable.sol"; import {ERC2771HandlerUpgradeable} from "@sandbox-smart-contracts/dependency-metatx/contracts/ERC2771HandlerUpgradeable.sol"; import {IOrderValidator} from "../interfaces/IOrderValidator.sol"; -import {IAssetMatcher} from "../interfaces/IAssetMatcher.sol"; import {TransferManager, IRoyaltiesProvider} from "../transfer-manager/TransferManager.sol"; import {LibOrder} from "../lib-order/LibOrder.sol"; import {ExchangeCore} from "./ExchangeCore.sol"; @@ -52,7 +51,6 @@ contract Exchange is /// @param newDefaultFeeReceiver market fee receiver /// @param newRoyaltiesProvider registry for the different types of royalties /// @param orderValidatorAddress new OrderValidator contract address - /// @param newAssetMatcher new AssetMatcher contract address // solhint-disable-next-line func-name-mixedcase function __Exchange_init( address admin, @@ -61,8 +59,7 @@ contract Exchange is uint256 newProtocolFeeSecondary, address newDefaultFeeReceiver, IRoyaltiesProvider newRoyaltiesProvider, - IOrderValidator orderValidatorAddress, - IAssetMatcher newAssetMatcher + IOrderValidator orderValidatorAddress ) external initializer { __ERC2771Handler_init_unchained(newTrustedForwarder); __AccessControl_init_unchained(); @@ -73,7 +70,7 @@ contract Exchange is newDefaultFeeReceiver, newRoyaltiesProvider ); - __ExchangeCoreInitialize(orderValidatorAddress, newAssetMatcher); + __ExchangeCoreInitialize(orderValidatorAddress); _grantRole(DEFAULT_ADMIN_ROLE, admin); } @@ -109,12 +106,6 @@ contract Exchange is _setRoyaltiesRegistry(newRoyaltiesRegistry); } - /// @notice set AssetMatcher address - /// @param contractAddress new AssetMatcher contract address - function setAssetMatcherContract(IAssetMatcher contractAddress) external onlyRole(DEFAULT_ADMIN_ROLE) { - _setAssetMatcherContract(contractAddress); - } - /// @notice set OrderValidator address /// @param contractAddress new OrderValidator contract address function setOrderValidatorContract(IOrderValidator contractAddress) external onlyRole(DEFAULT_ADMIN_ROLE) { diff --git a/packages/marketplace/contracts/exchange/ExchangeCore.sol b/packages/marketplace/contracts/exchange/ExchangeCore.sol index 210f322163..1e1f4b37bc 100644 --- a/packages/marketplace/contracts/exchange/ExchangeCore.sol +++ b/packages/marketplace/contracts/exchange/ExchangeCore.sol @@ -4,7 +4,6 @@ pragma solidity 0.8.21; import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import {LibFill} from "./libraries/LibFill.sol"; -import {IAssetMatcher} from "../interfaces/IAssetMatcher.sol"; import {TransferExecutor} from "../transfer-manager/TransferExecutor.sol"; import {LibAsset} from "../lib-asset/LibAsset.sol"; import {LibOrder} from "../lib-order/LibOrder.sol"; @@ -24,10 +23,6 @@ abstract contract ExchangeCore is Initializable, TransferExecutor, ITransferMana bytes signatureRight; // signature for the right order } - /// @notice AssetMatcher contract - /// @return AssetMatcher address - IAssetMatcher public assetMatcher; - /// @notice OrderValidator contract /// @return OrderValidator address IOrderValidator public orderValidator; @@ -60,29 +55,14 @@ abstract contract ExchangeCore is Initializable, TransferExecutor, ITransferMana uint256 valueLeft, uint256 valueRight ); - event AssetMatcherSet(IAssetMatcher indexed contractAddress); event OrderValidatorSet(IOrderValidator indexed contractAddress); /// @notice initializer for ExchangeCore /// @param newOrderValidatorAddress new OrderValidator contract address - /// @param newAssetMatcher new AssetMatcher contract address /// @dev initialize permissions for native token exchange // solhint-disable-next-line func-name-mixedcase - function __ExchangeCoreInitialize( - IOrderValidator newOrderValidatorAddress, - IAssetMatcher newAssetMatcher - ) internal onlyInitializing { + function __ExchangeCoreInitialize(IOrderValidator newOrderValidatorAddress) internal onlyInitializing { _setOrderValidatorContract(newOrderValidatorAddress); - _setAssetMatcherContract(newAssetMatcher); - } - - /// @notice set AssetMatcher address - /// @param contractAddress new AssetMatcher contract address - /// @dev matches assets between left and right order - function _setAssetMatcherContract(IAssetMatcher contractAddress) internal { - require(address(contractAddress) != address(0), "invalid asset matcher"); - assetMatcher = contractAddress; - emit AssetMatcherSet(contractAddress); } /// @notice set OrderValidator address @@ -152,12 +132,17 @@ abstract contract ExchangeCore is Initializable, TransferExecutor, ITransferMana LibOrder.Order calldata orderLeft, LibOrder.Order calldata orderRight ) internal { - (LibAsset.AssetType memory makeMatch, LibAsset.AssetType memory takeMatch) = _matchAssets( - orderLeft, - orderRight + LibAsset.AssetType memory makeMatch = LibAsset.matchAssets( + orderLeft.makeAsset.assetType, + orderRight.takeAsset.assetType + ); + LibAsset.AssetType memory takeMatch = LibAsset.matchAssets( + orderLeft.takeAsset.assetType, + orderRight.makeAsset.assetType ); LibFill.FillResult memory newFill = _parseOrdersSetFillEmitMatch(sender, orderLeft, orderRight); + doTransfers( ITransferManager.DealSide({ asset: LibAsset.Asset({assetType: makeMatch, value: newFill.leftValue}), @@ -234,19 +219,5 @@ abstract contract ExchangeCore is Initializable, TransferExecutor, ITransferMana } } - /// @notice match assets from orders - /// @param orderLeft left order - /// @param orderRight right order - /// @dev each make asset must correrspond to the other take asset and be different from 0 - function _matchAssets( - LibOrder.Order memory orderLeft, - LibOrder.Order memory orderRight - ) internal view returns (LibAsset.AssetType memory makeMatch, LibAsset.AssetType memory takeMatch) { - makeMatch = assetMatcher.matchAssets(orderLeft.makeAsset.assetType, orderRight.takeAsset.assetType); - require(makeMatch.assetClass != LibAsset.AssetClassType.INVALID_ASSET_CLASS, "assets don't match"); - takeMatch = assetMatcher.matchAssets(orderLeft.takeAsset.assetType, orderRight.makeAsset.assetType); - require(takeMatch.assetClass != LibAsset.AssetClassType.INVALID_ASSET_CLASS, "assets don't match"); - } - uint256[49] private __gap; } diff --git a/packages/marketplace/contracts/lib-asset/LibAsset.sol b/packages/marketplace/contracts/lib-asset/LibAsset.sol index 7866b2fc81..35c4156109 100644 --- a/packages/marketplace/contracts/lib-asset/LibAsset.sol +++ b/packages/marketplace/contracts/lib-asset/LibAsset.sol @@ -49,6 +49,28 @@ library LibAsset { return FeeSide.NONE; } + /// @notice calculate if Asset types match with each other + /// @param leftType to be matched with rightAssetType + /// @param rightType to be matched with leftAssetType + /// @return AssetType of the match + function matchAssets( + AssetType calldata leftType, + AssetType calldata rightType + ) internal pure returns (AssetType memory) { + AssetClassType classLeft = leftType.assetClass; + AssetClassType classRight = rightType.assetClass; + + require(classLeft != AssetClassType.INVALID_ASSET_CLASS, "not found IAssetMatcher"); + require(classRight != AssetClassType.INVALID_ASSET_CLASS, "not found IAssetMatcher"); + require(classLeft == classRight, "assets don't match"); + + bytes32 leftHash = keccak256(leftType.data); + bytes32 rightHash = keccak256(rightType.data); + require(leftHash == rightHash, "assets don't match"); + + return leftType; + } + /// @notice calculate hash of asset type /// @param assetType to be hashed /// @return hash of assetType @@ -56,9 +78,9 @@ library LibAsset { return keccak256(abi.encode(ASSET_TYPE_TYPEHASH, assetType.assetClass, keccak256(assetType.data))); } - /// @notice calculate hash of asset - /// @param asset to be hashed - /// @return hash of asset + /// @notice calculate hash of asset + /// @param asset to be hashed + /// @return hash of asset function hash(Asset memory asset) internal pure returns (bytes32) { return keccak256(abi.encode(ASSET_TYPEHASH, hash(asset.assetType), asset.value)); } diff --git a/packages/marketplace/contracts/mocks/LibAssetTest.sol b/packages/marketplace/contracts/mocks/LibAssetTest.sol new file mode 100644 index 0000000000..ac64c13a79 --- /dev/null +++ b/packages/marketplace/contracts/mocks/LibAssetTest.sol @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.21; + +import {LibAsset} from "../lib-asset/LibAsset.sol"; + +contract LibAssetTest { + function getFeeSide( + LibAsset.AssetClassType leftClass, + LibAsset.AssetClassType rightClass + ) external pure returns (LibAsset.FeeSide) { + return LibAsset.getFeeSide(leftClass, rightClass); + } + + /// @notice calculate if Asset types match with each other + /// @param leftType to be matched with rightAssetType + /// @param rightType to be matched with leftAssetType + /// @return AssetType of the match + function matchAssets( + LibAsset.AssetType calldata leftType, + LibAsset.AssetType calldata rightType + ) external pure returns (LibAsset.AssetType memory) { + return LibAsset.matchAssets(leftType, rightType); + } + + /// @notice calculate hash of asset type + /// @param assetType to be hashed + /// @return hash of assetType + function hash(LibAsset.AssetType memory assetType) external pure returns (bytes32) { + return LibAsset.hash(assetType); + } + + /// @notice calculate hash of asset + /// @param asset to be hashed + /// @return hash of asset + function hash(LibAsset.Asset memory asset) external pure returns (bytes32) { + return LibAsset.hash(asset); + } +} diff --git a/packages/marketplace/test/exchange/AssetMatcher.test.ts b/packages/marketplace/test/exchange/AssetMatcher.test.ts index c159fce4fd..3fd391dfe8 100644 --- a/packages/marketplace/test/exchange/AssetMatcher.test.ts +++ b/packages/marketplace/test/exchange/AssetMatcher.test.ts @@ -1,11 +1,24 @@ -import {deployFixtures} from '../fixtures'; +import {deployLibAssetTest} from '../fixtures'; import {loadFixture} from '@nomicfoundation/hardhat-network-helpers'; import {expect} from 'chai'; import {AssetClassType} from '../utils/assets'; +import {ethers} from 'hardhat'; + +async function deployLibAssetTest() { + const [deployer, user] = await ethers.getSigners(); + const LibAssetTest = await ethers.getContractFactory('LibAssetTest'); + const libAssetTest = await LibAssetTest.deploy(); + const assetMatcherAsUser = libAssetTest.connect(user); + return { + deployer, + user, + assetMatcherAsUser, + }; +} describe('AssetMatcher.sol', function () { it('should revert matchAsset call if asset class is invalid', async function () { - const {assetMatcherAsUser} = await loadFixture(deployFixtures); + const {assetMatcherAsUser} = await loadFixture(deployLibAssetTest); const leftAssetType = { assetClass: AssetClassType.INVALID_ASSET_CLASS, @@ -25,7 +38,7 @@ describe('AssetMatcher.sol', function () { }); it('should call return the expected AssetType', async function () { - const {assetMatcherAsUser} = await loadFixture(deployFixtures); + const {assetMatcherAsUser} = await loadFixture(deployLibAssetTest); const leftAssetType = { assetClass: AssetClassType.ERC721_ASSET_CLASS, @@ -44,8 +57,8 @@ describe('AssetMatcher.sol', function () { expect(result[1]).to.be.equal(leftAssetType.data); }); - it('should return null when data does not match', async function () { - const {assetMatcherAsUser} = await loadFixture(deployFixtures); + it('should revert when asset class does not match', async function () { + const {assetMatcherAsUser} = await loadFixture(deployLibAssetTest); const leftAssetType = { assetClass: AssetClassType.ERC721_ASSET_CLASS, @@ -53,18 +66,27 @@ describe('AssetMatcher.sol', function () { }; const rightAssetType = { + assetClass: AssetClassType.ERC20_ASSET_CLASS, + data: '0x1234', + }; + await expect( + assetMatcherAsUser.matchAssets(leftAssetType, rightAssetType) + ).to.revertedWith("assets don't match"); + }); + it('should revert when data does not match', async function () { + const {assetMatcherAsUser} = await loadFixture(deployLibAssetTest); + + const leftAssetType = { assetClass: AssetClassType.ERC721_ASSET_CLASS, - data: '0x1254', + data: '0x1234', }; - const nullAsetType = { - assetClass: AssetClassType.INVALID_ASSET_CLASS, - data: '0x', + + const rightAssetType = { + assetClass: AssetClassType.ERC721_ASSET_CLASS, + data: '0xFFFF', }; - const result = await assetMatcherAsUser.matchAssets( - leftAssetType, - rightAssetType - ); - expect(result[0]).to.be.equal(nullAsetType.assetClass); - expect(result[1]).to.be.equal(nullAsetType.data); + await expect( + assetMatcherAsUser.matchAssets(leftAssetType, rightAssetType) + ).to.revertedWith("assets don't match"); }); }); diff --git a/packages/marketplace/test/exchange/ExchangeSettings.test.ts b/packages/marketplace/test/exchange/ExchangeSettings.test.ts index 92c1cd143e..e3e44714a5 100644 --- a/packages/marketplace/test/exchange/ExchangeSettings.test.ts +++ b/packages/marketplace/test/exchange/ExchangeSettings.test.ts @@ -11,7 +11,6 @@ describe('Exchange.sol settings', function () { protocolFeeSecondary, ExchangeContractAsAdmin, RoyaltiesRegistryAsDeployer, - assetMatcherAsUser, OrderValidatorAsAdmin, TrustedForwarder, defaultFeeReceiver, @@ -20,9 +19,6 @@ describe('Exchange.sol settings', function () { expect(await ExchangeContractAsAdmin.royaltiesRegistry()).to.be.equal( await RoyaltiesRegistryAsDeployer.getAddress() ); - expect(await ExchangeContractAsAdmin.assetMatcher()).to.be.equal( - await assetMatcherAsUser.getAddress() - ); expect(await ExchangeContractAsAdmin.orderValidator()).to.be.equal( await OrderValidatorAsAdmin.getAddress() ); @@ -42,7 +38,6 @@ describe('Exchange.sol settings', function () { describe('roles', function () { describe('default admin', function () { checkPermsForDefaultAdmin('setRoyaltiesRegistry', 'RoyaltiesRegistrySet'); - checkPermsForDefaultAdmin('setAssetMatcherContract', 'AssetMatcherSet'); checkPermsForDefaultAdmin( 'setOrderValidatorContract', 'OrderValidatorSet' @@ -171,10 +166,6 @@ describe('Exchange.sol settings', function () { 'setRoyaltiesRegistry', 'invalid Royalties Registry' ); - shouldNotBeAbleToSetAsZero( - 'setAssetMatcherContract', - 'invalid asset matcher' - ); shouldNotBeAbleToSetAsZero( 'setOrderValidatorContract', 'invalid order validator' diff --git a/packages/marketplace/test/fixtures.ts b/packages/marketplace/test/fixtures.ts index 58c540e6ac..5ccd2b2cc1 100644 --- a/packages/marketplace/test/fixtures.ts +++ b/packages/marketplace/test/fixtures.ts @@ -6,9 +6,6 @@ async function deploy() { const [deployer, admin, user, defaultFeeReceiver, user1, user2] = await ethers.getSigners(); - const AssetMatcher = await ethers.getContractFactory('AssetMatcher'); - const assetMatcherAsDeployer = await AssetMatcher.deploy(); - const assetMatcherAsUser = await assetMatcherAsDeployer.connect(user); const TrustedForwarderFactory = await ethers.getContractFactory( 'TrustedForwarderMock' ); @@ -53,7 +50,6 @@ async function deploy() { defaultFeeReceiver.address, await RoyaltiesRegistryAsDeployer.getAddress(), await OrderValidatorAsAdmin.getAddress(), - await assetMatcherAsDeployer.getAddress(), ], { initializer: '__Exchange_init', @@ -120,8 +116,6 @@ async function deploy() { EXCHANGE_ADMIN_ROLE, DEFAULT_ADMIN_ROLE, PAUSER_ROLE, - assetMatcherAsDeployer, - assetMatcherAsUser, ExchangeContractAsDeployer, ExchangeContractAsAdmin, ExchangeContractAsUser,