// File: contracts/Exchange.sol




pragma solidity 0.8.12;

import "./SafeMath.sol";

contract RugRaceDex {
    using SafeMath for uint256;
    IERC20Lite public rugRaceToken;
    IERC721Lite public ratRaceNft;
    address public kingRat;    
    uint256 constant public exchange = 2674000000;
    uint256 constant public minSaleAmount = 1000000000000000000;
    uint256 constant public preSaleCap =  267400000000 * 10 ** 18;
    uint256 public preSaleAmount = 0;
    uint256 constant public holderSwapRate =  50000000 * 10 ** 18;
    bool public isLive = false;

    constructor() {      
    kingRat = msg.sender;
    }

  
  function setAddresses(address _rugRace, address _ratRace) public {    
    onlyOwner();
    rugRaceToken = IERC20Lite(_rugRace);
    ratRaceNft = IERC721Lite(_ratRace);    
  }

  function swapEthForTokens() external payable{    
    uint256 tokensToTransfer = msg.value.mul(exchange);
    allowTokenSwap(tokensToTransfer);
    preSaleAmount = preSaleAmount.add(tokensToTransfer);
    rugRaceToken.transfer(msg.sender, tokensToTransfer);
  }

  function swapRatForTokens(uint256 tokenId) external {       
    allowRatSwap(tokenId);
    ratRaceNft.transferFrom(msg.sender, address(this), tokenId);
    rugRaceToken.transfer(msg.sender, holderSwapRate);
  } 

    function toggleLive() external {
    onlyOwner();
    isLive = !isLive;
    }

     function withdrawAll() public {
    onlyOwner();
    uint256 balance = address(this).balance;
    require(balance > 0);
    _withdraw(kingRat, balance);    
    }    

    function onlyOwner() internal view {
    require(kingRat == msg.sender,"NotKingRat");
    }   

    function allowTokenSwap(uint256 tokensToTransfer) internal {
    require(isLive, "NotLive");
    require(rugRaceToken.balanceOf(address(this)) >= tokensToTransfer, "NotEnoughTokensLeft");        
    require(preSaleAmount.add(tokensToTransfer) <= preSaleCap, "PreSaleCapReached");
    }

    function allowRatSwap(uint256 tokenId) internal {
    require(isLive, "NotLive");
    require(ratRaceNft.ownerOf(tokenId) == msg.sender, "NotOwner");
    require(ratRaceNft.isApprovedForAll(msg.sender, address(this)), "OperatorNotApproved");
    }
   
    function _withdraw(address _address, uint256 _amount) private {
    (bool success, ) = _address.call{value: _amount}("");
    require(success);
    }   
}

interface IERC20Lite {
    
    function transfer(address to, uint256 value) external returns (bool);
    function burn(address from, uint256 value) external;
    function mint(address to, uint256 value) external; 
    function approve(address spender, uint256 value) external returns (bool);     
    function balanceOf(address account) external returns (uint256); 
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);

}

interface IERC721Lite {
    function transferFrom(address from, address to, uint256 id) external;   
    function transfer(address to, uint256 id) external;
    function ownerOf(uint256 id) external returns (address owner);
    function setApprovalForAll(address operator, bool approved) external;
    function mint(address to, uint256 tokenid) external;
    function isApprovedForAll(address owner, address operator) external returns (bool);
}
// File: contracts/SafeMath.sol



pragma solidity 0.8.12;


/**
 * Math operations with safety checks
 */
library SafeMath {
  function mul(uint a, uint b) internal returns (uint) {
    uint c = a * b;
    assert(a == 0 || c / a == b);
    return c;
  }

  function div(uint a, uint b) internal returns (uint) {
    // assert(b > 0); // Solidity automatically throws when dividing by 0
    uint c = a / b;
    // assert(a == b * c + a % b); // There is no case in which this doesn't hold
    return c;
  }

  function sub(uint a, uint b) internal returns (uint) {
    assert(b <= a);
    return a - b;
  }

  function add(uint a, uint b) internal returns (uint) {
    uint c = a + b;
    assert(c >= a);
    return c;
  }

  function percent(uint a, uint b) internal returns (uint) {
    uint c = a * b;
    assert(a == 0 || c / a == b);
    return c / 100;
  }
}