158 lines
4.4 KiB
Solidity
158 lines
4.4 KiB
Solidity
// 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 "@openzeppelin/contracts/governance/TimelockController.sol";
|
|
import "../core/HasSignature.sol";
|
|
|
|
contract BEBoxMall is Ownable, HasSignature, TimelockController {
|
|
using SafeERC20 for IERC20;
|
|
using Address for address;
|
|
|
|
uint256 public constant MIN_DELAY = 2 days;
|
|
uint256 public constant MAX_DELAY = 16 days;
|
|
uint256 private _minDelay;
|
|
|
|
bool public address_initialized;
|
|
|
|
constructor(address[] memory proposers, address[] memory executors)
|
|
TimelockController(MIN_DELAY, proposers, executors)
|
|
HasSignature("BEBoxMall", "1")
|
|
{
|
|
_minDelay = MIN_DELAY;
|
|
address_initialized = false;
|
|
}
|
|
|
|
event BEBoxPaid(
|
|
uint256 indexed boxId,
|
|
address indexed buyer,
|
|
uint256 boxType,
|
|
uint256 price,
|
|
address paymentToken
|
|
);
|
|
|
|
address public paymentReceivedAddress;
|
|
|
|
function setPaymentReceivedAddress(address _paymentReceivedAddress) public {
|
|
require(
|
|
_paymentReceivedAddress != address(0),
|
|
"BEBoxMall::setPaymentReceivedAddress: payment received address can not be zero"
|
|
);
|
|
if (address_initialized) {
|
|
require(
|
|
msg.sender == address(this),
|
|
"BEBoxMall::setPaymentReceivedAddress: Call must come from BEBoxMall."
|
|
);
|
|
} else {
|
|
require(
|
|
msg.sender == owner(),
|
|
"BEBoxMall::setPaymentReceivedAddress: First call must come from owner."
|
|
);
|
|
address_initialized = true;
|
|
}
|
|
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 signatureValid(signature) {
|
|
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");
|
|
bytes32 criteriaMessageHash = getMessageHash(
|
|
_type,
|
|
paymentErc20,
|
|
price,
|
|
saltNonce
|
|
);
|
|
|
|
checkSigner712(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);
|
|
useSignature(signature);
|
|
// 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.encode(
|
|
keccak256(
|
|
"set(uint256 item,address token,uint256 price,uint256 salt)"
|
|
),
|
|
_boxType,
|
|
_paymentErc20,
|
|
_price,
|
|
_saltNonce
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @dev Returns the minimum delay for an operation to become valid.
|
|
*
|
|
* This value can be changed by executing an operation that calls `updateDelay`.
|
|
*/
|
|
function getMinDelay()
|
|
public
|
|
view
|
|
virtual
|
|
override
|
|
returns (uint256 duration)
|
|
{
|
|
return _minDelay;
|
|
}
|
|
|
|
/**
|
|
* @dev Changes the minimum timelock duration for future operations.
|
|
*
|
|
* Emits a {MinDelayChange} event.
|
|
*
|
|
* Requirements:
|
|
*
|
|
* - the caller must be the timelock itself. This can only be achieved by scheduling and later executing
|
|
* an operation where the timelock is the target and the data is the ABI-encoded call to this function.
|
|
*/
|
|
function updateDelay(uint256 newDelay) external virtual override {
|
|
require(msg.sender == address(this), "BEBoxMall: caller must be timelock");
|
|
require(
|
|
newDelay >= MIN_DELAY,
|
|
"BEBoxMall: newDelay must greater than or equal to MIN_DELAY"
|
|
);
|
|
require(
|
|
newDelay <= MAX_DELAY,
|
|
"BEBoxMall: newDelay must less than or equal to MAX_DELAY"
|
|
);
|
|
emit MinDelayChange(_minDelay, newDelay);
|
|
_minDelay = newDelay;
|
|
}
|
|
}
|