github.com/diadata-org/diadata@v1.4.593/config/nftContracts/looksrare/contract.sol (about) 1 // SPDX-License-Identifier: MIT 2 pragma solidity ^0.8.0; 3 4 // OpenZeppelin contracts 5 import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; 6 import {ReentrancyGuard} from "@openzeppelin/contracts/security/ReentrancyGuard.sol"; 7 import {IERC20, SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; 8 9 // LooksRare interfaces 10 import {ICurrencyManager} from "./interfaces/ICurrencyManager.sol"; 11 import {IExecutionManager} from "./interfaces/IExecutionManager.sol"; 12 import {IExecutionStrategy} from "./interfaces/IExecutionStrategy.sol"; 13 import {IRoyaltyFeeManager} from "./interfaces/IRoyaltyFeeManager.sol"; 14 import {ILooksRareExchange} from "./interfaces/ILooksRareExchange.sol"; 15 import {ITransferManagerNFT} from "./interfaces/ITransferManagerNFT.sol"; 16 import {ITransferSelectorNFT} from "./interfaces/ITransferSelectorNFT.sol"; 17 import {IWETH} from "./interfaces/IWETH.sol"; 18 19 // LooksRare libraries 20 import {OrderTypes} from "./libraries/OrderTypes.sol"; 21 import {SignatureChecker} from "./libraries/SignatureChecker.sol"; 22 23 /** 24 * @title LooksRareExchange 25 * @notice It is the core contract of the LooksRare exchange. 26 LOOKSRARELOOKSRARELOOKSRLOOKSRARELOOKSRARELOOKSRARELOOKSRARELOOKSRLOOKSRARELOOKSRARELOOKSR 27 LOOKSRARELOOKSRARELOOKSRAR'''''''''''''''''''''''''''''''''''OOKSRLOOKSRARELOOKSRARELOOKSR 28 LOOKSRARELOOKSRARELOOKS:. .;OOKSRARELOOKSRARELOOKSR 29 LOOKSRARELOOKSRARELOO,. .,KSRARELOOKSRARELOOKSR 30 LOOKSRARELOOKSRAREL' ..',;:LOOKS::;,'.. 'RARELOOKSRARELOOKSR 31 LOOKSRARELOOKSRAR. .,:LOOKSRARELOOKSRARELO:,. .RELOOKSRARELOOKSR 32 LOOKSRARELOOKS:. .;RARELOOKSRARELOOKSRARELOOKSl;. .:OOKSRARELOOKSR 33 LOOKSRARELOO;. .'OKSRARELOOKSRARELOOKSRARELOOKSRARE'. .;KSRARELOOKSR 34 LOOKSRAREL,. .,LOOKSRARELOOK:;;:"""":;;;lELOOKSRARELO,. .,RARELOOKSR 35 LOOKSRAR. .;okLOOKSRAREx:. .;OOKSRARELOOK;. .RELOOKSR 36 LOOKS:. .:dOOOLOOKSRARE' .''''.. .OKSRARELOOKSR:. .LOOKSR 37 LOx;. .cKSRARELOOKSRAR' 'LOOKSRAR' .KSRARELOOKSRARc.. .OKSR 38 L;. .cxOKSRARELOOKSRAR. .LOOKS.RARE' ;kRARELOOKSRARExc. .;R 39 LO' .;oOKSRARELOOKSRAl. .LOOKS.RARE. :kRARELOOKSRAREo;. 'SR 40 LOOK;. .,KSRARELOOKSRAx, .;LOOKSR;. .oSRARELOOKSRAo,. .;OKSR 41 LOOKSk:. .'RARELOOKSRARd;. .... 'oOOOOOOOOOOxc'. .:LOOKSR 42 LOOKSRARc. .:dLOOKSRAREko;. .,lxOOOOOOOOOd:. .ARELOOKSR 43 LOOKSRARELo' .;oOKSRARELOOxoc;,....,;:ldkOOOOOOOOkd;. 'SRARELOOKSR 44 LOOKSRARELOOd,. .,lSRARELOOKSRARELOOKSRARELOOKSRkl,. .,OKSRARELOOKSR 45 LOOKSRARELOOKSx;. ..;oxELOOKSRARELOOKSRARELOkxl:.. .:LOOKSRARELOOKSR 46 LOOKSRARELOOKSRARc. .':cOKSRARELOOKSRALOc;'. .ARELOOKSRARELOOKSR 47 LOOKSRARELOOKSRARELl' ...'',,,,''... 'SRARELOOKSRARELOOKSR 48 LOOKSRARELOOKSRARELOOo,. .,OKSRARELOOKSRARELOOKSR 49 LOOKSRARELOOKSRARELOOKSx;. .;xOOKSRARELOOKSRARELOOKSR 50 LOOKSRARELOOKSRARELOOKSRLO:. .:SRLOOKSRARELOOKSRARELOOKSR 51 LOOKSRARELOOKSRARELOOKSRLOOKl. .lOKSRLOOKSRARELOOKSRARELOOKSR 52 LOOKSRARELOOKSRARELOOKSRLOOKSRo'. .'oLOOKSRLOOKSRARELOOKSRARELOOKSR 53 LOOKSRARELOOKSRARELOOKSRLOOKSRARd;. .;xRELOOKSRLOOKSRARELOOKSRARELOOKSR 54 LOOKSRARELOOKSRARELOOKSRLOOKSRARELO:. .:kRARELOOKSRLOOKSRARELOOKSRARELOOKSR 55 LOOKSRARELOOKSRARELOOKSRLOOKSRARELOOKl. .cOKSRARELOOKSRLOOKSRARELOOKSRARELOOKSR 56 LOOKSRARELOOKSRARELOOKSRLOOKSRARELOOKSRo' 'oLOOKSRARELOOKSRLOOKSRARELOOKSRARELOOKSR 57 LOOKSRARELOOKSRARELOOKSRLOOKSRARELOOKSRARE,. .,dRELOOKSRARELOOKSRLOOKSRARELOOKSRARELOOKSR 58 LOOKSRARELOOKSRARELOOKSRLOOKSRARELOOKSRARELOOKSRARELOOKSRARELOOKSRLOOKSRARELOOKSRARELOOKSR 59 */ 60 contract LooksRareExchange is ILooksRareExchange, ReentrancyGuard, Ownable { 61 using SafeERC20 for IERC20; 62 63 using OrderTypes for OrderTypes.MakerOrder; 64 using OrderTypes for OrderTypes.TakerOrder; 65 66 address public immutable WETH; 67 bytes32 public immutable DOMAIN_SEPARATOR; 68 69 address public protocolFeeRecipient; 70 71 ICurrencyManager public currencyManager; 72 IExecutionManager public executionManager; 73 IRoyaltyFeeManager public royaltyFeeManager; 74 ITransferSelectorNFT public transferSelectorNFT; 75 76 mapping(address => uint256) public userMinOrderNonce; 77 mapping(address => mapping(uint256 => bool)) private _isUserOrderNonceExecutedOrCancelled; 78 79 event CancelAllOrders(address indexed user, uint256 newMinNonce); 80 event CancelMultipleOrders(address indexed user, uint256[] orderNonces); 81 event NewCurrencyManager(address indexed currencyManager); 82 event NewExecutionManager(address indexed executionManager); 83 event NewProtocolFeeRecipient(address indexed protocolFeeRecipient); 84 event NewRoyaltyFeeManager(address indexed royaltyFeeManager); 85 event NewTransferSelectorNFT(address indexed transferSelectorNFT); 86 87 event RoyaltyPayment( 88 address indexed collection, 89 uint256 indexed tokenId, 90 address indexed royaltyRecipient, 91 address currency, 92 uint256 amount 93 ); 94 95 event TakerAsk( 96 bytes32 orderHash, // bid hash of the maker order 97 uint256 orderNonce, // user order nonce 98 address indexed taker, // sender address for the taker ask order 99 address indexed maker, // maker address of the initial bid order 100 address indexed strategy, // strategy that defines the execution 101 address currency, // currency address 102 address collection, // collection address 103 uint256 tokenId, // tokenId transferred 104 uint256 amount, // amount of tokens transferred 105 uint256 price // final transacted price 106 ); 107 108 event TakerBid( 109 bytes32 orderHash, // ask hash of the maker order 110 uint256 orderNonce, // user order nonce 111 address indexed taker, // sender address for the taker bid order 112 address indexed maker, // maker address of the initial ask order 113 address indexed strategy, // strategy that defines the execution 114 address currency, // currency address 115 address collection, // collection address 116 uint256 tokenId, // tokenId transferred 117 uint256 amount, // amount of tokens transferred 118 uint256 price // final transacted price 119 ); 120 121 /** 122 * @notice Constructor 123 * @param _currencyManager currency manager address 124 * @param _executionManager execution manager address 125 * @param _royaltyFeeManager royalty fee manager address 126 * @param _WETH wrapped ether address (for other chains, use wrapped native asset) 127 * @param _protocolFeeRecipient protocol fee recipient 128 */ 129 constructor( 130 address _currencyManager, 131 address _executionManager, 132 address _royaltyFeeManager, 133 address _WETH, 134 address _protocolFeeRecipient 135 ) { 136 // Calculate the domain separator 137 DOMAIN_SEPARATOR = keccak256( 138 abi.encode( 139 0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f, // keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)") 140 0xda9101ba92939daf4bb2e18cd5f942363b9297fbc3232c9dd964abb1fb70ed71, // keccak256("LooksRareExchange") 141 0xc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6, // keccak256(bytes("1")) for versionId = 1 142 block.chainid, 143 address(this) 144 ) 145 ); 146 147 currencyManager = ICurrencyManager(_currencyManager); 148 executionManager = IExecutionManager(_executionManager); 149 royaltyFeeManager = IRoyaltyFeeManager(_royaltyFeeManager); 150 WETH = _WETH; 151 protocolFeeRecipient = _protocolFeeRecipient; 152 } 153 154 /** 155 * @notice Cancel all pending orders for a sender 156 * @param minNonce minimum user nonce 157 */ 158 function cancelAllOrdersForSender(uint256 minNonce) external { 159 require(minNonce > userMinOrderNonce[msg.sender], "Cancel: Order nonce lower than current"); 160 require(minNonce < userMinOrderNonce[msg.sender] + 500000, "Cancel: Cannot cancel more orders"); 161 userMinOrderNonce[msg.sender] = minNonce; 162 163 emit CancelAllOrders(msg.sender, minNonce); 164 } 165 166 /** 167 * @notice Cancel maker orders 168 * @param orderNonces array of order nonces 169 */ 170 function cancelMultipleMakerOrders(uint256[] calldata orderNonces) external { 171 require(orderNonces.length > 0, "Cancel: Cannot be empty"); 172 173 for (uint256 i = 0; i < orderNonces.length; i++) { 174 require(orderNonces[i] >= userMinOrderNonce[msg.sender], "Cancel: Order nonce lower than current"); 175 _isUserOrderNonceExecutedOrCancelled[msg.sender][orderNonces[i]] = true; 176 } 177 178 emit CancelMultipleOrders(msg.sender, orderNonces); 179 } 180 181 /** 182 * @notice Match ask with a taker bid order using ETH 183 * @param takerBid taker bid order 184 * @param makerAsk maker ask order 185 */ 186 function matchAskWithTakerBidUsingETHAndWETH( 187 OrderTypes.TakerOrder calldata takerBid, 188 OrderTypes.MakerOrder calldata makerAsk 189 ) external payable override nonReentrant { 190 require((makerAsk.isOrderAsk) && (!takerBid.isOrderAsk), "Order: Wrong sides"); 191 require(makerAsk.currency == WETH, "Order: Currency must be WETH"); 192 require(msg.sender == takerBid.taker, "Order: Taker must be the sender"); 193 194 // If not enough ETH to cover the price, use WETH 195 if (takerBid.price > msg.value) { 196 IERC20(WETH).safeTransferFrom(msg.sender, address(this), (takerBid.price - msg.value)); 197 } else { 198 require(takerBid.price == msg.value, "Order: Msg.value too high"); 199 } 200 201 // Wrap ETH sent to this contract 202 IWETH(WETH).deposit{value: msg.value}(); 203 204 // Check the maker ask order 205 bytes32 askHash = makerAsk.hash(); 206 _validateOrder(makerAsk, askHash); 207 208 // Retrieve execution parameters 209 (bool isExecutionValid, uint256 tokenId, uint256 amount) = IExecutionStrategy(makerAsk.strategy) 210 .canExecuteTakerBid(takerBid, makerAsk); 211 212 require(isExecutionValid, "Strategy: Execution invalid"); 213 214 // Update maker ask order status to true (prevents replay) 215 _isUserOrderNonceExecutedOrCancelled[makerAsk.signer][makerAsk.nonce] = true; 216 217 // Execution part 1/2 218 _transferFeesAndFundsWithWETH( 219 makerAsk.strategy, 220 makerAsk.collection, 221 tokenId, 222 makerAsk.signer, 223 takerBid.price, 224 makerAsk.minPercentageToAsk 225 ); 226 227 // Execution part 2/2 228 _transferNonFungibleToken(makerAsk.collection, makerAsk.signer, takerBid.taker, tokenId, amount); 229 230 emit TakerBid( 231 askHash, 232 makerAsk.nonce, 233 takerBid.taker, 234 makerAsk.signer, 235 makerAsk.strategy, 236 makerAsk.currency, 237 makerAsk.collection, 238 tokenId, 239 amount, 240 takerBid.price 241 ); 242 } 243 244 /** 245 * @notice Match a takerBid with a matchAsk 246 * @param takerBid taker bid order 247 * @param makerAsk maker ask order 248 */ 249 function matchAskWithTakerBid(OrderTypes.TakerOrder calldata takerBid, OrderTypes.MakerOrder calldata makerAsk) 250 external 251 override 252 nonReentrant 253 { 254 require((makerAsk.isOrderAsk) && (!takerBid.isOrderAsk), "Order: Wrong sides"); 255 require(msg.sender == takerBid.taker, "Order: Taker must be the sender"); 256 257 // Check the maker ask order 258 bytes32 askHash = makerAsk.hash(); 259 _validateOrder(makerAsk, askHash); 260 261 (bool isExecutionValid, uint256 tokenId, uint256 amount) = IExecutionStrategy(makerAsk.strategy) 262 .canExecuteTakerBid(takerBid, makerAsk); 263 264 require(isExecutionValid, "Strategy: Execution invalid"); 265 266 // Update maker ask order status to true (prevents replay) 267 _isUserOrderNonceExecutedOrCancelled[makerAsk.signer][makerAsk.nonce] = true; 268 269 // Execution part 1/2 270 _transferFeesAndFunds( 271 makerAsk.strategy, 272 makerAsk.collection, 273 tokenId, 274 makerAsk.currency, 275 msg.sender, 276 makerAsk.signer, 277 takerBid.price, 278 makerAsk.minPercentageToAsk 279 ); 280 281 // Execution part 2/2 282 _transferNonFungibleToken(makerAsk.collection, makerAsk.signer, takerBid.taker, tokenId, amount); 283 284 emit TakerBid( 285 askHash, 286 makerAsk.nonce, 287 takerBid.taker, 288 makerAsk.signer, 289 makerAsk.strategy, 290 makerAsk.currency, 291 makerAsk.collection, 292 tokenId, 293 amount, 294 takerBid.price 295 ); 296 } 297 298 /** 299 * @notice Match a takerAsk with a makerBid 300 * @param takerAsk taker ask order 301 * @param makerBid maker bid order 302 */ 303 function matchBidWithTakerAsk(OrderTypes.TakerOrder calldata takerAsk, OrderTypes.MakerOrder calldata makerBid) 304 external 305 override 306 nonReentrant 307 { 308 require((!makerBid.isOrderAsk) && (takerAsk.isOrderAsk), "Order: Wrong sides"); 309 require(msg.sender == takerAsk.taker, "Order: Taker must be the sender"); 310 311 // Check the maker bid order 312 bytes32 bidHash = makerBid.hash(); 313 _validateOrder(makerBid, bidHash); 314 315 (bool isExecutionValid, uint256 tokenId, uint256 amount) = IExecutionStrategy(makerBid.strategy) 316 .canExecuteTakerAsk(takerAsk, makerBid); 317 318 require(isExecutionValid, "Strategy: Execution invalid"); 319 320 // Update maker bid order status to true (prevents replay) 321 _isUserOrderNonceExecutedOrCancelled[makerBid.signer][makerBid.nonce] = true; 322 323 // Execution part 1/2 324 _transferNonFungibleToken(makerBid.collection, msg.sender, makerBid.signer, tokenId, amount); 325 326 // Execution part 2/2 327 _transferFeesAndFunds( 328 makerBid.strategy, 329 makerBid.collection, 330 tokenId, 331 makerBid.currency, 332 makerBid.signer, 333 takerAsk.taker, 334 takerAsk.price, 335 takerAsk.minPercentageToAsk 336 ); 337 338 emit TakerAsk( 339 bidHash, 340 makerBid.nonce, 341 takerAsk.taker, 342 makerBid.signer, 343 makerBid.strategy, 344 makerBid.currency, 345 makerBid.collection, 346 tokenId, 347 amount, 348 takerAsk.price 349 ); 350 } 351 352 /** 353 * @notice Update currency manager 354 * @param _currencyManager new currency manager address 355 */ 356 function updateCurrencyManager(address _currencyManager) external onlyOwner { 357 require(_currencyManager != address(0), "Owner: Cannot be null address"); 358 currencyManager = ICurrencyManager(_currencyManager); 359 emit NewCurrencyManager(_currencyManager); 360 } 361 362 /** 363 * @notice Update execution manager 364 * @param _executionManager new execution manager address 365 */ 366 function updateExecutionManager(address _executionManager) external onlyOwner { 367 require(_executionManager != address(0), "Owner: Cannot be null address"); 368 executionManager = IExecutionManager(_executionManager); 369 emit NewExecutionManager(_executionManager); 370 } 371 372 /** 373 * @notice Update protocol fee and recipient 374 * @param _protocolFeeRecipient new recipient for protocol fees 375 */ 376 function updateProtocolFeeRecipient(address _protocolFeeRecipient) external onlyOwner { 377 protocolFeeRecipient = _protocolFeeRecipient; 378 emit NewProtocolFeeRecipient(_protocolFeeRecipient); 379 } 380 381 /** 382 * @notice Update royalty fee manager 383 * @param _royaltyFeeManager new fee manager address 384 */ 385 function updateRoyaltyFeeManager(address _royaltyFeeManager) external onlyOwner { 386 require(_royaltyFeeManager != address(0), "Owner: Cannot be null address"); 387 royaltyFeeManager = IRoyaltyFeeManager(_royaltyFeeManager); 388 emit NewRoyaltyFeeManager(_royaltyFeeManager); 389 } 390 391 /** 392 * @notice Update transfer selector NFT 393 * @param _transferSelectorNFT new transfer selector address 394 */ 395 function updateTransferSelectorNFT(address _transferSelectorNFT) external onlyOwner { 396 require(_transferSelectorNFT != address(0), "Owner: Cannot be null address"); 397 transferSelectorNFT = ITransferSelectorNFT(_transferSelectorNFT); 398 399 emit NewTransferSelectorNFT(_transferSelectorNFT); 400 } 401 402 /** 403 * @notice Check whether user order nonce is executed or cancelled 404 * @param user address of user 405 * @param orderNonce nonce of the order 406 */ 407 function isUserOrderNonceExecutedOrCancelled(address user, uint256 orderNonce) external view returns (bool) { 408 return _isUserOrderNonceExecutedOrCancelled[user][orderNonce]; 409 } 410 411 /** 412 * @notice Transfer fees and funds to royalty recipient, protocol, and seller 413 * @param strategy address of the execution strategy 414 * @param collection non fungible token address for the transfer 415 * @param tokenId tokenId 416 * @param currency currency being used for the purchase (e.g., WETH/USDC) 417 * @param from sender of the funds 418 * @param to seller's recipient 419 * @param amount amount being transferred (in currency) 420 * @param minPercentageToAsk minimum percentage of the gross amount that goes to ask 421 */ 422 function _transferFeesAndFunds( 423 address strategy, 424 address collection, 425 uint256 tokenId, 426 address currency, 427 address from, 428 address to, 429 uint256 amount, 430 uint256 minPercentageToAsk 431 ) internal { 432 // Initialize the final amount that is transferred to seller 433 uint256 finalSellerAmount = amount; 434 435 // 1. Protocol fee 436 { 437 uint256 protocolFeeAmount = _calculateProtocolFee(strategy, amount); 438 439 // Check if the protocol fee is different than 0 for this strategy 440 if ((protocolFeeRecipient != address(0)) && (protocolFeeAmount != 0)) { 441 IERC20(currency).safeTransferFrom(from, protocolFeeRecipient, protocolFeeAmount); 442 finalSellerAmount -= protocolFeeAmount; 443 } 444 } 445 446 // 2. Royalty fee 447 { 448 (address royaltyFeeRecipient, uint256 royaltyFeeAmount) = royaltyFeeManager 449 .calculateRoyaltyFeeAndGetRecipient(collection, tokenId, amount); 450 451 // Check if there is a royalty fee and that it is different to 0 452 if ((royaltyFeeRecipient != address(0)) && (royaltyFeeAmount != 0)) { 453 IERC20(currency).safeTransferFrom(from, royaltyFeeRecipient, royaltyFeeAmount); 454 finalSellerAmount -= royaltyFeeAmount; 455 456 emit RoyaltyPayment(collection, tokenId, royaltyFeeRecipient, currency, royaltyFeeAmount); 457 } 458 } 459 460 require((finalSellerAmount * 10000) >= (minPercentageToAsk * amount), "Fees: Higher than expected"); 461 462 // 3. Transfer final amount (post-fees) to seller 463 { 464 IERC20(currency).safeTransferFrom(from, to, finalSellerAmount); 465 } 466 } 467 468 /** 469 * @notice Transfer fees and funds to royalty recipient, protocol, and seller 470 * @param strategy address of the execution strategy 471 * @param collection non fungible token address for the transfer 472 * @param tokenId tokenId 473 * @param to seller's recipient 474 * @param amount amount being transferred (in currency) 475 * @param minPercentageToAsk minimum percentage of the gross amount that goes to ask 476 */ 477 function _transferFeesAndFundsWithWETH( 478 address strategy, 479 address collection, 480 uint256 tokenId, 481 address to, 482 uint256 amount, 483 uint256 minPercentageToAsk 484 ) internal { 485 // Initialize the final amount that is transferred to seller 486 uint256 finalSellerAmount = amount; 487 488 // 1. Protocol fee 489 { 490 uint256 protocolFeeAmount = _calculateProtocolFee(strategy, amount); 491 492 // Check if the protocol fee is different than 0 for this strategy 493 if ((protocolFeeRecipient != address(0)) && (protocolFeeAmount != 0)) { 494 IERC20(WETH).safeTransfer(protocolFeeRecipient, protocolFeeAmount); 495 finalSellerAmount -= protocolFeeAmount; 496 } 497 } 498 499 // 2. Royalty fee 500 { 501 (address royaltyFeeRecipient, uint256 royaltyFeeAmount) = royaltyFeeManager 502 .calculateRoyaltyFeeAndGetRecipient(collection, tokenId, amount); 503 504 // Check if there is a royalty fee and that it is different to 0 505 if ((royaltyFeeRecipient != address(0)) && (royaltyFeeAmount != 0)) { 506 IERC20(WETH).safeTransfer(royaltyFeeRecipient, royaltyFeeAmount); 507 finalSellerAmount -= royaltyFeeAmount; 508 509 emit RoyaltyPayment(collection, tokenId, royaltyFeeRecipient, address(WETH), royaltyFeeAmount); 510 } 511 } 512 513 require((finalSellerAmount * 10000) >= (minPercentageToAsk * amount), "Fees: Higher than expected"); 514 515 // 3. Transfer final amount (post-fees) to seller 516 { 517 IERC20(WETH).safeTransfer(to, finalSellerAmount); 518 } 519 } 520 521 /** 522 * @notice Transfer NFT 523 * @param collection address of the token collection 524 * @param from address of the sender 525 * @param to address of the recipient 526 * @param tokenId tokenId 527 * @param amount amount of tokens (1 for ERC721, 1+ for ERC1155) 528 * @dev For ERC721, amount is not used 529 */ 530 function _transferNonFungibleToken( 531 address collection, 532 address from, 533 address to, 534 uint256 tokenId, 535 uint256 amount 536 ) internal { 537 // Retrieve the transfer manager address 538 address transferManager = transferSelectorNFT.checkTransferManagerForToken(collection); 539 540 // If no transfer manager found, it returns address(0) 541 require(transferManager != address(0), "Transfer: No NFT transfer manager available"); 542 543 // If one is found, transfer the token 544 ITransferManagerNFT(transferManager).transferNonFungibleToken(collection, from, to, tokenId, amount); 545 } 546 547 /** 548 * @notice Calculate protocol fee for an execution strategy 549 * @param executionStrategy strategy 550 * @param amount amount to transfer 551 */ 552 function _calculateProtocolFee(address executionStrategy, uint256 amount) internal view returns (uint256) { 553 uint256 protocolFee = IExecutionStrategy(executionStrategy).viewProtocolFee(); 554 return (protocolFee * amount) / 10000; 555 } 556 557 /** 558 * @notice Verify the validity of the maker order 559 * @param makerOrder maker order 560 * @param orderHash computed hash for the order 561 */ 562 function _validateOrder(OrderTypes.MakerOrder calldata makerOrder, bytes32 orderHash) internal view { 563 // Verify whether order nonce has expired 564 require( 565 (!_isUserOrderNonceExecutedOrCancelled[makerOrder.signer][makerOrder.nonce]) && 566 (makerOrder.nonce >= userMinOrderNonce[makerOrder.signer]), 567 "Order: Matching order expired" 568 ); 569 570 // Verify the signer is not address(0) 571 require(makerOrder.signer != address(0), "Order: Invalid signer"); 572 573 // Verify the amount is not 0 574 require(makerOrder.amount > 0, "Order: Amount cannot be 0"); 575 576 // Verify the validity of the signature 577 require( 578 SignatureChecker.verify( 579 orderHash, 580 makerOrder.signer, 581 makerOrder.v, 582 makerOrder.r, 583 makerOrder.s, 584 DOMAIN_SEPARATOR 585 ), 586 "Signature: Invalid" 587 ); 588 589 // Verify whether the currency is whitelisted 590 require(currencyManager.isCurrencyWhitelisted(makerOrder.currency), "Currency: Not whitelisted"); 591 592 // Verify whether strategy can be executed 593 require(executionManager.isStrategyWhitelisted(makerOrder.strategy), "Strategy: Not whitelisted"); 594 } 595 }