pragma solidity ^0.4.24; contract DSMath {
    function add(uint x, uint y) internal pure returns (uint z) {
        require((z = x + y) >= x, "ds-math-add-overflow");
    }
    function sub(uint x, uint y) internal pure returns (uint z) {
        require((z = x - y) <= x, "ds-math-sub-underflow");
    }
    function mul(uint x, uint y) internal pure returns (uint z) {
        require(y == 0 || (z = x * y) / y == x, "ds-math-mul-overflow");
    }

    function min(uint x, uint y) internal pure returns (uint z) {
        return x <= y ? x : y;
    }
    function max(uint x, uint y) internal pure returns (uint z) {
        return x >= y ? x : y;
    }
    function imin(int x, int y) internal pure returns (int z) {
        return x <= y ? x : y;
    }
    function imax(int x, int y) internal pure returns (int z) {
        return x >= y ? x : y;
    }

    uint constant WAD = 10 ** 18;
    uint constant RAY = 10 ** 27;

    function wmul(uint x, uint y) internal pure returns (uint z) {
        z = add(mul(x, y), WAD / 2) / WAD;
    }
    function rmul(uint x, uint y) internal pure returns (uint z) {
        z = add(mul(x, y), RAY / 2) / RAY;
    }
    function wdiv(uint x, uint y) internal pure returns (uint z) {
        z = add(mul(x, WAD), y / 2) / y;
    }
    function rdiv(uint x, uint y) internal pure returns (uint z) {
        z = add(mul(x, RAY), y / 2) / y;
    } function rpow(uint x, uint n) internal pure returns (uint z) {
        z = n % 2 != 0 ? x : RAY;

        for (n /= 2; n != 0; n /= 2) {
            x = rmul(x, x);

            if (n % 2 != 0) {
                z = rmul(z, x);
            }
        }
    }
} contract Bank is DSMath { mapping(address => uint) public balances;
  event LogDepositMade(address accountAddress, uint amount); function deposit() public payable returns (uint balance) {
    balances[msg.sender] = add(balances[msg.sender], msg.value);
    emit LogDepositMade(msg.sender, msg.value);
    return balances[msg.sender];
  } function withdraw(uint amount) public returns (uint remainingBalance){
    require(min(amount,balances[msg.sender]) == amount);
    balances[msg.sender] = sub(balances[msg.sender],amount);
    msg.sender.transfer(amount);
    return balances[msg.sender];
  } 

function balance() view public returns (uint) {
    return balances[msg.sender];
  }
} contract OwnsArt is DSMath, Bank{
  address public artist;
  address public artOwner;
  uint public price;
  uint public resaleFee;
  uint public constant maxFlatIncreaseAmount = 0.01 ether;
  uint public constant maxPercentIncreaseAmount = 10;

  event LogArtBought(address purchaserAddress, uint price, uint resalePrice);

  bool private buyArtMutex = false;

  constructor() public {
    artist = msg.sender;
    artOwner = msg.sender;
    price = 0.01 ether;
    resaleFee = 0 ether;
    emit LogArtBought(msg.sender,0 ether,price);
  } function buyArt(uint maxBid, uint resalePrice) public returns (uint){
    require(msg.sender != artOwner);
    require(max(maxBid,price) == maxBid);
    require(min(maxBid,balances[msg.sender]) == maxBid);
    require(min(resalePrice,maxResalePrice()) == resalePrice);

    require(!buyArtMutex);
    buyArtMutex = true;


    balances[msg.sender] = sub(balances[msg.sender],price);
    balances[artOwner] = add(balances[artOwner],sub(price,resaleFee));
    balances[artist] = add(balances[artist],resaleFee);
    artOwner = msg.sender; if(min(resalePrice,price)==resalePrice){
      resaleFee = 0 ether;
    } else{
      resaleFee = rdiv(sub(resalePrice,price),2*RAY);
    }

    emit LogArtBought(msg.sender,price,resalePrice);
    price = resalePrice;

    buyArtMutex = false;
    return balances[msg.sender];
  } function maxResalePrice() view public returns (uint){
    return add(add(rdiv(mul(price,maxPercentIncreaseAmount),100*RAY),price),maxFlatIncreaseAmount);
  }
}