contract Purchasing is AccessControl {
  bytes32 public constant SIGNER_ROLE = keccak256("SIGNER_ROLE");
  mapping (uint256 => address) packOwners;

  constructor() {
    _setupRole(DEFAULT_ADMIN_ROLE, _msgSender());
    _setupRole(SIGNER_ROLE, _msgSender());
  }

  event PaymentSuccess(address account, uint256[] packIds, uint256 amountPaid);

  function purchasePacks(uint256[] calldata packIds, uint blockNum, uint256 amount, address account, bytes calldata signature) external payable {
        require(block.number <= blockNum, "Signature expired");
        require(_verify(_hash(packIds, blockNum, amount, account), signature), "Invalid signature");
        require(msg.value == amount, "Incorrect ether sent");

        // Store addresses of pack purchaser to prevent re-purchase with same signature
        for (uint i=0; i<packIds.length; i++){
          require(packOwners[packIds[i]] == address(0x0) , "Pack has been purchased!");
          packOwners[packIds[i]] = account;
        }

        emit PaymentSuccess(account, packIds, msg.value);
  }

  // Check/Withdraw contract balance functions
  function getBalance() external view onlyRole(DEFAULT_ADMIN_ROLE) returns (uint256) {
      return address(this).balance;
  }

  function withdraw() external onlyRole(DEFAULT_ADMIN_ROLE) {
    payable(msg.sender).transfer(address(this).balance);
  }

  // Signature and reservation functions
  function _hash(uint256[] calldata packIds, uint blockNum, uint256 amount, address account)
    public pure returns (bytes32)
    {
        return ECDSA.toEthSignedMessageHash(keccak256(abi.encodePacked(packIds, blockNum, amount, account)));
  }

  function _verify(bytes32 digest, bytes calldata signature)
    internal view returns (bool)
    {
        // Ensures that the resulting address recovered has a SIGNER_ROLE function
        return hasRole(SIGNER_ROLE, ECDSA.recover(digest, signature));
  }

}
function getBalance() external view onlyRole(DEFAULT_ADMIN_ROLE) returns (uint256) {
      return address(this).balance;
  }
// Check/Withdraw contract balance functions