ETH Price: $2,431.62 (-2.92%)

Contract Diff Checker

Contract Name:
Ticket

Contract Source Code:

File 1 of 1 : Ticket

pragma solidity ^0.5.0;

contract IERC721 {
  event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
  event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
  event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

  function balanceOf(address owner) public view returns (uint256 balance);
  function ownerOf(uint256 tokenId) public view returns (address owner);

  function transferFrom(address from, address to, uint256 tokenId) public returns (bool);
  function safeTransferFrom(address from, address to, uint256 tokenId) public returns (bool);
  function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) public returns (bool);

  function approve(address to, uint256 tokenId) public;
  function getApproved(uint256 tokenId) public view returns (address operator);
  function setApprovalForAll(address operator, bool _approved) public;
  function isApprovedForAll(address owner, address operator) public view returns (bool);
}

contract IERC721Receiver {
  function onERC721Received(address operator, address from, uint256 tokenId, bytes memory data) public returns (bytes4);
}

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 * Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/introspection/IERC165.sol
 */
interface IERC165 {
  /**
   * @dev Returns true if this contract implements the interface defined by
   * `interfaceId`. See the corresponding
   * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
   * to learn more about how these ids are created.
   *
   * This function call must use less than 30 000 gas.
   */
  function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts may inherit from this and call {_registerInterface} to declare
 * their support of an interface.
 * Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/introspection/ERC165.sol
 */
contract ERC165 is IERC165 {
  /*
   * bytes4(keccak256('supportsInterface(bytes4)')) == 0x01ffc9a7
   */
  bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7;

  /**
   * @dev Mapping of interface ids to whether or not it's supported.
   */
  mapping(bytes4 => bool) private _supportedInterfaces;

  constructor () internal {
    // Derived contracts need only register support for their own interfaces,
    // we register support for ERC165 itself here
    registerInterface(_INTERFACE_ID_ERC165);
  }

  /**
   * @dev See {IERC165-supportsInterface}.
   *
   * Time complexity O(1), guaranteed to always use less than 30 000 gas.
   */
  function supportsInterface(bytes4 interfaceId) external view returns (bool) {
    return _supportedInterfaces[interfaceId];
  }

  /**
   * @dev Registers the contract as an implementer of the interface defined by
   * `interfaceId`. Support of the actual ERC165 interface is automatic and
   * registering its interface id is not required.
   *
   * See {IERC165-supportsInterface}.
   *
   * Requirements:
   *
   * - `interfaceId` cannot be the ERC165 invalid interface (`0xffffffff`).
   */
  function registerInterface(bytes4 interfaceId) internal {
    require(interfaceId != 0xffffffff, "ERC165: invalid interface id");
    _supportedInterfaces[interfaceId] = true;
  }
}

library SafeMath {
  function mul(uint256 _a, uint256 _b) internal pure returns (uint256) {
    if (_a == 0) {
      return 0;
    }

    uint256 c = _a * _b;
    require(c / _a == _b, "Invalid argument.");

    return c;
  }

  function div(uint256 _a, uint256 _b) internal pure returns (uint256) {
    require(_b > 0, "Invalid argument.");
    uint256 c = _a / _b;

    return c;
  }

  function sub(uint256 _a, uint256 _b) internal pure returns (uint256) {
    require(_b <= _a, "Invalid argument.");
    uint256 c = _a - _b;

    return c;
  }

  function add(uint256 _a, uint256 _b) internal pure returns (uint256) {
    uint256 c = _a + _b;
    require(c >= _a, "Invalid argument.");

    return c;
  }

  function mod(uint256 a, uint256 b) internal pure returns (uint256) {
    require(b != 0, "Invalid argument.");
    return a % b;
  }
}

contract Ownable {
  address payable private _owner;

  event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

  modifier onlyOwner() {
    require(msg.sender == _owner, "Forbidden");
    _;
  }

  constructor() public {
    _owner = msg.sender;
  }

  function owner() public view returns (address payable) {
    return _owner;
  }

  function transferOwnership(address payable newOwner) public onlyOwner {
    require(newOwner != address(0), "Non-zero address required.");
    emit OwnershipTransferred(_owner, newOwner);
    _owner = newOwner;
  }
}

contract Ticket is ERC165, IERC721, Ownable {
  using SafeMath for uint256;

  mapping(uint256 => bool) private _redemptions;
  mapping(address => bool) private _operators;
  mapping(uint256 => address) private _tokenOwner;
  mapping(uint256 => address) private _tokenApprovals;
  mapping(address => uint256) private _ownedTokensCount;
  mapping(address => uint256[]) private _ownedTokens;
  mapping(uint256 => uint256) private _ownedTokensIndex;
  mapping(address => mapping(address => bool)) private _operatorApprovals;
  uint256[] private _allTokens;
  mapping(uint256 => uint256) private _allTokensIndex;
  bool private _paused;
  string private _name;
  string private _symbol;
  mapping(uint256 => string) private _tokenURIs;

  event TokenRedeemed(uint256 tokenID);

  modifier whenNotPaused() {
    require(!_paused, "contract is paused");
    _;
  }

  modifier onlyOperator() {
    require(_operators[msg.sender] == true, "Forbidden");
    _;
  }

  constructor(string memory name, string memory symbol) public {
    _name = name;
    _symbol = symbol;

    registerInterface(0x80ac58cd);
    registerInterface(0x5b5e139f);
    registerInterface(0x780e9d63);

    _operators[msg.sender] = true;
    _paused = true;
  }

  function name() public view returns (string memory) {
    return _name;
  }

  function symbol() public view returns (string memory) {
    return _symbol;
  }

  function tokenURI(uint256 tokenId) public view returns (string memory) {
    require(exists(tokenId), "URI query for nonexistent token");
    return _tokenURIs[tokenId];
  }

  function balanceOf(address owner) public view returns (uint256) {
    return _ownedTokensCount[owner];
  }

  function ownerOf(uint256 tokenId) public view returns (address) {
    address owner = _tokenOwner[tokenId];
    return owner;
  }

  function paused() public view returns (bool) {
    return _paused;
  }

  function totalSupply() public view returns (uint256) {
    return _allTokens.length;
  }

  function tokenOfOwnerByIndex(address owner, uint256 index) public view returns (uint256 tokenId) {
    require(index < balanceOf(owner), "owner index out of bounds");
    return _ownedTokens[owner][index];
  }

  function tokenByIndex(uint256 index) public view returns (uint256) {
    require(index < totalSupply(), "global index out of bounds");
    return _allTokens[index];
  }

  function transferFrom(address from, address to, uint256 tokenId) public whenNotPaused returns (bool) {
    require(ownerOf(tokenId) == from, "transfer of token that is not own");
    require(to != address(0), "transfer to the zero address");
    require(isApprovedOrOwner(msg.sender, tokenId), "transfer caller is not owner nor approved");

    clearApproval(tokenId);

    _ownedTokensCount[from] = _ownedTokensCount[from].sub(1);
    _ownedTokensCount[to] = _ownedTokensCount[to].add(1);

    _tokenOwner[tokenId] = to;

    removeTokenFromOwnerEnumeration(from, tokenId);
    addTokenToOwnerEnumeration(to, tokenId);

    emit Transfer(from, to, tokenId);
    return true;
  }

  function safeTransferFrom(address from, address to, uint256 tokenId) public returns (bool) {
    return safeTransferFrom(from, to, tokenId, "");
  }

  function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) public returns (bool) {
    require(checkOnERC721Received(from, to, tokenId, data), "transfer to non ERC721Receiver implementer");
    return transferFrom(from, to, tokenId);
  }

  function approve(address to, uint256 tokenId) public whenNotPaused {
    address owner = ownerOf(tokenId);
    require(to != owner, "approval to current owner");
    require(msg.sender == owner || isApprovedForAll(owner, msg.sender), "approve caller is not owner nor approved for all");
    _tokenApprovals[tokenId] = to;
    emit Approval(owner, to, tokenId);
  }

  function getApproved(uint256 tokenId) public view returns (address) {
    require(exists(tokenId), "approved query for nonexistent token");
    return _tokenApprovals[tokenId];
  }

  function setApprovalForAll(address to, bool approved) public whenNotPaused {
    require(to != msg.sender, "approve to caller");
    _operatorApprovals[msg.sender][to] = approved;
    emit ApprovalForAll(msg.sender, to, approved);
  }

  function isApprovedForAll(address owner, address operator) public view returns (bool) {
    return _operatorApprovals[owner][operator];
  }

  function exists(uint256 tokenId) public view returns (bool) {
    address owner = _tokenOwner[tokenId];
    return owner != address(0);
  }

  function mint(address to, uint256 tokenId) public onlyOwner returns (bool) {
    require(to != address(0), "mint to the zero address");
    require(!exists(tokenId), "token already minted");

    _tokenOwner[tokenId] = to;
    _ownedTokensCount[to] = _ownedTokensCount[to].add(1);

    addTokenToOwnerEnumeration(to, tokenId);
    addTokenToAllTokensEnumeration(tokenId);

    emit Transfer(address(0), to, tokenId);
    return true;
  }

  function mintWithTokenURI(address to, uint256 tokenId, string memory uri) public onlyOwner returns (bool) {
    mint(to, tokenId);
    _tokenURIs[tokenId] = uri;
    return true;
  }

  function burn(uint256 tokenId) public whenNotPaused returns (bool) {
    require(isApprovedOrOwner(msg.sender, tokenId), "caller is not owner nor approved");

    clearApproval(tokenId);

    _ownedTokensCount[msg.sender] = _ownedTokensCount[msg.sender].sub(1);
    _tokenOwner[tokenId] = address(0);

    if (bytes(_tokenURIs[tokenId]).length != 0) {
      delete _tokenURIs[tokenId];
    }

    removeTokenFromOwnerEnumeration(msg.sender, tokenId);
    _ownedTokensIndex[tokenId] = 0;
    removeTokenFromAllTokensEnumeration(tokenId);

    emit Transfer(msg.sender, address(0), tokenId);

    return true;
  }

  function pause() public onlyOwner {
    _paused = true;
  }

  function unpause() public onlyOwner {
    _paused = false;
  }

  function addOperator(address operator) public onlyOwner {
    _operators[operator] = true;
  }

  function isOperator(address user) public view returns (bool) {
    return _operators[user];
  }

  function removeOperator(address operator) public onlyOwner {
    delete _operators[operator];
  }

  function isRedeemed(uint256 tokenID) public view returns (bool) {
    return _redemptions[tokenID];
  }

  function getSignerAndOwner(uint256 tokenID, bytes memory signature) public view returns (address, address) {
    bytes32 hash = keccak256(abi.encodePacked(_tokenURIs[tokenID]));

    bytes memory prefix = "\x19Ethereum Signed Message:\n32";
    hash = keccak256(abi.encodePacked(prefix, hash));

    address signer = recover(hash,signature);
    address tokenOwner = ownerOf(tokenID);

    return (signer, tokenOwner);
  }

  function markTokenAsRedeemed(uint256 tokenID, bytes memory signature) public onlyOperator {
    require(!_redemptions[tokenID], "Token already redeemed");

    (address signer, address tokenOwner) = getSignerAndOwner(tokenID, signature);

    require(signer == tokenOwner, "Not signed by token owner");

    _redemptions[tokenID] = true;
    emit TokenRedeemed(tokenID);
  }

  function isApprovedOrOwner(address spender, uint256 tokenId) private view returns (bool) {
    require(exists(tokenId), "operator query for nonexistent token");
    address owner = ownerOf(tokenId);
    return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender));
  }

  function checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory _data) private returns (bool) {
    if (!isContract(to)) {
      return true;
    }

    bytes4 retval = IERC721Receiver(to).onERC721Received(msg.sender, from, tokenId, _data);
    return (retval == 0x150b7a02);
  }

  function clearApproval(uint256 tokenId) private {
    if (_tokenApprovals[tokenId] != address(0)) {
      _tokenApprovals[tokenId] = address(0);
    }
  }

  function isContract(address account) private view returns (bool) {
    uint256 size = 0;
    // solium-disable-next-line security/no-inline-assembly
    assembly { size := extcodesize(account) }
    return size > 0;
  }

  function addTokenToOwnerEnumeration(address to, uint256 tokenId) private {
    _ownedTokensIndex[tokenId] = _ownedTokens[to].length;
    _ownedTokens[to].push(tokenId);
  }

  function addTokenToAllTokensEnumeration(uint256 tokenId) private {
    _allTokensIndex[tokenId] = _allTokens.length;
    _allTokens.push(tokenId);
  }

  function removeTokenFromOwnerEnumeration(address from, uint256 tokenId) private {
    uint256 lastTokenIndex = _ownedTokens[from].length.sub(1);
    uint256 tokenIndex = _ownedTokensIndex[tokenId];

    if (tokenIndex != lastTokenIndex) {
        uint256 lastTokenId = _ownedTokens[from][lastTokenIndex];

        _ownedTokens[from][tokenIndex] = lastTokenId;
        _ownedTokensIndex[lastTokenId] = tokenIndex;
    }

    _ownedTokens[from].pop();
  }

  function removeTokenFromAllTokensEnumeration(uint256 tokenId) private {
    uint256 lastTokenIndex = _allTokens.length.sub(1);
    uint256 tokenIndex = _allTokensIndex[tokenId];

    uint256 lastTokenId = _allTokens[lastTokenIndex];

    _allTokens[tokenIndex] = lastTokenId;
    _allTokensIndex[lastTokenId] = tokenIndex;

    _allTokens.pop();
    _allTokensIndex[tokenId] = 0;
  }

  function recover(bytes32 hash, bytes memory signature) public pure returns (address) {
    bytes32 r;
    bytes32 s;
    uint8 v;

    //Check the signature length
    if (signature.length != 65) {
      return (address(0));
    }

    // Divide the signature in r, s and v variables
    assembly {
      r := mload(add(signature, 32))
      s := mload(add(signature, 64))
      v := byte(0, mload(add(signature, 96)))
    }

    // Version of signature should be 27 or 28, but 0 and 1 are also possible versions
    if (v < 27) {
      v += 27;
    }

    // If the version is correct return the signer address
    if (v != 27 && v != 28) {
      return (address(0));
    } else {
      return ecrecover(hash, v, r, s);
    }
  }

  function destroy() public onlyOwner {
    selfdestruct(owner());
  }
}

Please enter a contract address above to load the contract details and source code.

Context size (optional):