62 lines
2.9 KiB
Solidity
62 lines
2.9 KiB
Solidity
|
// SPDX-License-Identifier: MIT
|
||
|
pragma solidity 0.8.16;
|
||
|
|
||
|
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
|
||
|
import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
|
||
|
import "./interfaces/IERC6672.sol";
|
||
|
|
||
|
contract ERC6672 is ERC721, IERC6672 {
|
||
|
using EnumerableSet for EnumerableSet.Bytes32Set;
|
||
|
|
||
|
bytes4 public constant IERC6672_ID = type(IERC6672).interfaceId;
|
||
|
|
||
|
mapping(address => mapping(uint256 => mapping(bytes32 => bool))) redemptionStatus;
|
||
|
mapping(address => mapping(uint256 => mapping(bytes32 => string))) public memos;
|
||
|
mapping(address => mapping(uint256 => EnumerableSet.Bytes32Set)) redemptions;
|
||
|
|
||
|
constructor() ERC721("Multiple RedeemableNFT", "mrNFT") {}
|
||
|
|
||
|
function isRedeemed(address _operator, bytes32 _redemptionId, uint256 _tokenId) external view returns (bool) {
|
||
|
return _isRedeemed(_operator, _redemptionId, _tokenId);
|
||
|
}
|
||
|
|
||
|
function getRedemptionIds(address _operator, uint256 _tokenId) external view returns (bytes32[] memory) {
|
||
|
require(redemptions[_operator][_tokenId].length() > 0, "ERC6672: token doesn't have any redemptions.");
|
||
|
return redemptions[_operator][_tokenId].values();
|
||
|
}
|
||
|
|
||
|
function redeem(bytes32 _redemptionId, uint256 _tokenId, string memory _memo) external {
|
||
|
address _operator = msg.sender;
|
||
|
require(!_isRedeemed(_operator, _redemptionId, _tokenId), "ERC6672: token already redeemed.");
|
||
|
_update(_operator, _redemptionId, _tokenId, _memo, true);
|
||
|
redemptions[_operator][_tokenId].add(_redemptionId);
|
||
|
}
|
||
|
|
||
|
function cancel(bytes32 _redemptionId, uint256 _tokenId, string memory _memo) external {
|
||
|
address _operator = msg.sender;
|
||
|
require(_isRedeemed(_operator, _redemptionId, _tokenId), "ERC6672: token doesn't redeemed.");
|
||
|
_update(_operator, _redemptionId, _tokenId, _memo, false);
|
||
|
_removeRedemption(_operator, _redemptionId, _tokenId);
|
||
|
}
|
||
|
|
||
|
function _isRedeemed(address _operator, bytes32 _redemptionId, uint256 _tokenId) internal view returns (bool) {
|
||
|
require(_exists(_tokenId), "ERC6672: token doesn't exists.");
|
||
|
return redemptionStatus[_operator][_tokenId][_redemptionId];
|
||
|
}
|
||
|
|
||
|
function _update(address _operator, bytes32 _redemptionId, uint256 _tokenId, string memory _memo, bool isRedeemed_) internal {
|
||
|
redemptionStatus[_operator][_tokenId][_redemptionId] = isRedeemed_;
|
||
|
memos[_operator][_tokenId][_redemptionId] = _memo;
|
||
|
}
|
||
|
|
||
|
function _removeRedemption(address _operator, bytes32 _redemptionId, uint256 _tokenId) internal {
|
||
|
redemptions[_operator][_tokenId].remove(_redemptionId);
|
||
|
}
|
||
|
|
||
|
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721, IERC165) returns (bool) {
|
||
|
return
|
||
|
interfaceId == type(IERC721).interfaceId ||
|
||
|
interfaceId == type(IERC6672).interfaceId ||
|
||
|
super.supportsInterface(interfaceId);
|
||
|
}
|
||
|
}
|