// SPDX-License-Identifier: MIT pragma solidity 0.8.10; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/utils/Address.sol"; import "./HasSignature.sol"; contract BEBoxMall is Ownable, HasSignature { using SafeERC20 for IERC20; using Address for address; event BEBoxPaid( uint256 indexed boxId, address indexed buyer, uint256 boxType, uint256 price, address paymentToken ); address public paymentReceivedAddress; mapping(bytes => bool) public usedSignatures; function setPaymentReceivedAddress(address _paymentReceivedAddress) external onlyOwner { require(_paymentReceivedAddress != address(0), 'payment received address can not be zero'); paymentReceivedAddress = _paymentReceivedAddress; } /** * @dev BE box payment function */ function payForBoxWithSignature( uint256 boxId, uint256 _type, address userAddress, uint256 price, address paymentErc20, uint256 saltNonce, bytes calldata signature ) external onlyOwner { require( !userAddress.isContract(), "BEBoxPayment: Only user address is allowed to buy box" ); require(_type > 0, "BEBoxPayment: Invalid box type"); require(price > 0, "BEBoxPayment: Invalid payment amount"); require( !usedSignatures[signature], "BEBoxPayment: signature used. please send another transaction with new signature" ); bytes32 criteriaMessageHash = getMessageHash( _type, paymentErc20, price, saltNonce ); checkSigner(userAddress, criteriaMessageHash, signature); IERC20 paymentToken = IERC20(paymentErc20); uint256 allowToPayAmount = paymentToken.allowance( userAddress, address(this) ); require( allowToPayAmount >= price, "BEBoxPayment: Invalid token allowance" ); // Transfer payment paymentToken.safeTransferFrom( userAddress, paymentReceivedAddress, price ); usedSignatures[signature] = true; // Emit payment event emit BEBoxPaid(boxId, userAddress, _type, price, paymentErc20); } function getMessageHash( uint256 _boxType, address _paymentErc20, uint256 _price, uint256 _saltNonce ) public pure returns (bytes32) { return keccak256( abi.encodePacked(_boxType, _paymentErc20, _price, _saltNonce) ); } }