github.com/diadata-org/diadata@v1.4.593/config/nftContracts/cryptokittiesauction/cryptokittiesauction.sol (about)

     1  /**
     2   *Submitted for verification at Etherscan.io on 2017-11-28
     3  */
     4  
     5  pragma solidity ^0.4.11;
     6  
     7  
     8  /**
     9   * @title Ownable
    10   * @dev The Ownable contract has an owner address, and provides basic authorization control
    11   * functions, this simplifies the implementation of "user permissions".
    12   */
    13  contract Ownable {
    14    address public owner;
    15  
    16  
    17    /**
    18     * @dev The Ownable constructor sets the original `owner` of the contract to the sender
    19     * account.
    20     */
    21    function Ownable() {
    22      owner = msg.sender;
    23    }
    24  
    25  
    26    /**
    27     * @dev Throws if called by any account other than the owner.
    28     */
    29    modifier onlyOwner() {
    30      require(msg.sender == owner);
    31      _;
    32    }
    33  
    34  
    35    /**
    36     * @dev Allows the current owner to transfer control of the contract to a newOwner.
    37     * @param newOwner The address to transfer ownership to.
    38     */
    39    function transferOwnership(address newOwner) onlyOwner {
    40      if (newOwner != address(0)) {
    41        owner = newOwner;
    42      }
    43    }
    44  
    45  }
    46  
    47  
    48  
    49  /// @title Interface for contracts conforming to ERC-721: Non-Fungible Tokens
    50  /// @author Dieter Shirley <dete@axiomzen.co> (https://github.com/dete)
    51  contract ERC721 {
    52      // Required methods
    53      function totalSupply() public view returns (uint256 total);
    54      function balanceOf(address _owner) public view returns (uint256 balance);
    55      function ownerOf(uint256 _tokenId) external view returns (address owner);
    56      function approve(address _to, uint256 _tokenId) external;
    57      function transfer(address _to, uint256 _tokenId) external;
    58      function transferFrom(address _from, address _to, uint256 _tokenId) external;
    59  
    60      // Events
    61      event Transfer(address from, address to, uint256 tokenId);
    62      event Approval(address owner, address approved, uint256 tokenId);
    63  
    64      // Optional
    65      // function name() public view returns (string name);
    66      // function symbol() public view returns (string symbol);
    67      // function tokensOfOwner(address _owner) external view returns (uint256[] tokenIds);
    68      // function tokenMetadata(uint256 _tokenId, string _preferredTransport) public view returns (string infoUrl);
    69  
    70      // ERC-165 Compatibility (https://github.com/ethereum/EIPs/issues/165)
    71      function supportsInterface(bytes4 _interfaceID) external view returns (bool);
    72  }
    73  
    74  
    75  
    76  
    77  
    78  
    79  
    80  
    81  
    82  /// @title Auction Core
    83  /// @dev Contains models, variables, and internal methods for the auction.
    84  /// @notice We omit a fallback function to prevent accidental sends to this contract.
    85  contract ClockAuctionBase {
    86  
    87      // Represents an auction on an NFT
    88      struct Auction {
    89          // Current owner of NFT
    90          address seller;
    91          // Price (in wei) at beginning of auction
    92          uint128 startingPrice;
    93          // Price (in wei) at end of auction
    94          uint128 endingPrice;
    95          // Duration (in seconds) of auction
    96          uint64 duration;
    97          // Time when auction started
    98          // NOTE: 0 if this auction has been concluded
    99          uint64 startedAt;
   100      }
   101  
   102      // Reference to contract tracking NFT ownership
   103      ERC721 public nonFungibleContract;
   104  
   105      // Cut owner takes on each auction, measured in basis points (1/100 of a percent).
   106      // Values 0-10,000 map to 0%-100%
   107      uint256 public ownerCut;
   108  
   109      // Map from token ID to their corresponding auction.
   110      mapping (uint256 => Auction) tokenIdToAuction;
   111  
   112      event AuctionCreated(uint256 tokenId, uint256 startingPrice, uint256 endingPrice, uint256 duration);
   113      event AuctionSuccessful(uint256 tokenId, uint256 totalPrice, address winner);
   114      event AuctionCancelled(uint256 tokenId);
   115  
   116      /// @dev Returns true if the claimant owns the token.
   117      /// @param _claimant - Address claiming to own the token.
   118      /// @param _tokenId - ID of token whose ownership to verify.
   119      function _owns(address _claimant, uint256 _tokenId) internal view returns (bool) {
   120          return (nonFungibleContract.ownerOf(_tokenId) == _claimant);
   121      }
   122  
   123      /// @dev Escrows the NFT, assigning ownership to this contract.
   124      /// Throws if the escrow fails.
   125      /// @param _owner - Current owner address of token to escrow.
   126      /// @param _tokenId - ID of token whose approval to verify.
   127      function _escrow(address _owner, uint256 _tokenId) internal {
   128          // it will throw if transfer fails
   129          nonFungibleContract.transferFrom(_owner, this, _tokenId);
   130      }
   131  
   132      /// @dev Transfers an NFT owned by this contract to another address.
   133      /// Returns true if the transfer succeeds.
   134      /// @param _receiver - Address to transfer NFT to.
   135      /// @param _tokenId - ID of token to transfer.
   136      function _transfer(address _receiver, uint256 _tokenId) internal {
   137          // it will throw if transfer fails
   138          nonFungibleContract.transfer(_receiver, _tokenId);
   139      }
   140  
   141      /// @dev Adds an auction to the list of open auctions. Also fires the
   142      ///  AuctionCreated event.
   143      /// @param _tokenId The ID of the token to be put on auction.
   144      /// @param _auction Auction to add.
   145      function _addAuction(uint256 _tokenId, Auction _auction) internal {
   146          // Require that all auctions have a duration of
   147          // at least one minute. (Keeps our math from getting hairy!)
   148          require(_auction.duration >= 1 minutes);
   149  
   150          tokenIdToAuction[_tokenId] = _auction;
   151  
   152          AuctionCreated(
   153              uint256(_tokenId),
   154              uint256(_auction.startingPrice),
   155              uint256(_auction.endingPrice),
   156              uint256(_auction.duration)
   157          );
   158      }
   159  
   160      /// @dev Cancels an auction unconditionally.
   161      function _cancelAuction(uint256 _tokenId, address _seller) internal {
   162          _removeAuction(_tokenId);
   163          _transfer(_seller, _tokenId);
   164          AuctionCancelled(_tokenId);
   165      }
   166  
   167      /// @dev Computes the price and transfers winnings.
   168      /// Does NOT transfer ownership of token.
   169      function _bid(uint256 _tokenId, uint256 _bidAmount)
   170          internal
   171          returns (uint256)
   172      {
   173          // Get a reference to the auction struct
   174          Auction storage auction = tokenIdToAuction[_tokenId];
   175  
   176          // Explicitly check that this auction is currently live.
   177          // (Because of how Ethereum mappings work, we can't just count
   178          // on the lookup above failing. An invalid _tokenId will just
   179          // return an auction object that is all zeros.)
   180          require(_isOnAuction(auction));
   181  
   182          // Check that the bid is greater than or equal to the current price
   183          uint256 price = _currentPrice(auction);
   184          require(_bidAmount >= price);
   185  
   186          // Grab a reference to the seller before the auction struct
   187          // gets deleted.
   188          address seller = auction.seller;
   189  
   190          // The bid is good! Remove the auction before sending the fees
   191          // to the sender so we can't have a reentrancy attack.
   192          _removeAuction(_tokenId);
   193  
   194          // Transfer proceeds to seller (if there are any!)
   195          if (price > 0) {
   196              // Calculate the auctioneer's cut.
   197              // (NOTE: _computeCut() is guaranteed to return a
   198              // value <= price, so this subtraction can't go negative.)
   199              uint256 auctioneerCut = _computeCut(price);
   200              uint256 sellerProceeds = price - auctioneerCut;
   201  
   202              // NOTE: Doing a transfer() in the middle of a complex
   203              // method like this is generally discouraged because of
   204              // reentrancy attacks and DoS attacks if the seller is
   205              // a contract with an invalid fallback function. We explicitly
   206              // guard against reentrancy attacks by removing the auction
   207              // before calling transfer(), and the only thing the seller
   208              // can DoS is the sale of their own asset! (And if it's an
   209              // accident, they can call cancelAuction(). )
   210              seller.transfer(sellerProceeds);
   211          }
   212  
   213          // Calculate any excess funds included with the bid. If the excess
   214          // is anything worth worrying about, transfer it back to bidder.
   215          // NOTE: We checked above that the bid amount is greater than or
   216          // equal to the price so this cannot underflow.
   217          uint256 bidExcess = _bidAmount - price;
   218  
   219          // Return the funds. Similar to the previous transfer, this is
   220          // not susceptible to a re-entry attack because the auction is
   221          // removed before any transfers occur.
   222          msg.sender.transfer(bidExcess);
   223  
   224          // Tell the world!
   225          AuctionSuccessful(_tokenId, price, msg.sender);
   226  
   227          return price;
   228      }
   229  
   230      /// @dev Removes an auction from the list of open auctions.
   231      /// @param _tokenId - ID of NFT on auction.
   232      function _removeAuction(uint256 _tokenId) internal {
   233          delete tokenIdToAuction[_tokenId];
   234      }
   235  
   236      /// @dev Returns true if the NFT is on auction.
   237      /// @param _auction - Auction to check.
   238      function _isOnAuction(Auction storage _auction) internal view returns (bool) {
   239          return (_auction.startedAt > 0);
   240      }
   241  
   242      /// @dev Returns current price of an NFT on auction. Broken into two
   243      ///  functions (this one, that computes the duration from the auction
   244      ///  structure, and the other that does the price computation) so we
   245      ///  can easily test that the price computation works correctly.
   246      function _currentPrice(Auction storage _auction)
   247          internal
   248          view
   249          returns (uint256)
   250      {
   251          uint256 secondsPassed = 0;
   252  
   253          // A bit of insurance against negative values (or wraparound).
   254          // Probably not necessary (since Ethereum guarnatees that the
   255          // now variable doesn't ever go backwards).
   256          if (now > _auction.startedAt) {
   257              secondsPassed = now - _auction.startedAt;
   258          }
   259  
   260          return _computeCurrentPrice(
   261              _auction.startingPrice,
   262              _auction.endingPrice,
   263              _auction.duration,
   264              secondsPassed
   265          );
   266      }
   267  
   268      /// @dev Computes the current price of an auction. Factored out
   269      ///  from _currentPrice so we can run extensive unit tests.
   270      ///  When testing, make this function public and turn on
   271      ///  `Current price computation` test suite.
   272      function _computeCurrentPrice(
   273          uint256 _startingPrice,
   274          uint256 _endingPrice,
   275          uint256 _duration,
   276          uint256 _secondsPassed
   277      )
   278          internal
   279          pure
   280          returns (uint256)
   281      {
   282          // NOTE: We don't use SafeMath (or similar) in this function because
   283          //  all of our public functions carefully cap the maximum values for
   284          //  time (at 64-bits) and currency (at 128-bits). _duration is
   285          //  also known to be non-zero (see the require() statement in
   286          //  _addAuction())
   287          if (_secondsPassed >= _duration) {
   288              // We've reached the end of the dynamic pricing portion
   289              // of the auction, just return the end price.
   290              return _endingPrice;
   291          } else {
   292              // Starting price can be higher than ending price (and often is!), so
   293              // this delta can be negative.
   294              int256 totalPriceChange = int256(_endingPrice) - int256(_startingPrice);
   295  
   296              // This multiplication can't overflow, _secondsPassed will easily fit within
   297              // 64-bits, and totalPriceChange will easily fit within 128-bits, their product
   298              // will always fit within 256-bits.
   299              int256 currentPriceChange = totalPriceChange * int256(_secondsPassed) / int256(_duration);
   300  
   301              // currentPriceChange can be negative, but if so, will have a magnitude
   302              // less that _startingPrice. Thus, this result will always end up positive.
   303              int256 currentPrice = int256(_startingPrice) + currentPriceChange;
   304  
   305              return uint256(currentPrice);
   306          }
   307      }
   308  
   309      /// @dev Computes owner's cut of a sale.
   310      /// @param _price - Sale price of NFT.
   311      function _computeCut(uint256 _price) internal view returns (uint256) {
   312          // NOTE: We don't use SafeMath (or similar) in this function because
   313          //  all of our entry functions carefully cap the maximum values for
   314          //  currency (at 128-bits), and ownerCut <= 10000 (see the require()
   315          //  statement in the ClockAuction constructor). The result of this
   316          //  function is always guaranteed to be <= _price.
   317          return _price * ownerCut / 10000;
   318      }
   319  
   320  }
   321  
   322  
   323  
   324  
   325  
   326  
   327  
   328  /**
   329   * @title Pausable
   330   * @dev Base contract which allows children to implement an emergency stop mechanism.
   331   */
   332  contract Pausable is Ownable {
   333    event Pause();
   334    event Unpause();
   335  
   336    bool public paused = false;
   337  
   338  
   339    /**
   340     * @dev modifier to allow actions only when the contract IS paused
   341     */
   342    modifier whenNotPaused() {
   343      require(!paused);
   344      _;
   345    }
   346  
   347    /**
   348     * @dev modifier to allow actions only when the contract IS NOT paused
   349     */
   350    modifier whenPaused {
   351      require(paused);
   352      _;
   353    }
   354  
   355    /**
   356     * @dev called by the owner to pause, triggers stopped state
   357     */
   358    function pause() onlyOwner whenNotPaused returns (bool) {
   359      paused = true;
   360      Pause();
   361      return true;
   362    }
   363  
   364    /**
   365     * @dev called by the owner to unpause, returns to normal state
   366     */
   367    function unpause() onlyOwner whenPaused returns (bool) {
   368      paused = false;
   369      Unpause();
   370      return true;
   371    }
   372  }
   373  
   374  
   375  /// @title Clock auction for non-fungible tokens.
   376  /// @notice We omit a fallback function to prevent accidental sends to this contract.
   377  contract ClockAuction is Pausable, ClockAuctionBase {
   378  
   379      /// @dev The ERC-165 interface signature for ERC-721.
   380      ///  Ref: https://github.com/ethereum/EIPs/issues/165
   381      ///  Ref: https://github.com/ethereum/EIPs/issues/721
   382      bytes4 constant InterfaceSignature_ERC721 = bytes4(0x9a20483d);
   383  
   384      /// @dev Constructor creates a reference to the NFT ownership contract
   385      ///  and verifies the owner cut is in the valid range.
   386      /// @param _nftAddress - address of a deployed contract implementing
   387      ///  the Nonfungible Interface.
   388      /// @param _cut - percent cut the owner takes on each auction, must be
   389      ///  between 0-10,000.
   390      function ClockAuction(address _nftAddress, uint256 _cut) public {
   391          require(_cut <= 10000);
   392          ownerCut = _cut;
   393  
   394          ERC721 candidateContract = ERC721(_nftAddress);
   395          require(candidateContract.supportsInterface(InterfaceSignature_ERC721));
   396          nonFungibleContract = candidateContract;
   397      }
   398  
   399      /// @dev Remove all Ether from the contract, which is the owner's cuts
   400      ///  as well as any Ether sent directly to the contract address.
   401      ///  Always transfers to the NFT contract, but can be called either by
   402      ///  the owner or the NFT contract.
   403      function withdrawBalance() external {
   404          address nftAddress = address(nonFungibleContract);
   405  
   406          require(
   407              msg.sender == owner ||
   408              msg.sender == nftAddress
   409          );
   410          // We are using this boolean method to make sure that even if one fails it will still work
   411          bool res = nftAddress.send(this.balance);
   412      }
   413  
   414      /// @dev Creates and begins a new auction.
   415      /// @param _tokenId - ID of token to auction, sender must be owner.
   416      /// @param _startingPrice - Price of item (in wei) at beginning of auction.
   417      /// @param _endingPrice - Price of item (in wei) at end of auction.
   418      /// @param _duration - Length of time to move between starting
   419      ///  price and ending price (in seconds).
   420      /// @param _seller - Seller, if not the message sender
   421      function createAuction(
   422          uint256 _tokenId,
   423          uint256 _startingPrice,
   424          uint256 _endingPrice,
   425          uint256 _duration,
   426          address _seller
   427      )
   428          external
   429          whenNotPaused
   430      {
   431          // Sanity check that no inputs overflow how many bits we've allocated
   432          // to store them in the auction struct.
   433          require(_startingPrice == uint256(uint128(_startingPrice)));
   434          require(_endingPrice == uint256(uint128(_endingPrice)));
   435          require(_duration == uint256(uint64(_duration)));
   436  
   437          require(_owns(msg.sender, _tokenId));
   438          _escrow(msg.sender, _tokenId);
   439          Auction memory auction = Auction(
   440              _seller,
   441              uint128(_startingPrice),
   442              uint128(_endingPrice),
   443              uint64(_duration),
   444              uint64(now)
   445          );
   446          _addAuction(_tokenId, auction);
   447      }
   448  
   449      /// @dev Bids on an open auction, completing the auction and transferring
   450      ///  ownership of the NFT if enough Ether is supplied.
   451      /// @param _tokenId - ID of token to bid on.
   452      function bid(uint256 _tokenId)
   453          external
   454          payable
   455          whenNotPaused
   456      {
   457          // _bid will throw if the bid or funds transfer fails
   458          _bid(_tokenId, msg.value);
   459          _transfer(msg.sender, _tokenId);
   460      }
   461  
   462      /// @dev Cancels an auction that hasn't been won yet.
   463      ///  Returns the NFT to original owner.
   464      /// @notice This is a state-modifying function that can
   465      ///  be called while the contract is paused.
   466      /// @param _tokenId - ID of token on auction
   467      function cancelAuction(uint256 _tokenId)
   468          external
   469      {
   470          Auction storage auction = tokenIdToAuction[_tokenId];
   471          require(_isOnAuction(auction));
   472          address seller = auction.seller;
   473          require(msg.sender == seller);
   474          _cancelAuction(_tokenId, seller);
   475      }
   476  
   477      /// @dev Cancels an auction when the contract is paused.
   478      ///  Only the owner may do this, and NFTs are returned to
   479      ///  the seller. This should only be used in emergencies.
   480      /// @param _tokenId - ID of the NFT on auction to cancel.
   481      function cancelAuctionWhenPaused(uint256 _tokenId)
   482          whenPaused
   483          onlyOwner
   484          external
   485      {
   486          Auction storage auction = tokenIdToAuction[_tokenId];
   487          require(_isOnAuction(auction));
   488          _cancelAuction(_tokenId, auction.seller);
   489      }
   490  
   491      /// @dev Returns auction info for an NFT on auction.
   492      /// @param _tokenId - ID of NFT on auction.
   493      function getAuction(uint256 _tokenId)
   494          external
   495          view
   496          returns
   497      (
   498          address seller,
   499          uint256 startingPrice,
   500          uint256 endingPrice,
   501          uint256 duration,
   502          uint256 startedAt
   503      ) {
   504          Auction storage auction = tokenIdToAuction[_tokenId];
   505          require(_isOnAuction(auction));
   506          return (
   507              auction.seller,
   508              auction.startingPrice,
   509              auction.endingPrice,
   510              auction.duration,
   511              auction.startedAt
   512          );
   513      }
   514  
   515      /// @dev Returns the current price of an auction.
   516      /// @param _tokenId - ID of the token price we are checking.
   517      function getCurrentPrice(uint256 _tokenId)
   518          external
   519          view
   520          returns (uint256)
   521      {
   522          Auction storage auction = tokenIdToAuction[_tokenId];
   523          require(_isOnAuction(auction));
   524          return _currentPrice(auction);
   525      }
   526  
   527  }
   528  
   529  
   530  /// @title Clock auction modified for sale of kitties
   531  /// @notice We omit a fallback function to prevent accidental sends to this contract.
   532  contract SaleClockAuction is ClockAuction {
   533  
   534      // @dev Sanity check that allows us to ensure that we are pointing to the
   535      //  right auction in our setSaleAuctionAddress() call.
   536      bool public isSaleClockAuction = true;
   537      
   538      // Tracks last 5 sale price of gen0 kitty sales
   539      uint256 public gen0SaleCount;
   540      uint256[5] public lastGen0SalePrices;
   541  
   542      // Delegate constructor
   543      function SaleClockAuction(address _nftAddr, uint256 _cut) public
   544          ClockAuction(_nftAddr, _cut) {}
   545  
   546      /// @dev Creates and begins a new auction.
   547      /// @param _tokenId - ID of token to auction, sender must be owner.
   548      /// @param _startingPrice - Price of item (in wei) at beginning of auction.
   549      /// @param _endingPrice - Price of item (in wei) at end of auction.
   550      /// @param _duration - Length of auction (in seconds).
   551      /// @param _seller - Seller, if not the message sender
   552      function createAuction(
   553          uint256 _tokenId,
   554          uint256 _startingPrice,
   555          uint256 _endingPrice,
   556          uint256 _duration,
   557          address _seller
   558      )
   559          external
   560      {
   561          // Sanity check that no inputs overflow how many bits we've allocated
   562          // to store them in the auction struct.
   563          require(_startingPrice == uint256(uint128(_startingPrice)));
   564          require(_endingPrice == uint256(uint128(_endingPrice)));
   565          require(_duration == uint256(uint64(_duration)));
   566  
   567          require(msg.sender == address(nonFungibleContract));
   568          _escrow(_seller, _tokenId);
   569          Auction memory auction = Auction(
   570              _seller,
   571              uint128(_startingPrice),
   572              uint128(_endingPrice),
   573              uint64(_duration),
   574              uint64(now)
   575          );
   576          _addAuction(_tokenId, auction);
   577      }
   578  
   579      /// @dev Updates lastSalePrice if seller is the nft contract
   580      /// Otherwise, works the same as default bid method.
   581      function bid(uint256 _tokenId)
   582          external
   583          payable
   584      {
   585          // _bid verifies token ID size
   586          address seller = tokenIdToAuction[_tokenId].seller;
   587          uint256 price = _bid(_tokenId, msg.value);
   588          _transfer(msg.sender, _tokenId);
   589  
   590          // If not a gen0 auction, exit
   591          if (seller == address(nonFungibleContract)) {
   592              // Track gen0 sale prices
   593              lastGen0SalePrices[gen0SaleCount % 5] = price;
   594              gen0SaleCount++;
   595          }
   596      }
   597  
   598      function averageGen0SalePrice() external view returns (uint256) {
   599          uint256 sum = 0;
   600          for (uint256 i = 0; i < 5; i++) {
   601              sum += lastGen0SalePrices[i];
   602          }
   603          return sum / 5;
   604      }
   605  
   606  }