From e9d46e3e9b57dac0c2b31a643226f2eef02ca8bb Mon Sep 17 00:00:00 2001 From: Ayush Tiwari Date: Tue, 3 Oct 2023 13:53:05 +0530 Subject: [PATCH] feat: added _skipFees function --- .../contracts/exchange/Exchange.sol | 30 ++++++++++++++++++- .../contracts/mocks/SimpleTest.sol | 2 ++ .../transfer-manager/TransferManager.sol | 21 ++----------- .../test/exchange/Exchange.test.ts | 11 +++---- 4 files changed, 40 insertions(+), 24 deletions(-) diff --git a/packages/marketplace/contracts/exchange/Exchange.sol b/packages/marketplace/contracts/exchange/Exchange.sol index 411565a4b3..ce9a63598c 100644 --- a/packages/marketplace/contracts/exchange/Exchange.sol +++ b/packages/marketplace/contracts/exchange/Exchange.sol @@ -2,6 +2,8 @@ pragma solidity 0.8.21; +import {ERC165Upgradeable, IERC165Upgradeable} from "@openzeppelin/contracts-upgradeable/utils/introspection/ERC165Upgradeable.sol"; +import {AccessControlUpgradeable} from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol"; import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import {ContextUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol"; import {ERC2771HandlerUpgradeable} from "@sandbox-smart-contracts/dependency-metatx/contracts/ERC2771HandlerUpgradeable.sol"; @@ -15,7 +17,14 @@ import {ExchangeCore} from "./ExchangeCore.sol"; /// @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 Initializable, ExchangeCore, TransferManager, ERC2771HandlerUpgradeable { +contract Exchange is + Initializable, + ERC165Upgradeable, + AccessControlUpgradeable, + ExchangeCore, + TransferManager, + ERC2771HandlerUpgradeable +{ /// @notice role erc1776 trusted meta transaction contracts (Sand for example). /// @return hash for ERC1776_OPERATOR_ROLE bytes32 public constant ERC1776_OPERATOR_ROLE = keccak256("ERC1776_OPERATOR_ROLE"); @@ -24,6 +33,10 @@ contract Exchange is Initializable, ExchangeCore, TransferManager, ERC2771Handle /// @return hash for EXCHANGE_ADMIN_ROLE bytes32 public constant EXCHANGE_ADMIN_ROLE = keccak256("EXCHANGE_ADMIN_ROLE"); + /// @notice role to identify the sandbox accounts + /// @return hash for SKIP_FEES_ROLE + bytes32 public constant SKIP_FEES_ROLE = keccak256("SKIP_FEES_ROLE"); + /// @dev this protects the implementation contract from being initialized. /// @custom:oz-upgrades-unsafe-allow constructor constructor() { @@ -58,6 +71,7 @@ contract Exchange is Initializable, ExchangeCore, TransferManager, ERC2771Handle newRoyaltiesProvider ); __ExchangeCoreInitialize(orderValidatorAddress, newAssetMatcher); + __AccessControl_init(); _grantRole(DEFAULT_ADMIN_ROLE, admin); } @@ -125,6 +139,10 @@ contract Exchange is Initializable, ExchangeCore, TransferManager, ERC2771Handle _setDefaultFeeReceiver(newDefaultFeeReceiver); } + function _skipFees(address from) internal view override returns (bool) { + return !hasRole(SKIP_FEES_ROLE, from); + } + function _msgSender() internal view @@ -138,4 +156,14 @@ contract Exchange is Initializable, ExchangeCore, TransferManager, ERC2771Handle function _msgData() internal view override(ContextUpgradeable, ERC2771HandlerUpgradeable) returns (bytes calldata) { return ERC2771HandlerUpgradeable._msgData(); } + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface( + bytes4 interfaceId + ) public view virtual override(ERC165Upgradeable, AccessControlUpgradeable) returns (bool) { + return + ERC165Upgradeable.supportsInterface(interfaceId) || AccessControlUpgradeable.supportsInterface(interfaceId); + } } diff --git a/packages/marketplace/contracts/mocks/SimpleTest.sol b/packages/marketplace/contracts/mocks/SimpleTest.sol index bf58cfada1..7a51dbf6a1 100644 --- a/packages/marketplace/contracts/mocks/SimpleTest.sol +++ b/packages/marketplace/contracts/mocks/SimpleTest.sol @@ -10,4 +10,6 @@ contract SimpleTest is TransferManager, TransferExecutor { function getRoyaltiesByAssetTest(LibAsset.AssetType memory matchNft) external returns (LibPart.Part[] memory) { return getRoyaltiesByAssetType(matchNft); } + + function _skipFees(address from) internal virtual override returns (bool) {} } diff --git a/packages/marketplace/contracts/transfer-manager/TransferManager.sol b/packages/marketplace/contracts/transfer-manager/TransferManager.sol index e0312ef35e..ba2b19707b 100644 --- a/packages/marketplace/contracts/transfer-manager/TransferManager.sol +++ b/packages/marketplace/contracts/transfer-manager/TransferManager.sol @@ -3,7 +3,6 @@ pragma solidity 0.8.21; import {ERC165Upgradeable, IERC165Upgradeable} from "@openzeppelin/contracts-upgradeable/utils/introspection/ERC165Upgradeable.sol"; -import {AccessControlUpgradeable} from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol"; import {IRoyaltiesProvider} from "../interfaces/IRoyaltiesProvider.sol"; import {BpLibrary} from "../lib-bp/BpLibrary.sol"; import {IRoyaltyUGC} from "./interfaces/IRoyaltyUGC.sol"; @@ -15,15 +14,11 @@ import {LibPart} from "../lib-part/LibPart.sol"; /// @notice responsible for transferring all Assets /// @dev this manager supports different types of fees /// @dev also it supports different beneficiaries -abstract contract TransferManager is ERC165Upgradeable, AccessControlUpgradeable, ITransferManager { +abstract contract TransferManager is ERC165Upgradeable, ITransferManager { using BpLibrary for uint; bytes4 internal constant INTERFACE_ID_IROYALTYUGC = 0xa30b4db9; - /// @notice role to identify the sandbox accounts - /// @return hash for TSB_WALLET - bytes32 public constant TSB_WALLET = keccak256("TSB_WALLET"); - /// @notice fee for primary sales /// @return uint256 of primary sale fee uint256 public protocolFeePrimary; @@ -66,8 +61,6 @@ abstract contract TransferManager is ERC165Upgradeable, AccessControlUpgradeable IRoyaltiesProvider newRoyaltiesProvider ) internal onlyInitializing { __ERC165_init(); - __AccessControl_init(); - _grantRole(DEFAULT_ADMIN_ROLE, _msgSender()); _setProtocolFee(newProtocolFeePrimary, newProtocolFeeSecondary); _setRoyaltiesRegistry(newRoyaltiesProvider); _setDefaultFeeReceiver(newDefaultFeeReceiver); @@ -129,7 +122,7 @@ abstract contract TransferManager is ERC165Upgradeable, AccessControlUpgradeable function doTransfersWithFees(LibDeal.DealSide memory paymentSide, LibDeal.DealSide memory nftSide) internal { uint256 rest = paymentSide.asset.value; - if (!hasRole(TSB_WALLET, paymentSide.from)) { + if (_skipFees(paymentSide.from)) { rest = transferRoyalties( paymentSide.asset.assetType, nftSide.asset.assetType, @@ -323,15 +316,7 @@ abstract contract TransferManager is ERC165Upgradeable, AccessControlUpgradeable } } - /** - * @dev See {IERC165-supportsInterface}. - */ - function supportsInterface( - bytes4 interfaceId - ) public view virtual override(ERC165Upgradeable, AccessControlUpgradeable) returns (bool) { - return - ERC165Upgradeable.supportsInterface(interfaceId) || AccessControlUpgradeable.supportsInterface(interfaceId); - } + function _skipFees(address from) internal virtual returns (bool); uint256[46] private __gap; } diff --git a/packages/marketplace/test/exchange/Exchange.test.ts b/packages/marketplace/test/exchange/Exchange.test.ts index 1f7e7b923c..58776bb4d6 100644 --- a/packages/marketplace/test/exchange/Exchange.test.ts +++ b/packages/marketplace/test/exchange/Exchange.test.ts @@ -849,6 +849,7 @@ describe('Exchange.sol', function () { ERC721WithRoyaltyV2981, defaultFeeReceiver, deployer, + admin, user1: maker, user2: taker, } = await loadFixture(deployFixtures); @@ -865,11 +866,11 @@ describe('Exchange.sol', function () { // set up receiver await ERC721WithRoyaltyV2981.setRoyaltiesReceiver(1, deployer.address); - // grant TSB Wallet role to seller - const TSB_WALLET = - '0x1c3ffa8a78d1cdbeb9812a2ae7c540d20292531d0254f9ac1fa85e0ac44b9ad0'; // keccak256("TSB_WALLET") - await ExchangeContractAsDeployer.connect(deployer).grantRole( - TSB_WALLET, + // grant Skip Fees role to seller + const SKIP_FEES_ROLE = + '0x9c14d84aa0a4264a5c33560cb08e43e3ed227d0565fa3d19078d0f01304516eb'; // keccak256("SKIP_FEES_ROLE") + await ExchangeContractAsDeployer.connect(admin).grantRole( + SKIP_FEES_ROLE, taker.address );