becrypto/contracts/BEBoxMall.sol
2022-01-27 17:00:35 +08:00

105 lines
3.0 KiB
Solidity

// SPDX-License-Identifier: MIT
pragma solidity 0.8.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "./HasSignature.sol";
contract BEBoxMall is Ownable, HasSignature {
using SafeERC20 for IERC20;
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)
public
onlyOwner
{
require(_paymentReceivedAddress != address(0), 'payment received address can not be zero');
paymentReceivedAddress = _paymentReceivedAddress;
}
/**
* @dev BE box payment buy function
*/
function buyBoxWithSignature(
uint256 boxId,
uint256 _type,
address userAddress,
uint256 price,
address paymentErc20,
uint256 saltNonce,
bytes calldata signature
) external onlyOwner {
require(
!isContract(userAddress),
"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)
);
}
/**
* @dev Identify an address is user address or contract address
*/
function isContract(address _address) private view returns (bool) {
uint32 size;
assembly {
size := extcodesize(_address)
}
return (size > 0);
}
}