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 }