github.com/diadata-org/diadata@v1.4.593/config/nftContracts/opensea/contract.sol (about) 1 /** 2 *Submitted for verification at Etherscan.io on 2018-06-12 3 */ 4 5 pragma solidity ^0.4.13; 6 7 library SafeMath { 8 9 /** 10 * @dev Multiplies two numbers, throws on overflow. 11 */ 12 function mul(uint256 a, uint256 b) internal pure returns (uint256 c) { 13 if (a == 0) { 14 return 0; 15 } 16 c = a * b; 17 assert(c / a == b); 18 return c; 19 } 20 21 /** 22 * @dev Integer division of two numbers, truncating the quotient. 23 */ 24 function div(uint256 a, uint256 b) internal pure returns (uint256) { 25 // assert(b > 0); // Solidity automatically throws when dividing by 0 26 // uint256 c = a / b; 27 // assert(a == b * c + a % b); // There is no case in which this doesn't hold 28 return a / b; 29 } 30 31 /** 32 * @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend). 33 */ 34 function sub(uint256 a, uint256 b) internal pure returns (uint256) { 35 assert(b <= a); 36 return a - b; 37 } 38 39 /** 40 * @dev Adds two numbers, throws on overflow. 41 */ 42 function add(uint256 a, uint256 b) internal pure returns (uint256 c) { 43 c = a + b; 44 assert(c >= a); 45 return c; 46 } 47 } 48 49 contract Ownable { 50 address public owner; 51 52 53 event OwnershipRenounced(address indexed previousOwner); 54 event OwnershipTransferred( 55 address indexed previousOwner, 56 address indexed newOwner 57 ); 58 59 60 /** 61 * @dev The Ownable constructor sets the original `owner` of the contract to the sender 62 * account. 63 */ 64 constructor() public { 65 owner = msg.sender; 66 } 67 68 /** 69 * @dev Throws if called by any account other than the owner. 70 */ 71 modifier onlyOwner() { 72 require(msg.sender == owner); 73 _; 74 } 75 76 /** 77 * @dev Allows the current owner to transfer control of the contract to a newOwner. 78 * @param newOwner The address to transfer ownership to. 79 */ 80 function transferOwnership(address newOwner) public onlyOwner { 81 require(newOwner != address(0)); 82 emit OwnershipTransferred(owner, newOwner); 83 owner = newOwner; 84 } 85 86 /** 87 * @dev Allows the current owner to relinquish control of the contract. 88 */ 89 function renounceOwnership() public onlyOwner { 90 emit OwnershipRenounced(owner); 91 owner = address(0); 92 } 93 } 94 95 contract ERC20Basic { 96 function totalSupply() public view returns (uint256); 97 function balanceOf(address who) public view returns (uint256); 98 function transfer(address to, uint256 value) public returns (bool); 99 event Transfer(address indexed from, address indexed to, uint256 value); 100 } 101 102 contract ERC20 is ERC20Basic { 103 function allowance(address owner, address spender) 104 public view returns (uint256); 105 106 function transferFrom(address from, address to, uint256 value) 107 public returns (bool); 108 109 function approve(address spender, uint256 value) public returns (bool); 110 event Approval( 111 address indexed owner, 112 address indexed spender, 113 uint256 value 114 ); 115 } 116 117 library ArrayUtils { 118 119 /** 120 * Replace bytes in an array with bytes in another array, guarded by a bitmask 121 * Efficiency of this function is a bit unpredictable because of the EVM's word-specific model (arrays under 32 bytes will be slower) 122 * 123 * @dev Mask must be the size of the byte array. A nonzero byte means the byte array can be changed. 124 * @param array The original array 125 * @param desired The target array 126 * @param mask The mask specifying which bits can be changed 127 * @return The updated byte array (the parameter will be modified inplace) 128 */ 129 function guardedArrayReplace(bytes memory array, bytes memory desired, bytes memory mask) 130 internal 131 pure 132 { 133 require(array.length == desired.length); 134 require(array.length == mask.length); 135 136 uint words = array.length / 0x20; 137 uint index = words * 0x20; 138 assert(index / 0x20 == words); 139 uint i; 140 141 for (i = 0; i < words; i++) { 142 /* Conceptually: array[i] = (!mask[i] && array[i]) || (mask[i] && desired[i]), bitwise in word chunks. */ 143 assembly { 144 let commonIndex := mul(0x20, add(1, i)) 145 let maskValue := mload(add(mask, commonIndex)) 146 mstore(add(array, commonIndex), or(and(not(maskValue), mload(add(array, commonIndex))), and(maskValue, mload(add(desired, commonIndex))))) 147 } 148 } 149 150 /* Deal with the last section of the byte array. */ 151 if (words > 0) { 152 /* This overlaps with bytes already set but is still more efficient than iterating through each of the remaining bytes individually. */ 153 i = words; 154 assembly { 155 let commonIndex := mul(0x20, add(1, i)) 156 let maskValue := mload(add(mask, commonIndex)) 157 mstore(add(array, commonIndex), or(and(not(maskValue), mload(add(array, commonIndex))), and(maskValue, mload(add(desired, commonIndex))))) 158 } 159 } else { 160 /* If the byte array is shorter than a word, we must unfortunately do the whole thing bytewise. 161 (bounds checks could still probably be optimized away in assembly, but this is a rare case) */ 162 for (i = index; i < array.length; i++) { 163 array[i] = ((mask[i] ^ 0xff) & array[i]) | (mask[i] & desired[i]); 164 } 165 } 166 } 167 168 /** 169 * Test if two arrays are equal 170 * Source: https://github.com/GNSPS/solidity-bytes-utils/blob/master/contracts/BytesLib.sol 171 * 172 * @dev Arrays must be of equal length, otherwise will return false 173 * @param a First array 174 * @param b Second array 175 * @return Whether or not all bytes in the arrays are equal 176 */ 177 function arrayEq(bytes memory a, bytes memory b) 178 internal 179 pure 180 returns (bool) 181 { 182 bool success = true; 183 184 assembly { 185 let length := mload(a) 186 187 // if lengths don't match the arrays are not equal 188 switch eq(length, mload(b)) 189 case 1 { 190 // cb is a circuit breaker in the for loop since there's 191 // no said feature for inline assembly loops 192 // cb = 1 - don't breaker 193 // cb = 0 - break 194 let cb := 1 195 196 let mc := add(a, 0x20) 197 let end := add(mc, length) 198 199 for { 200 let cc := add(b, 0x20) 201 // the next line is the loop condition: 202 // while(uint(mc < end) + cb == 2) 203 } eq(add(lt(mc, end), cb), 2) { 204 mc := add(mc, 0x20) 205 cc := add(cc, 0x20) 206 } { 207 // if any of these checks fails then arrays are not equal 208 if iszero(eq(mload(mc), mload(cc))) { 209 // unsuccess: 210 success := 0 211 cb := 0 212 } 213 } 214 } 215 default { 216 // unsuccess: 217 success := 0 218 } 219 } 220 221 return success; 222 } 223 224 /** 225 * Unsafe write byte array into a memory location 226 * 227 * @param index Memory location 228 * @param source Byte array to write 229 * @return End memory index 230 */ 231 function unsafeWriteBytes(uint index, bytes source) 232 internal 233 pure 234 returns (uint) 235 { 236 if (source.length > 0) { 237 assembly { 238 let length := mload(source) 239 let end := add(source, add(0x20, length)) 240 let arrIndex := add(source, 0x20) 241 let tempIndex := index 242 for { } eq(lt(arrIndex, end), 1) { 243 arrIndex := add(arrIndex, 0x20) 244 tempIndex := add(tempIndex, 0x20) 245 } { 246 mstore(tempIndex, mload(arrIndex)) 247 } 248 index := add(index, length) 249 } 250 } 251 return index; 252 } 253 254 /** 255 * Unsafe write address into a memory location 256 * 257 * @param index Memory location 258 * @param source Address to write 259 * @return End memory index 260 */ 261 function unsafeWriteAddress(uint index, address source) 262 internal 263 pure 264 returns (uint) 265 { 266 uint conv = uint(source) << 0x60; 267 assembly { 268 mstore(index, conv) 269 index := add(index, 0x14) 270 } 271 return index; 272 } 273 274 /** 275 * Unsafe write uint into a memory location 276 * 277 * @param index Memory location 278 * @param source uint to write 279 * @return End memory index 280 */ 281 function unsafeWriteUint(uint index, uint source) 282 internal 283 pure 284 returns (uint) 285 { 286 assembly { 287 mstore(index, source) 288 index := add(index, 0x20) 289 } 290 return index; 291 } 292 293 /** 294 * Unsafe write uint8 into a memory location 295 * 296 * @param index Memory location 297 * @param source uint8 to write 298 * @return End memory index 299 */ 300 function unsafeWriteUint8(uint index, uint8 source) 301 internal 302 pure 303 returns (uint) 304 { 305 assembly { 306 mstore8(index, source) 307 index := add(index, 0x1) 308 } 309 return index; 310 } 311 312 } 313 314 contract ReentrancyGuarded { 315 316 bool reentrancyLock = false; 317 318 /* Prevent a contract function from being reentrant-called. */ 319 modifier reentrancyGuard { 320 if (reentrancyLock) { 321 revert(); 322 } 323 reentrancyLock = true; 324 _; 325 reentrancyLock = false; 326 } 327 328 } 329 330 contract TokenRecipient { 331 event ReceivedEther(address indexed sender, uint amount); 332 event ReceivedTokens(address indexed from, uint256 value, address indexed token, bytes extraData); 333 334 /** 335 * @dev Receive tokens and generate a log event 336 * @param from Address from which to transfer tokens 337 * @param value Amount of tokens to transfer 338 * @param token Address of token 339 * @param extraData Additional data to log 340 */ 341 function receiveApproval(address from, uint256 value, address token, bytes extraData) public { 342 ERC20 t = ERC20(token); 343 require(t.transferFrom(from, this, value)); 344 emit ReceivedTokens(from, value, token, extraData); 345 } 346 347 /** 348 * @dev Receive Ether and generate a log event 349 */ 350 function () payable public { 351 emit ReceivedEther(msg.sender, msg.value); 352 } 353 } 354 355 contract ExchangeCore is ReentrancyGuarded, Ownable { 356 357 /* The token used to pay exchange fees. */ 358 ERC20 public exchangeToken; 359 360 /* User registry. */ 361 ProxyRegistry public registry; 362 363 /* Token transfer proxy. */ 364 TokenTransferProxy public tokenTransferProxy; 365 366 /* Cancelled / finalized orders, by hash. */ 367 mapping(bytes32 => bool) public cancelledOrFinalized; 368 369 /* Orders verified by on-chain approval (alternative to ECDSA signatures so that smart contracts can place orders directly). */ 370 mapping(bytes32 => bool) public approvedOrders; 371 372 /* For split fee orders, minimum required protocol maker fee, in basis points. Paid to owner (who can change it). */ 373 uint public minimumMakerProtocolFee = 0; 374 375 /* For split fee orders, minimum required protocol taker fee, in basis points. Paid to owner (who can change it). */ 376 uint public minimumTakerProtocolFee = 0; 377 378 /* Recipient of protocol fees. */ 379 address public protocolFeeRecipient; 380 381 /* Fee method: protocol fee or split fee. */ 382 enum FeeMethod { ProtocolFee, SplitFee } 383 384 /* Inverse basis point. */ 385 uint public constant INVERSE_BASIS_POINT = 10000; 386 387 /* An ECDSA signature. */ 388 struct Sig { 389 /* v parameter */ 390 uint8 v; 391 /* r parameter */ 392 bytes32 r; 393 /* s parameter */ 394 bytes32 s; 395 } 396 397 /* An order on the exchange. */ 398 struct Order { 399 /* Exchange address, intended as a versioning mechanism. */ 400 address exchange; 401 /* Order maker address. */ 402 address maker; 403 /* Order taker address, if specified. */ 404 address taker; 405 /* Maker relayer fee of the order, unused for taker order. */ 406 uint makerRelayerFee; 407 /* Taker relayer fee of the order, or maximum taker fee for a taker order. */ 408 uint takerRelayerFee; 409 /* Maker protocol fee of the order, unused for taker order. */ 410 uint makerProtocolFee; 411 /* Taker protocol fee of the order, or maximum taker fee for a taker order. */ 412 uint takerProtocolFee; 413 /* Order fee recipient or zero address for taker order. */ 414 address feeRecipient; 415 /* Fee method (protocol token or split fee). */ 416 FeeMethod feeMethod; 417 /* Side (buy/sell). */ 418 SaleKindInterface.Side side; 419 /* Kind of sale. */ 420 SaleKindInterface.SaleKind saleKind; 421 /* Target. */ 422 address target; 423 /* HowToCall. */ 424 AuthenticatedProxy.HowToCall howToCall; 425 /* Calldata. */ 426 bytes calldata; 427 /* Calldata replacement pattern, or an empty byte array for no replacement. */ 428 bytes replacementPattern; 429 /* Static call target, zero-address for no static call. */ 430 address staticTarget; 431 /* Static call extra data. */ 432 bytes staticExtradata; 433 /* Token used to pay for the order, or the zero-address as a sentinel value for Ether. */ 434 address paymentToken; 435 /* Base price of the order (in paymentTokens). */ 436 uint basePrice; 437 /* Auction extra parameter - minimum bid increment for English auctions, starting/ending price difference. */ 438 uint extra; 439 /* Listing timestamp. */ 440 uint listingTime; 441 /* Expiration timestamp - 0 for no expiry. */ 442 uint expirationTime; 443 /* Order salt, used to prevent duplicate hashes. */ 444 uint salt; 445 } 446 447 event OrderApprovedPartOne (bytes32 indexed hash, address exchange, address indexed maker, address taker, uint makerRelayerFee, uint takerRelayerFee, uint makerProtocolFee, uint takerProtocolFee, address indexed feeRecipient, FeeMethod feeMethod, SaleKindInterface.Side side, SaleKindInterface.SaleKind saleKind, address target); 448 event OrderApprovedPartTwo (bytes32 indexed hash, AuthenticatedProxy.HowToCall howToCall, bytes calldata, bytes replacementPattern, address staticTarget, bytes staticExtradata, address paymentToken, uint basePrice, uint extra, uint listingTime, uint expirationTime, uint salt, bool orderbookInclusionDesired); 449 event OrderCancelled (bytes32 indexed hash); 450 event OrdersMatched (bytes32 buyHash, bytes32 sellHash, address indexed maker, address indexed taker, uint price, bytes32 indexed metadata); 451 452 /** 453 * @dev Change the minimum maker fee paid to the protocol (owner only) 454 * @param newMinimumMakerProtocolFee New fee to set in basis points 455 */ 456 function changeMinimumMakerProtocolFee(uint newMinimumMakerProtocolFee) 457 public 458 onlyOwner 459 { 460 minimumMakerProtocolFee = newMinimumMakerProtocolFee; 461 } 462 463 /** 464 * @dev Change the minimum taker fee paid to the protocol (owner only) 465 * @param newMinimumTakerProtocolFee New fee to set in basis points 466 */ 467 function changeMinimumTakerProtocolFee(uint newMinimumTakerProtocolFee) 468 public 469 onlyOwner 470 { 471 minimumTakerProtocolFee = newMinimumTakerProtocolFee; 472 } 473 474 /** 475 * @dev Change the protocol fee recipient (owner only) 476 * @param newProtocolFeeRecipient New protocol fee recipient address 477 */ 478 function changeProtocolFeeRecipient(address newProtocolFeeRecipient) 479 public 480 onlyOwner 481 { 482 protocolFeeRecipient = newProtocolFeeRecipient; 483 } 484 485 /** 486 * @dev Transfer tokens 487 * @param token Token to transfer 488 * @param from Address to charge fees 489 * @param to Address to receive fees 490 * @param amount Amount of protocol tokens to charge 491 */ 492 function transferTokens(address token, address from, address to, uint amount) 493 internal 494 { 495 if (amount > 0) { 496 require(tokenTransferProxy.transferFrom(token, from, to, amount)); 497 } 498 } 499 500 /** 501 * @dev Charge a fee in protocol tokens 502 * @param from Address to charge fees 503 * @param to Address to receive fees 504 * @param amount Amount of protocol tokens to charge 505 */ 506 function chargeProtocolFee(address from, address to, uint amount) 507 internal 508 { 509 transferTokens(exchangeToken, from, to, amount); 510 } 511 512 /** 513 * @dev Execute a STATICCALL (introduced with Ethereum Metropolis, non-state-modifying external call) 514 * @param target Contract to call 515 * @param calldata Calldata (appended to extradata) 516 * @param extradata Base data for STATICCALL (probably function selector and argument encoding) 517 * @return The result of the call (success or failure) 518 */ 519 function staticCall(address target, bytes memory calldata, bytes memory extradata) 520 public 521 view 522 returns (bool result) 523 { 524 bytes memory combined = new bytes(calldata.length + extradata.length); 525 uint index; 526 assembly { 527 index := add(combined, 0x20) 528 } 529 index = ArrayUtils.unsafeWriteBytes(index, extradata); 530 ArrayUtils.unsafeWriteBytes(index, calldata); 531 assembly { 532 result := staticcall(gas, target, add(combined, 0x20), mload(combined), mload(0x40), 0) 533 } 534 return result; 535 } 536 537 /** 538 * Calculate size of an order struct when tightly packed 539 * 540 * @param order Order to calculate size of 541 * @return Size in bytes 542 */ 543 function sizeOf(Order memory order) 544 internal 545 pure 546 returns (uint) 547 { 548 return ((0x14 * 7) + (0x20 * 9) + 4 + order.calldata.length + order.replacementPattern.length + order.staticExtradata.length); 549 } 550 551 /** 552 * @dev Hash an order, returning the canonical order hash, without the message prefix 553 * @param order Order to hash 554 * @return Hash of order 555 */ 556 function hashOrder(Order memory order) 557 internal 558 pure 559 returns (bytes32 hash) 560 { 561 /* Unfortunately abi.encodePacked doesn't work here, stack size constraints. */ 562 uint size = sizeOf(order); 563 bytes memory array = new bytes(size); 564 uint index; 565 assembly { 566 index := add(array, 0x20) 567 } 568 index = ArrayUtils.unsafeWriteAddress(index, order.exchange); 569 index = ArrayUtils.unsafeWriteAddress(index, order.maker); 570 index = ArrayUtils.unsafeWriteAddress(index, order.taker); 571 index = ArrayUtils.unsafeWriteUint(index, order.makerRelayerFee); 572 index = ArrayUtils.unsafeWriteUint(index, order.takerRelayerFee); 573 index = ArrayUtils.unsafeWriteUint(index, order.makerProtocolFee); 574 index = ArrayUtils.unsafeWriteUint(index, order.takerProtocolFee); 575 index = ArrayUtils.unsafeWriteAddress(index, order.feeRecipient); 576 index = ArrayUtils.unsafeWriteUint8(index, uint8(order.feeMethod)); 577 index = ArrayUtils.unsafeWriteUint8(index, uint8(order.side)); 578 index = ArrayUtils.unsafeWriteUint8(index, uint8(order.saleKind)); 579 index = ArrayUtils.unsafeWriteAddress(index, order.target); 580 index = ArrayUtils.unsafeWriteUint8(index, uint8(order.howToCall)); 581 index = ArrayUtils.unsafeWriteBytes(index, order.calldata); 582 index = ArrayUtils.unsafeWriteBytes(index, order.replacementPattern); 583 index = ArrayUtils.unsafeWriteAddress(index, order.staticTarget); 584 index = ArrayUtils.unsafeWriteBytes(index, order.staticExtradata); 585 index = ArrayUtils.unsafeWriteAddress(index, order.paymentToken); 586 index = ArrayUtils.unsafeWriteUint(index, order.basePrice); 587 index = ArrayUtils.unsafeWriteUint(index, order.extra); 588 index = ArrayUtils.unsafeWriteUint(index, order.listingTime); 589 index = ArrayUtils.unsafeWriteUint(index, order.expirationTime); 590 index = ArrayUtils.unsafeWriteUint(index, order.salt); 591 assembly { 592 hash := keccak256(add(array, 0x20), size) 593 } 594 return hash; 595 } 596 597 /** 598 * @dev Hash an order, returning the hash that a client must sign, including the standard message prefix 599 * @param order Order to hash 600 * @return Hash of message prefix and order hash per Ethereum format 601 */ 602 function hashToSign(Order memory order) 603 internal 604 pure 605 returns (bytes32) 606 { 607 return keccak256("\x19Ethereum Signed Message:\n32", hashOrder(order)); 608 } 609 610 /** 611 * @dev Assert an order is valid and return its hash 612 * @param order Order to validate 613 * @param sig ECDSA signature 614 */ 615 function requireValidOrder(Order memory order, Sig memory sig) 616 internal 617 view 618 returns (bytes32) 619 { 620 bytes32 hash = hashToSign(order); 621 require(validateOrder(hash, order, sig)); 622 return hash; 623 } 624 625 /** 626 * @dev Validate order parameters (does *not* check signature validity) 627 * @param order Order to validate 628 */ 629 function validateOrderParameters(Order memory order) 630 internal 631 view 632 returns (bool) 633 { 634 /* Order must be targeted at this protocol version (this Exchange contract). */ 635 if (order.exchange != address(this)) { 636 return false; 637 } 638 639 /* Order must possess valid sale kind parameter combination. */ 640 if (!SaleKindInterface.validateParameters(order.saleKind, order.expirationTime)) { 641 return false; 642 } 643 644 /* If using the split fee method, order must have sufficient protocol fees. */ 645 if (order.feeMethod == FeeMethod.SplitFee && (order.makerProtocolFee < minimumMakerProtocolFee || order.takerProtocolFee < minimumTakerProtocolFee)) { 646 return false; 647 } 648 649 return true; 650 } 651 652 /** 653 * @dev Validate a provided previously approved / signed order, hash, and signature. 654 * @param hash Order hash (already calculated, passed to avoid recalculation) 655 * @param order Order to validate 656 * @param sig ECDSA signature 657 */ 658 function validateOrder(bytes32 hash, Order memory order, Sig memory sig) 659 internal 660 view 661 returns (bool) 662 { 663 /* Not done in an if-conditional to prevent unnecessary ecrecover evaluation, which seems to happen even though it should short-circuit. */ 664 665 /* Order must have valid parameters. */ 666 if (!validateOrderParameters(order)) { 667 return false; 668 } 669 670 /* Order must have not been canceled or already filled. */ 671 if (cancelledOrFinalized[hash]) { 672 return false; 673 } 674 675 /* Order authentication. Order must be either: 676 /* (a) previously approved */ 677 if (approvedOrders[hash]) { 678 return true; 679 } 680 681 /* or (b) ECDSA-signed by maker. */ 682 if (ecrecover(hash, sig.v, sig.r, sig.s) == order.maker) { 683 return true; 684 } 685 686 return false; 687 } 688 689 /** 690 * @dev Approve an order and optionally mark it for orderbook inclusion. Must be called by the maker of the order 691 * @param order Order to approve 692 * @param orderbookInclusionDesired Whether orderbook providers should include the order in their orderbooks 693 */ 694 function approveOrder(Order memory order, bool orderbookInclusionDesired) 695 internal 696 { 697 /* CHECKS */ 698 699 /* Assert sender is authorized to approve order. */ 700 require(msg.sender == order.maker); 701 702 /* Calculate order hash. */ 703 bytes32 hash = hashToSign(order); 704 705 /* Assert order has not already been approved. */ 706 require(!approvedOrders[hash]); 707 708 /* EFFECTS */ 709 710 /* Mark order as approved. */ 711 approvedOrders[hash] = true; 712 713 /* Log approval event. Must be split in two due to Solidity stack size limitations. */ 714 { 715 emit OrderApprovedPartOne(hash, order.exchange, order.maker, order.taker, order.makerRelayerFee, order.takerRelayerFee, order.makerProtocolFee, order.takerProtocolFee, order.feeRecipient, order.feeMethod, order.side, order.saleKind, order.target); 716 } 717 { 718 emit OrderApprovedPartTwo(hash, order.howToCall, order.calldata, order.replacementPattern, order.staticTarget, order.staticExtradata, order.paymentToken, order.basePrice, order.extra, order.listingTime, order.expirationTime, order.salt, orderbookInclusionDesired); 719 } 720 } 721 722 /** 723 * @dev Cancel an order, preventing it from being matched. Must be called by the maker of the order 724 * @param order Order to cancel 725 * @param sig ECDSA signature 726 */ 727 function cancelOrder(Order memory order, Sig memory sig) 728 internal 729 { 730 /* CHECKS */ 731 732 /* Calculate order hash. */ 733 bytes32 hash = requireValidOrder(order, sig); 734 735 /* Assert sender is authorized to cancel order. */ 736 require(msg.sender == order.maker); 737 738 /* EFFECTS */ 739 740 /* Mark order as cancelled, preventing it from being matched. */ 741 cancelledOrFinalized[hash] = true; 742 743 /* Log cancel event. */ 744 emit OrderCancelled(hash); 745 } 746 747 /** 748 * @dev Calculate the current price of an order (convenience function) 749 * @param order Order to calculate the price of 750 * @return The current price of the order 751 */ 752 function calculateCurrentPrice (Order memory order) 753 internal 754 view 755 returns (uint) 756 { 757 return SaleKindInterface.calculateFinalPrice(order.side, order.saleKind, order.basePrice, order.extra, order.listingTime, order.expirationTime); 758 } 759 760 /** 761 * @dev Calculate the price two orders would match at, if in fact they would match (otherwise fail) 762 * @param buy Buy-side order 763 * @param sell Sell-side order 764 * @return Match price 765 */ 766 function calculateMatchPrice(Order memory buy, Order memory sell) 767 view 768 internal 769 returns (uint) 770 { 771 /* Calculate sell price. */ 772 uint sellPrice = SaleKindInterface.calculateFinalPrice(sell.side, sell.saleKind, sell.basePrice, sell.extra, sell.listingTime, sell.expirationTime); 773 774 /* Calculate buy price. */ 775 uint buyPrice = SaleKindInterface.calculateFinalPrice(buy.side, buy.saleKind, buy.basePrice, buy.extra, buy.listingTime, buy.expirationTime); 776 777 /* Require price cross. */ 778 require(buyPrice >= sellPrice); 779 780 /* Maker/taker priority. */ 781 return sell.feeRecipient != address(0) ? sellPrice : buyPrice; 782 } 783 784 /** 785 * @dev Execute all ERC20 token / Ether transfers associated with an order match (fees and buyer => seller transfer) 786 * @param buy Buy-side order 787 * @param sell Sell-side order 788 */ 789 function executeFundsTransfer(Order memory buy, Order memory sell) 790 internal 791 returns (uint) 792 { 793 /* Only payable in the special case of unwrapped Ether. */ 794 if (sell.paymentToken != address(0)) { 795 require(msg.value == 0); 796 } 797 798 /* Calculate match price. */ 799 uint price = calculateMatchPrice(buy, sell); 800 801 /* If paying using a token (not Ether), transfer tokens. This is done prior to fee payments to that a seller will have tokens before being charged fees. */ 802 if (price > 0 && sell.paymentToken != address(0)) { 803 transferTokens(sell.paymentToken, buy.maker, sell.maker, price); 804 } 805 806 /* Amount that will be received by seller (for Ether). */ 807 uint receiveAmount = price; 808 809 /* Amount that must be sent by buyer (for Ether). */ 810 uint requiredAmount = price; 811 812 /* Determine maker/taker and charge fees accordingly. */ 813 if (sell.feeRecipient != address(0)) { 814 /* Sell-side order is maker. */ 815 816 /* Assert taker fee is less than or equal to maximum fee specified by buyer. */ 817 require(sell.takerRelayerFee <= buy.takerRelayerFee); 818 819 if (sell.feeMethod == FeeMethod.SplitFee) { 820 /* Assert taker fee is less than or equal to maximum fee specified by buyer. */ 821 require(sell.takerProtocolFee <= buy.takerProtocolFee); 822 823 /* Maker fees are deducted from the token amount that the maker receives. Taker fees are extra tokens that must be paid by the taker. */ 824 825 if (sell.makerRelayerFee > 0) { 826 uint makerRelayerFee = SafeMath.div(SafeMath.mul(sell.makerRelayerFee, price), INVERSE_BASIS_POINT); 827 if (sell.paymentToken == address(0)) { 828 receiveAmount = SafeMath.sub(receiveAmount, makerRelayerFee); 829 sell.feeRecipient.transfer(makerRelayerFee); 830 } else { 831 transferTokens(sell.paymentToken, sell.maker, sell.feeRecipient, makerRelayerFee); 832 } 833 } 834 835 if (sell.takerRelayerFee > 0) { 836 uint takerRelayerFee = SafeMath.div(SafeMath.mul(sell.takerRelayerFee, price), INVERSE_BASIS_POINT); 837 if (sell.paymentToken == address(0)) { 838 requiredAmount = SafeMath.add(requiredAmount, takerRelayerFee); 839 sell.feeRecipient.transfer(takerRelayerFee); 840 } else { 841 transferTokens(sell.paymentToken, buy.maker, sell.feeRecipient, takerRelayerFee); 842 } 843 } 844 845 if (sell.makerProtocolFee > 0) { 846 uint makerProtocolFee = SafeMath.div(SafeMath.mul(sell.makerProtocolFee, price), INVERSE_BASIS_POINT); 847 if (sell.paymentToken == address(0)) { 848 receiveAmount = SafeMath.sub(receiveAmount, makerProtocolFee); 849 protocolFeeRecipient.transfer(makerProtocolFee); 850 } else { 851 transferTokens(sell.paymentToken, sell.maker, protocolFeeRecipient, makerProtocolFee); 852 } 853 } 854 855 if (sell.takerProtocolFee > 0) { 856 uint takerProtocolFee = SafeMath.div(SafeMath.mul(sell.takerProtocolFee, price), INVERSE_BASIS_POINT); 857 if (sell.paymentToken == address(0)) { 858 requiredAmount = SafeMath.add(requiredAmount, takerProtocolFee); 859 protocolFeeRecipient.transfer(takerProtocolFee); 860 } else { 861 transferTokens(sell.paymentToken, buy.maker, protocolFeeRecipient, takerProtocolFee); 862 } 863 } 864 865 } else { 866 /* Charge maker fee to seller. */ 867 chargeProtocolFee(sell.maker, sell.feeRecipient, sell.makerRelayerFee); 868 869 /* Charge taker fee to buyer. */ 870 chargeProtocolFee(buy.maker, sell.feeRecipient, sell.takerRelayerFee); 871 } 872 } else { 873 /* Buy-side order is maker. */ 874 875 /* Assert taker fee is less than or equal to maximum fee specified by seller. */ 876 require(buy.takerRelayerFee <= sell.takerRelayerFee); 877 878 if (sell.feeMethod == FeeMethod.SplitFee) { 879 /* The Exchange does not escrow Ether, so direct Ether can only be used to with sell-side maker / buy-side taker orders. */ 880 require(sell.paymentToken != address(0)); 881 882 /* Assert taker fee is less than or equal to maximum fee specified by seller. */ 883 require(buy.takerProtocolFee <= sell.takerProtocolFee); 884 885 if (buy.makerRelayerFee > 0) { 886 makerRelayerFee = SafeMath.div(SafeMath.mul(buy.makerRelayerFee, price), INVERSE_BASIS_POINT); 887 transferTokens(sell.paymentToken, buy.maker, buy.feeRecipient, makerRelayerFee); 888 } 889 890 if (buy.takerRelayerFee > 0) { 891 takerRelayerFee = SafeMath.div(SafeMath.mul(buy.takerRelayerFee, price), INVERSE_BASIS_POINT); 892 transferTokens(sell.paymentToken, sell.maker, buy.feeRecipient, takerRelayerFee); 893 } 894 895 if (buy.makerProtocolFee > 0) { 896 makerProtocolFee = SafeMath.div(SafeMath.mul(buy.makerProtocolFee, price), INVERSE_BASIS_POINT); 897 transferTokens(sell.paymentToken, buy.maker, protocolFeeRecipient, makerProtocolFee); 898 } 899 900 if (buy.takerProtocolFee > 0) { 901 takerProtocolFee = SafeMath.div(SafeMath.mul(buy.takerProtocolFee, price), INVERSE_BASIS_POINT); 902 transferTokens(sell.paymentToken, sell.maker, protocolFeeRecipient, takerProtocolFee); 903 } 904 905 } else { 906 /* Charge maker fee to buyer. */ 907 chargeProtocolFee(buy.maker, buy.feeRecipient, buy.makerRelayerFee); 908 909 /* Charge taker fee to seller. */ 910 chargeProtocolFee(sell.maker, buy.feeRecipient, buy.takerRelayerFee); 911 } 912 } 913 914 if (sell.paymentToken == address(0)) { 915 /* Special-case Ether, order must be matched by buyer. */ 916 require(msg.value >= requiredAmount); 917 sell.maker.transfer(receiveAmount); 918 /* Allow overshoot for variable-price auctions, refund difference. */ 919 uint diff = SafeMath.sub(msg.value, requiredAmount); 920 if (diff > 0) { 921 buy.maker.transfer(diff); 922 } 923 } 924 925 /* This contract should never hold Ether, however, we cannot assert this, since it is impossible to prevent anyone from sending Ether e.g. with selfdestruct. */ 926 927 return price; 928 } 929 930 /** 931 * @dev Return whether or not two orders can be matched with each other by basic parameters (does not check order signatures / calldata or perform static calls) 932 * @param buy Buy-side order 933 * @param sell Sell-side order 934 * @return Whether or not the two orders can be matched 935 */ 936 function ordersCanMatch(Order memory buy, Order memory sell) 937 internal 938 view 939 returns (bool) 940 { 941 return ( 942 /* Must be opposite-side. */ 943 (buy.side == SaleKindInterface.Side.Buy && sell.side == SaleKindInterface.Side.Sell) && 944 /* Must use same fee method. */ 945 (buy.feeMethod == sell.feeMethod) && 946 /* Must use same payment token. */ 947 (buy.paymentToken == sell.paymentToken) && 948 /* Must match maker/taker addresses. */ 949 (sell.taker == address(0) || sell.taker == buy.maker) && 950 (buy.taker == address(0) || buy.taker == sell.maker) && 951 /* One must be maker and the other must be taker (no bool XOR in Solidity). */ 952 ((sell.feeRecipient == address(0) && buy.feeRecipient != address(0)) || (sell.feeRecipient != address(0) && buy.feeRecipient == address(0))) && 953 /* Must match target. */ 954 (buy.target == sell.target) && 955 /* Must match howToCall. */ 956 (buy.howToCall == sell.howToCall) && 957 /* Buy-side order must be settleable. */ 958 SaleKindInterface.canSettleOrder(buy.listingTime, buy.expirationTime) && 959 /* Sell-side order must be settleable. */ 960 SaleKindInterface.canSettleOrder(sell.listingTime, sell.expirationTime) 961 ); 962 } 963 964 /** 965 * @dev Atomically match two orders, ensuring validity of the match, and execute all associated state transitions. Protected against reentrancy by a contract-global lock. 966 * @param buy Buy-side order 967 * @param buySig Buy-side order signature 968 * @param sell Sell-side order 969 * @param sellSig Sell-side order signature 970 */ 971 function atomicMatch(Order memory buy, Sig memory buySig, Order memory sell, Sig memory sellSig, bytes32 metadata) 972 internal 973 reentrancyGuard 974 { 975 /* CHECKS */ 976 977 /* Ensure buy order validity and calculate hash if necessary. */ 978 bytes32 buyHash; 979 if (buy.maker == msg.sender) { 980 require(validateOrderParameters(buy)); 981 } else { 982 buyHash = requireValidOrder(buy, buySig); 983 } 984 985 /* Ensure sell order validity and calculate hash if necessary. */ 986 bytes32 sellHash; 987 if (sell.maker == msg.sender) { 988 require(validateOrderParameters(sell)); 989 } else { 990 sellHash = requireValidOrder(sell, sellSig); 991 } 992 993 /* Must be matchable. */ 994 require(ordersCanMatch(buy, sell)); 995 996 /* Target must exist (prevent malicious selfdestructs just prior to order settlement). */ 997 uint size; 998 address target = sell.target; 999 assembly { 1000 size := extcodesize(target) 1001 } 1002 require(size > 0); 1003 1004 /* Must match calldata after replacement, if specified. */ 1005 if (buy.replacementPattern.length > 0) { 1006 ArrayUtils.guardedArrayReplace(buy.calldata, sell.calldata, buy.replacementPattern); 1007 } 1008 if (sell.replacementPattern.length > 0) { 1009 ArrayUtils.guardedArrayReplace(sell.calldata, buy.calldata, sell.replacementPattern); 1010 } 1011 require(ArrayUtils.arrayEq(buy.calldata, sell.calldata)); 1012 1013 /* Retrieve delegateProxy contract. */ 1014 OwnableDelegateProxy delegateProxy = registry.proxies(sell.maker); 1015 1016 /* Proxy must exist. */ 1017 require(delegateProxy != address(0)); 1018 1019 /* Assert implementation. */ 1020 require(delegateProxy.implementation() == registry.delegateProxyImplementation()); 1021 1022 /* Access the passthrough AuthenticatedProxy. */ 1023 AuthenticatedProxy proxy = AuthenticatedProxy(delegateProxy); 1024 1025 /* EFFECTS */ 1026 1027 /* Mark previously signed or approved orders as finalized. */ 1028 if (msg.sender != buy.maker) { 1029 cancelledOrFinalized[buyHash] = true; 1030 } 1031 if (msg.sender != sell.maker) { 1032 cancelledOrFinalized[sellHash] = true; 1033 } 1034 1035 /* INTERACTIONS */ 1036 1037 /* Execute funds transfer and pay fees. */ 1038 uint price = executeFundsTransfer(buy, sell); 1039 1040 /* Execute specified call through proxy. */ 1041 require(proxy.proxy(sell.target, sell.howToCall, sell.calldata)); 1042 1043 /* Static calls are intentionally done after the effectful call so they can check resulting state. */ 1044 1045 /* Handle buy-side static call if specified. */ 1046 if (buy.staticTarget != address(0)) { 1047 require(staticCall(buy.staticTarget, sell.calldata, buy.staticExtradata)); 1048 } 1049 1050 /* Handle sell-side static call if specified. */ 1051 if (sell.staticTarget != address(0)) { 1052 require(staticCall(sell.staticTarget, sell.calldata, sell.staticExtradata)); 1053 } 1054 1055 /* Log match event. */ 1056 emit OrdersMatched(buyHash, sellHash, sell.feeRecipient != address(0) ? sell.maker : buy.maker, sell.feeRecipient != address(0) ? buy.maker : sell.maker, price, metadata); 1057 } 1058 1059 } 1060 1061 contract Exchange is ExchangeCore { 1062 1063 /** 1064 * @dev Call guardedArrayReplace - library function exposed for testing. 1065 */ 1066 function guardedArrayReplace(bytes array, bytes desired, bytes mask) 1067 public 1068 pure 1069 returns (bytes) 1070 { 1071 ArrayUtils.guardedArrayReplace(array, desired, mask); 1072 return array; 1073 } 1074 1075 /** 1076 * Test copy byte array 1077 * 1078 * @param arrToCopy Array to copy 1079 * @return byte array 1080 */ 1081 function testCopy(bytes arrToCopy) 1082 public 1083 pure 1084 returns (bytes) 1085 { 1086 bytes memory arr = new bytes(arrToCopy.length); 1087 uint index; 1088 assembly { 1089 index := add(arr, 0x20) 1090 } 1091 ArrayUtils.unsafeWriteBytes(index, arrToCopy); 1092 return arr; 1093 } 1094 1095 /** 1096 * Test write address to bytes 1097 * 1098 * @param addr Address to write 1099 * @return byte array 1100 */ 1101 function testCopyAddress(address addr) 1102 public 1103 pure 1104 returns (bytes) 1105 { 1106 bytes memory arr = new bytes(0x14); 1107 uint index; 1108 assembly { 1109 index := add(arr, 0x20) 1110 } 1111 ArrayUtils.unsafeWriteAddress(index, addr); 1112 return arr; 1113 } 1114 1115 /** 1116 * @dev Call calculateFinalPrice - library function exposed for testing. 1117 */ 1118 function calculateFinalPrice(SaleKindInterface.Side side, SaleKindInterface.SaleKind saleKind, uint basePrice, uint extra, uint listingTime, uint expirationTime) 1119 public 1120 view 1121 returns (uint) 1122 { 1123 return SaleKindInterface.calculateFinalPrice(side, saleKind, basePrice, extra, listingTime, expirationTime); 1124 } 1125 1126 /** 1127 * @dev Call hashOrder - Solidity ABI encoding limitation workaround, hopefully temporary. 1128 */ 1129 function hashOrder_( 1130 address[7] addrs, 1131 uint[9] uints, 1132 FeeMethod feeMethod, 1133 SaleKindInterface.Side side, 1134 SaleKindInterface.SaleKind saleKind, 1135 AuthenticatedProxy.HowToCall howToCall, 1136 bytes calldata, 1137 bytes replacementPattern, 1138 bytes staticExtradata) 1139 public 1140 pure 1141 returns (bytes32) 1142 { 1143 return hashOrder( 1144 Order(addrs[0], addrs[1], addrs[2], uints[0], uints[1], uints[2], uints[3], addrs[3], feeMethod, side, saleKind, addrs[4], howToCall, calldata, replacementPattern, addrs[5], staticExtradata, ERC20(addrs[6]), uints[4], uints[5], uints[6], uints[7], uints[8]) 1145 ); 1146 } 1147 1148 /** 1149 * @dev Call hashToSign - Solidity ABI encoding limitation workaround, hopefully temporary. 1150 */ 1151 function hashToSign_( 1152 address[7] addrs, 1153 uint[9] uints, 1154 FeeMethod feeMethod, 1155 SaleKindInterface.Side side, 1156 SaleKindInterface.SaleKind saleKind, 1157 AuthenticatedProxy.HowToCall howToCall, 1158 bytes calldata, 1159 bytes replacementPattern, 1160 bytes staticExtradata) 1161 public 1162 pure 1163 returns (bytes32) 1164 { 1165 return hashToSign( 1166 Order(addrs[0], addrs[1], addrs[2], uints[0], uints[1], uints[2], uints[3], addrs[3], feeMethod, side, saleKind, addrs[4], howToCall, calldata, replacementPattern, addrs[5], staticExtradata, ERC20(addrs[6]), uints[4], uints[5], uints[6], uints[7], uints[8]) 1167 ); 1168 } 1169 1170 /** 1171 * @dev Call validateOrderParameters - Solidity ABI encoding limitation workaround, hopefully temporary. 1172 */ 1173 function validateOrderParameters_ ( 1174 address[7] addrs, 1175 uint[9] uints, 1176 FeeMethod feeMethod, 1177 SaleKindInterface.Side side, 1178 SaleKindInterface.SaleKind saleKind, 1179 AuthenticatedProxy.HowToCall howToCall, 1180 bytes calldata, 1181 bytes replacementPattern, 1182 bytes staticExtradata) 1183 view 1184 public 1185 returns (bool) 1186 { 1187 Order memory order = Order(addrs[0], addrs[1], addrs[2], uints[0], uints[1], uints[2], uints[3], addrs[3], feeMethod, side, saleKind, addrs[4], howToCall, calldata, replacementPattern, addrs[5], staticExtradata, ERC20(addrs[6]), uints[4], uints[5], uints[6], uints[7], uints[8]); 1188 return validateOrderParameters( 1189 order 1190 ); 1191 } 1192 1193 /** 1194 * @dev Call validateOrder - Solidity ABI encoding limitation workaround, hopefully temporary. 1195 */ 1196 function validateOrder_ ( 1197 address[7] addrs, 1198 uint[9] uints, 1199 FeeMethod feeMethod, 1200 SaleKindInterface.Side side, 1201 SaleKindInterface.SaleKind saleKind, 1202 AuthenticatedProxy.HowToCall howToCall, 1203 bytes calldata, 1204 bytes replacementPattern, 1205 bytes staticExtradata, 1206 uint8 v, 1207 bytes32 r, 1208 bytes32 s) 1209 view 1210 public 1211 returns (bool) 1212 { 1213 Order memory order = Order(addrs[0], addrs[1], addrs[2], uints[0], uints[1], uints[2], uints[3], addrs[3], feeMethod, side, saleKind, addrs[4], howToCall, calldata, replacementPattern, addrs[5], staticExtradata, ERC20(addrs[6]), uints[4], uints[5], uints[6], uints[7], uints[8]); 1214 return validateOrder( 1215 hashToSign(order), 1216 order, 1217 Sig(v, r, s) 1218 ); 1219 } 1220 1221 /** 1222 * @dev Call approveOrder - Solidity ABI encoding limitation workaround, hopefully temporary. 1223 */ 1224 function approveOrder_ ( 1225 address[7] addrs, 1226 uint[9] uints, 1227 FeeMethod feeMethod, 1228 SaleKindInterface.Side side, 1229 SaleKindInterface.SaleKind saleKind, 1230 AuthenticatedProxy.HowToCall howToCall, 1231 bytes calldata, 1232 bytes replacementPattern, 1233 bytes staticExtradata, 1234 bool orderbookInclusionDesired) 1235 public 1236 { 1237 Order memory order = Order(addrs[0], addrs[1], addrs[2], uints[0], uints[1], uints[2], uints[3], addrs[3], feeMethod, side, saleKind, addrs[4], howToCall, calldata, replacementPattern, addrs[5], staticExtradata, ERC20(addrs[6]), uints[4], uints[5], uints[6], uints[7], uints[8]); 1238 return approveOrder(order, orderbookInclusionDesired); 1239 } 1240 1241 /** 1242 * @dev Call cancelOrder - Solidity ABI encoding limitation workaround, hopefully temporary. 1243 */ 1244 function cancelOrder_( 1245 address[7] addrs, 1246 uint[9] uints, 1247 FeeMethod feeMethod, 1248 SaleKindInterface.Side side, 1249 SaleKindInterface.SaleKind saleKind, 1250 AuthenticatedProxy.HowToCall howToCall, 1251 bytes calldata, 1252 bytes replacementPattern, 1253 bytes staticExtradata, 1254 uint8 v, 1255 bytes32 r, 1256 bytes32 s) 1257 public 1258 { 1259 1260 return cancelOrder( 1261 Order(addrs[0], addrs[1], addrs[2], uints[0], uints[1], uints[2], uints[3], addrs[3], feeMethod, side, saleKind, addrs[4], howToCall, calldata, replacementPattern, addrs[5], staticExtradata, ERC20(addrs[6]), uints[4], uints[5], uints[6], uints[7], uints[8]), 1262 Sig(v, r, s) 1263 ); 1264 } 1265 1266 /** 1267 * @dev Call calculateCurrentPrice - Solidity ABI encoding limitation workaround, hopefully temporary. 1268 */ 1269 function calculateCurrentPrice_( 1270 address[7] addrs, 1271 uint[9] uints, 1272 FeeMethod feeMethod, 1273 SaleKindInterface.Side side, 1274 SaleKindInterface.SaleKind saleKind, 1275 AuthenticatedProxy.HowToCall howToCall, 1276 bytes calldata, 1277 bytes replacementPattern, 1278 bytes staticExtradata) 1279 public 1280 view 1281 returns (uint) 1282 { 1283 return calculateCurrentPrice( 1284 Order(addrs[0], addrs[1], addrs[2], uints[0], uints[1], uints[2], uints[3], addrs[3], feeMethod, side, saleKind, addrs[4], howToCall, calldata, replacementPattern, addrs[5], staticExtradata, ERC20(addrs[6]), uints[4], uints[5], uints[6], uints[7], uints[8]) 1285 ); 1286 } 1287 1288 /** 1289 * @dev Call ordersCanMatch - Solidity ABI encoding limitation workaround, hopefully temporary. 1290 */ 1291 function ordersCanMatch_( 1292 address[14] addrs, 1293 uint[18] uints, 1294 uint8[8] feeMethodsSidesKindsHowToCalls, 1295 bytes calldataBuy, 1296 bytes calldataSell, 1297 bytes replacementPatternBuy, 1298 bytes replacementPatternSell, 1299 bytes staticExtradataBuy, 1300 bytes staticExtradataSell) 1301 public 1302 view 1303 returns (bool) 1304 { 1305 Order memory buy = Order(addrs[0], addrs[1], addrs[2], uints[0], uints[1], uints[2], uints[3], addrs[3], FeeMethod(feeMethodsSidesKindsHowToCalls[0]), SaleKindInterface.Side(feeMethodsSidesKindsHowToCalls[1]), SaleKindInterface.SaleKind(feeMethodsSidesKindsHowToCalls[2]), addrs[4], AuthenticatedProxy.HowToCall(feeMethodsSidesKindsHowToCalls[3]), calldataBuy, replacementPatternBuy, addrs[5], staticExtradataBuy, ERC20(addrs[6]), uints[4], uints[5], uints[6], uints[7], uints[8]); 1306 Order memory sell = Order(addrs[7], addrs[8], addrs[9], uints[9], uints[10], uints[11], uints[12], addrs[10], FeeMethod(feeMethodsSidesKindsHowToCalls[4]), SaleKindInterface.Side(feeMethodsSidesKindsHowToCalls[5]), SaleKindInterface.SaleKind(feeMethodsSidesKindsHowToCalls[6]), addrs[11], AuthenticatedProxy.HowToCall(feeMethodsSidesKindsHowToCalls[7]), calldataSell, replacementPatternSell, addrs[12], staticExtradataSell, ERC20(addrs[13]), uints[13], uints[14], uints[15], uints[16], uints[17]); 1307 return ordersCanMatch( 1308 buy, 1309 sell 1310 ); 1311 } 1312 1313 /** 1314 * @dev Return whether or not two orders' calldata specifications can match 1315 * @param buyCalldata Buy-side order calldata 1316 * @param buyReplacementPattern Buy-side order calldata replacement mask 1317 * @param sellCalldata Sell-side order calldata 1318 * @param sellReplacementPattern Sell-side order calldata replacement mask 1319 * @return Whether the orders' calldata can be matched 1320 */ 1321 function orderCalldataCanMatch(bytes buyCalldata, bytes buyReplacementPattern, bytes sellCalldata, bytes sellReplacementPattern) 1322 public 1323 pure 1324 returns (bool) 1325 { 1326 if (buyReplacementPattern.length > 0) { 1327 ArrayUtils.guardedArrayReplace(buyCalldata, sellCalldata, buyReplacementPattern); 1328 } 1329 if (sellReplacementPattern.length > 0) { 1330 ArrayUtils.guardedArrayReplace(sellCalldata, buyCalldata, sellReplacementPattern); 1331 } 1332 return ArrayUtils.arrayEq(buyCalldata, sellCalldata); 1333 } 1334 1335 /** 1336 * @dev Call calculateMatchPrice - Solidity ABI encoding limitation workaround, hopefully temporary. 1337 */ 1338 function calculateMatchPrice_( 1339 address[14] addrs, 1340 uint[18] uints, 1341 uint8[8] feeMethodsSidesKindsHowToCalls, 1342 bytes calldataBuy, 1343 bytes calldataSell, 1344 bytes replacementPatternBuy, 1345 bytes replacementPatternSell, 1346 bytes staticExtradataBuy, 1347 bytes staticExtradataSell) 1348 public 1349 view 1350 returns (uint) 1351 { 1352 Order memory buy = Order(addrs[0], addrs[1], addrs[2], uints[0], uints[1], uints[2], uints[3], addrs[3], FeeMethod(feeMethodsSidesKindsHowToCalls[0]), SaleKindInterface.Side(feeMethodsSidesKindsHowToCalls[1]), SaleKindInterface.SaleKind(feeMethodsSidesKindsHowToCalls[2]), addrs[4], AuthenticatedProxy.HowToCall(feeMethodsSidesKindsHowToCalls[3]), calldataBuy, replacementPatternBuy, addrs[5], staticExtradataBuy, ERC20(addrs[6]), uints[4], uints[5], uints[6], uints[7], uints[8]); 1353 Order memory sell = Order(addrs[7], addrs[8], addrs[9], uints[9], uints[10], uints[11], uints[12], addrs[10], FeeMethod(feeMethodsSidesKindsHowToCalls[4]), SaleKindInterface.Side(feeMethodsSidesKindsHowToCalls[5]), SaleKindInterface.SaleKind(feeMethodsSidesKindsHowToCalls[6]), addrs[11], AuthenticatedProxy.HowToCall(feeMethodsSidesKindsHowToCalls[7]), calldataSell, replacementPatternSell, addrs[12], staticExtradataSell, ERC20(addrs[13]), uints[13], uints[14], uints[15], uints[16], uints[17]); 1354 return calculateMatchPrice( 1355 buy, 1356 sell 1357 ); 1358 } 1359 1360 /** 1361 * @dev Call atomicMatch - Solidity ABI encoding limitation workaround, hopefully temporary. 1362 */ 1363 function atomicMatch_( 1364 address[14] addrs, 1365 uint[18] uints, 1366 uint8[8] feeMethodsSidesKindsHowToCalls, 1367 bytes calldataBuy, 1368 bytes calldataSell, 1369 bytes replacementPatternBuy, 1370 bytes replacementPatternSell, 1371 bytes staticExtradataBuy, 1372 bytes staticExtradataSell, 1373 uint8[2] vs, 1374 bytes32[5] rssMetadata) 1375 public 1376 payable 1377 { 1378 1379 return atomicMatch( 1380 Order(addrs[0], addrs[1], addrs[2], uints[0], uints[1], uints[2], uints[3], addrs[3], FeeMethod(feeMethodsSidesKindsHowToCalls[0]), SaleKindInterface.Side(feeMethodsSidesKindsHowToCalls[1]), SaleKindInterface.SaleKind(feeMethodsSidesKindsHowToCalls[2]), addrs[4], AuthenticatedProxy.HowToCall(feeMethodsSidesKindsHowToCalls[3]), calldataBuy, replacementPatternBuy, addrs[5], staticExtradataBuy, ERC20(addrs[6]), uints[4], uints[5], uints[6], uints[7], uints[8]), 1381 Sig(vs[0], rssMetadata[0], rssMetadata[1]), 1382 Order(addrs[7], addrs[8], addrs[9], uints[9], uints[10], uints[11], uints[12], addrs[10], FeeMethod(feeMethodsSidesKindsHowToCalls[4]), SaleKindInterface.Side(feeMethodsSidesKindsHowToCalls[5]), SaleKindInterface.SaleKind(feeMethodsSidesKindsHowToCalls[6]), addrs[11], AuthenticatedProxy.HowToCall(feeMethodsSidesKindsHowToCalls[7]), calldataSell, replacementPatternSell, addrs[12], staticExtradataSell, ERC20(addrs[13]), uints[13], uints[14], uints[15], uints[16], uints[17]), 1383 Sig(vs[1], rssMetadata[2], rssMetadata[3]), 1384 rssMetadata[4] 1385 ); 1386 } 1387 1388 } 1389 1390 contract WyvernExchange is Exchange { 1391 1392 string public constant name = "Project Wyvern Exchange"; 1393 1394 string public constant version = "2.2"; 1395 1396 string public constant codename = "Lambton Worm"; 1397 1398 /** 1399 * @dev Initialize a WyvernExchange instance 1400 * @param registryAddress Address of the registry instance which this Exchange instance will use 1401 * @param tokenAddress Address of the token used for protocol fees 1402 */ 1403 constructor (ProxyRegistry registryAddress, TokenTransferProxy tokenTransferProxyAddress, ERC20 tokenAddress, address protocolFeeAddress) public { 1404 registry = registryAddress; 1405 tokenTransferProxy = tokenTransferProxyAddress; 1406 exchangeToken = tokenAddress; 1407 protocolFeeRecipient = protocolFeeAddress; 1408 owner = msg.sender; 1409 } 1410 1411 } 1412 1413 library SaleKindInterface { 1414 1415 /** 1416 * Side: buy or sell. 1417 */ 1418 enum Side { Buy, Sell } 1419 1420 /** 1421 * Currently supported kinds of sale: fixed price, Dutch auction. 1422 * English auctions cannot be supported without stronger escrow guarantees. 1423 * Future interesting options: Vickrey auction, nonlinear Dutch auctions. 1424 */ 1425 enum SaleKind { FixedPrice, DutchAuction } 1426 1427 /** 1428 * @dev Check whether the parameters of a sale are valid 1429 * @param saleKind Kind of sale 1430 * @param expirationTime Order expiration time 1431 * @return Whether the parameters were valid 1432 */ 1433 function validateParameters(SaleKind saleKind, uint expirationTime) 1434 pure 1435 internal 1436 returns (bool) 1437 { 1438 /* Auctions must have a set expiration date. */ 1439 return (saleKind == SaleKind.FixedPrice || expirationTime > 0); 1440 } 1441 1442 /** 1443 * @dev Return whether or not an order can be settled 1444 * @dev Precondition: parameters have passed validateParameters 1445 * @param listingTime Order listing time 1446 * @param expirationTime Order expiration time 1447 */ 1448 function canSettleOrder(uint listingTime, uint expirationTime) 1449 view 1450 internal 1451 returns (bool) 1452 { 1453 return (listingTime < now) && (expirationTime == 0 || now < expirationTime); 1454 } 1455 1456 /** 1457 * @dev Calculate the settlement price of an order 1458 * @dev Precondition: parameters have passed validateParameters. 1459 * @param side Order side 1460 * @param saleKind Method of sale 1461 * @param basePrice Order base price 1462 * @param extra Order extra price data 1463 * @param listingTime Order listing time 1464 * @param expirationTime Order expiration time 1465 */ 1466 function calculateFinalPrice(Side side, SaleKind saleKind, uint basePrice, uint extra, uint listingTime, uint expirationTime) 1467 view 1468 internal 1469 returns (uint finalPrice) 1470 { 1471 if (saleKind == SaleKind.FixedPrice) { 1472 return basePrice; 1473 } else if (saleKind == SaleKind.DutchAuction) { 1474 uint diff = SafeMath.div(SafeMath.mul(extra, SafeMath.sub(now, listingTime)), SafeMath.sub(expirationTime, listingTime)); 1475 if (side == Side.Sell) { 1476 /* Sell-side - start price: basePrice. End price: basePrice - extra. */ 1477 return SafeMath.sub(basePrice, diff); 1478 } else { 1479 /* Buy-side - start price: basePrice. End price: basePrice + extra. */ 1480 return SafeMath.add(basePrice, diff); 1481 } 1482 } 1483 } 1484 1485 } 1486 1487 contract ProxyRegistry is Ownable { 1488 1489 /* DelegateProxy implementation contract. Must be initialized. */ 1490 address public delegateProxyImplementation; 1491 1492 /* Authenticated proxies by user. */ 1493 mapping(address => OwnableDelegateProxy) public proxies; 1494 1495 /* Contracts pending access. */ 1496 mapping(address => uint) public pending; 1497 1498 /* Contracts allowed to call those proxies. */ 1499 mapping(address => bool) public contracts; 1500 1501 /* Delay period for adding an authenticated contract. 1502 This mitigates a particular class of potential attack on the Wyvern DAO (which owns this registry) - if at any point the value of assets held by proxy contracts exceeded the value of half the WYV supply (votes in the DAO), 1503 a malicious but rational attacker could buy half the Wyvern and grant themselves access to all the proxy contracts. A delay period renders this attack nonthreatening - given two weeks, if that happened, users would have 1504 plenty of time to notice and transfer their assets. 1505 */ 1506 uint public DELAY_PERIOD = 2 weeks; 1507 1508 /** 1509 * Start the process to enable access for specified contract. Subject to delay period. 1510 * 1511 * @dev ProxyRegistry owner only 1512 * @param addr Address to which to grant permissions 1513 */ 1514 function startGrantAuthentication (address addr) 1515 public 1516 onlyOwner 1517 { 1518 require(!contracts[addr] && pending[addr] == 0); 1519 pending[addr] = now; 1520 } 1521 1522 /** 1523 * End the process to nable access for specified contract after delay period has passed. 1524 * 1525 * @dev ProxyRegistry owner only 1526 * @param addr Address to which to grant permissions 1527 */ 1528 function endGrantAuthentication (address addr) 1529 public 1530 onlyOwner 1531 { 1532 require(!contracts[addr] && pending[addr] != 0 && ((pending[addr] + DELAY_PERIOD) < now)); 1533 pending[addr] = 0; 1534 contracts[addr] = true; 1535 } 1536 1537 /** 1538 * Revoke access for specified contract. Can be done instantly. 1539 * 1540 * @dev ProxyRegistry owner only 1541 * @param addr Address of which to revoke permissions 1542 */ 1543 function revokeAuthentication (address addr) 1544 public 1545 onlyOwner 1546 { 1547 contracts[addr] = false; 1548 } 1549 1550 /** 1551 * Register a proxy contract with this registry 1552 * 1553 * @dev Must be called by the user which the proxy is for, creates a new AuthenticatedProxy 1554 * @return New AuthenticatedProxy contract 1555 */ 1556 function registerProxy() 1557 public 1558 returns (OwnableDelegateProxy proxy) 1559 { 1560 require(proxies[msg.sender] == address(0)); 1561 proxy = new OwnableDelegateProxy(msg.sender, delegateProxyImplementation, abi.encodeWithSignature("initialize(address,address)", msg.sender, address(this))); 1562 proxies[msg.sender] = proxy; 1563 return proxy; 1564 } 1565 1566 } 1567 1568 contract TokenTransferProxy { 1569 1570 /* Authentication registry. */ 1571 ProxyRegistry public registry; 1572 1573 /** 1574 * Call ERC20 `transferFrom` 1575 * 1576 * @dev Authenticated contract only 1577 * @param token ERC20 token address 1578 * @param from From address 1579 * @param to To address 1580 * @param amount Transfer amount 1581 */ 1582 function transferFrom(address token, address from, address to, uint amount) 1583 public 1584 returns (bool) 1585 { 1586 require(registry.contracts(msg.sender)); 1587 return ERC20(token).transferFrom(from, to, amount); 1588 } 1589 1590 } 1591 1592 contract OwnedUpgradeabilityStorage { 1593 1594 // Current implementation 1595 address internal _implementation; 1596 1597 // Owner of the contract 1598 address private _upgradeabilityOwner; 1599 1600 /** 1601 * @dev Tells the address of the owner 1602 * @return the address of the owner 1603 */ 1604 function upgradeabilityOwner() public view returns (address) { 1605 return _upgradeabilityOwner; 1606 } 1607 1608 /** 1609 * @dev Sets the address of the owner 1610 */ 1611 function setUpgradeabilityOwner(address newUpgradeabilityOwner) internal { 1612 _upgradeabilityOwner = newUpgradeabilityOwner; 1613 } 1614 1615 /** 1616 * @dev Tells the address of the current implementation 1617 * @return address of the current implementation 1618 */ 1619 function implementation() public view returns (address) { 1620 return _implementation; 1621 } 1622 1623 /** 1624 * @dev Tells the proxy type (EIP 897) 1625 * @return Proxy type, 2 for forwarding proxy 1626 */ 1627 function proxyType() public pure returns (uint256 proxyTypeId) { 1628 return 2; 1629 } 1630 } 1631 1632 contract AuthenticatedProxy is TokenRecipient, OwnedUpgradeabilityStorage { 1633 1634 /* Whether initialized. */ 1635 bool initialized = false; 1636 1637 /* Address which owns this proxy. */ 1638 address public user; 1639 1640 /* Associated registry with contract authentication information. */ 1641 ProxyRegistry public registry; 1642 1643 /* Whether access has been revoked. */ 1644 bool public revoked; 1645 1646 /* Delegate call could be used to atomically transfer multiple assets owned by the proxy contract with one order. */ 1647 enum HowToCall { Call, DelegateCall } 1648 1649 /* Event fired when the proxy access is revoked or unrevoked. */ 1650 event Revoked(bool revoked); 1651 1652 /** 1653 * Initialize an AuthenticatedProxy 1654 * 1655 * @param addrUser Address of user on whose behalf this proxy will act 1656 * @param addrRegistry Address of ProxyRegistry contract which will manage this proxy 1657 */ 1658 function initialize (address addrUser, ProxyRegistry addrRegistry) 1659 public 1660 { 1661 require(!initialized); 1662 initialized = true; 1663 user = addrUser; 1664 registry = addrRegistry; 1665 } 1666 1667 /** 1668 * Set the revoked flag (allows a user to revoke ProxyRegistry access) 1669 * 1670 * @dev Can be called by the user only 1671 * @param revoke Whether or not to revoke access 1672 */ 1673 function setRevoke(bool revoke) 1674 public 1675 { 1676 require(msg.sender == user); 1677 revoked = revoke; 1678 emit Revoked(revoke); 1679 } 1680 1681 /** 1682 * Execute a message call from the proxy contract 1683 * 1684 * @dev Can be called by the user, or by a contract authorized by the registry as long as the user has not revoked access 1685 * @param dest Address to which the call will be sent 1686 * @param howToCall Which kind of call to make 1687 * @param calldata Calldata to send 1688 * @return Result of the call (success or failure) 1689 */ 1690 function proxy(address dest, HowToCall howToCall, bytes calldata) 1691 public 1692 returns (bool result) 1693 { 1694 require(msg.sender == user || (!revoked && registry.contracts(msg.sender))); 1695 if (howToCall == HowToCall.Call) { 1696 result = dest.call(calldata); 1697 } else if (howToCall == HowToCall.DelegateCall) { 1698 result = dest.delegatecall(calldata); 1699 } 1700 return result; 1701 } 1702 1703 /** 1704 * Execute a message call and assert success 1705 * 1706 * @dev Same functionality as `proxy`, just asserts the return value 1707 * @param dest Address to which the call will be sent 1708 * @param howToCall What kind of call to make 1709 * @param calldata Calldata to send 1710 */ 1711 function proxyAssert(address dest, HowToCall howToCall, bytes calldata) 1712 public 1713 { 1714 require(proxy(dest, howToCall, calldata)); 1715 } 1716 1717 } 1718 1719 contract Proxy { 1720 1721 /** 1722 * @dev Tells the address of the implementation where every call will be delegated. 1723 * @return address of the implementation to which it will be delegated 1724 */ 1725 function implementation() public view returns (address); 1726 1727 /** 1728 * @dev Tells the type of proxy (EIP 897) 1729 * @return Type of proxy, 2 for upgradeable proxy 1730 */ 1731 function proxyType() public pure returns (uint256 proxyTypeId); 1732 1733 /** 1734 * @dev Fallback function allowing to perform a delegatecall to the given implementation. 1735 * This function will return whatever the implementation call returns 1736 */ 1737 function () payable public { 1738 address _impl = implementation(); 1739 require(_impl != address(0)); 1740 1741 assembly { 1742 let ptr := mload(0x40) 1743 calldatacopy(ptr, 0, calldatasize) 1744 let result := delegatecall(gas, _impl, ptr, calldatasize, 0, 0) 1745 let size := returndatasize 1746 returndatacopy(ptr, 0, size) 1747 1748 switch result 1749 case 0 { revert(ptr, size) } 1750 default { return(ptr, size) } 1751 } 1752 } 1753 } 1754 1755 contract OwnedUpgradeabilityProxy is Proxy, OwnedUpgradeabilityStorage { 1756 /** 1757 * @dev Event to show ownership has been transferred 1758 * @param previousOwner representing the address of the previous owner 1759 * @param newOwner representing the address of the new owner 1760 */ 1761 event ProxyOwnershipTransferred(address previousOwner, address newOwner); 1762 1763 /** 1764 * @dev This event will be emitted every time the implementation gets upgraded 1765 * @param implementation representing the address of the upgraded implementation 1766 */ 1767 event Upgraded(address indexed implementation); 1768 1769 /** 1770 * @dev Upgrades the implementation address 1771 * @param implementation representing the address of the new implementation to be set 1772 */ 1773 function _upgradeTo(address implementation) internal { 1774 require(_implementation != implementation); 1775 _implementation = implementation; 1776 emit Upgraded(implementation); 1777 } 1778 1779 /** 1780 * @dev Throws if called by any account other than the owner. 1781 */ 1782 modifier onlyProxyOwner() { 1783 require(msg.sender == proxyOwner()); 1784 _; 1785 } 1786 1787 /** 1788 * @dev Tells the address of the proxy owner 1789 * @return the address of the proxy owner 1790 */ 1791 function proxyOwner() public view returns (address) { 1792 return upgradeabilityOwner(); 1793 } 1794 1795 /** 1796 * @dev Allows the current owner to transfer control of the contract to a newOwner. 1797 * @param newOwner The address to transfer ownership to. 1798 */ 1799 function transferProxyOwnership(address newOwner) public onlyProxyOwner { 1800 require(newOwner != address(0)); 1801 emit ProxyOwnershipTransferred(proxyOwner(), newOwner); 1802 setUpgradeabilityOwner(newOwner); 1803 } 1804 1805 /** 1806 * @dev Allows the upgradeability owner to upgrade the current implementation of the proxy. 1807 * @param implementation representing the address of the new implementation to be set. 1808 */ 1809 function upgradeTo(address implementation) public onlyProxyOwner { 1810 _upgradeTo(implementation); 1811 } 1812 1813 /** 1814 * @dev Allows the upgradeability owner to upgrade the current implementation of the proxy 1815 * and delegatecall the new implementation for initialization. 1816 * @param implementation representing the address of the new implementation to be set. 1817 * @param data represents the msg.data to bet sent in the low level call. This parameter may include the function 1818 * signature of the implementation to be called with the needed payload 1819 */ 1820 function upgradeToAndCall(address implementation, bytes data) payable public onlyProxyOwner { 1821 upgradeTo(implementation); 1822 require(address(this).delegatecall(data)); 1823 } 1824 } 1825 1826 contract OwnableDelegateProxy is OwnedUpgradeabilityProxy { 1827 1828 constructor(address owner, address initialImplementation, bytes calldata) 1829 public 1830 { 1831 setUpgradeabilityOwner(owner); 1832 _upgradeTo(initialImplementation); 1833 require(initialImplementation.delegatecall(calldata)); 1834 } 1835 1836 }