-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathKYC.sol
115 lines (96 loc) · 3.87 KB
/
KYC.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
// This code snippet is provided by Pessimistic company.
// To apply for the internship opportunity at Pessimistic company,
// please fill out the form by visiting the following link: https://forms.gle/SUTcGi8X86yNoFnG7
// Caution: This code is intended for educational purposes only
// and should not be used in production environments.
pragma solidity ^0.8.0;
import '@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol';
import '@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol';
import '@openzeppelin/contracts-upgradeable/utils/cryptography/ECDSAUpgradeable.sol';
import '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol';
import '@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol';
import {SignatureChecker} from '@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol';
import '@openzeppelin/contracts-upgradeable/utils/structs/BitMapsUpgradeable.sol';
contract Token is Initializable, ERC721Upgradeable, AccessControlUpgradeable, UUPSUpgradeable {
using BitMapsUpgradeable for BitMapsUpgradeable.BitMap;
using ECDSAUpgradeable for bytes32;
using SignatureChecker for address;
struct SignatureData {
address signer;
address account;
uint256 nonce;
bytes signature;
}
uint256 chainId;
bytes32 public constant PROVIDER_ROLE = keccak256('PROVIDER_ROLE');
mapping(address => uint256) public nonces;
function initialize(uint256 _chainId) initializer public {
__ERC721_init('Token Name', 'TOKEN');
__AccessControl_init();
__UUPSUpgradeable_init();
_setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
_setupRole(PROVIDER_ROLE, msg.sender);
chainId = _chainId;
}
function _authorizeUpgrade(address newImplementation) internal override {}
function mintTo(
SignatureData calldata signatureData,
uint256 tokenId
) external
signerVerification(tokenId, signatureData) {
require(balanceOf(signatureData.account) == 0, 'The token has already been minted!');
_mint(signatureData.account, tokenId);
nonces[signatureData.account]++;
}
function burn(
uint256 tokenId,
SignatureData calldata signatureData
) external signerVerification(tokenId, signatureData) {
require(balanceOf(signatureData.account) > 0, 'Nothing to burn');
_burn(tokenId);
nonces[signatureData.account] += 1;
require(balanceOf(signatureData.account) == 0, 'The token has not been burnt!');
}
modifier signerVerification(
uint256 tokenId,
SignatureData calldata signature
) {
require(nonces[signature.signer] == signature.nonce, 'Invalid Nonce');
require(hasRole(PROVIDER_ROLE, msg.sender), 'Invalid Provider');
bytes32 hash = keccak256(
abi.encodePacked(
'\x19\x01',
keccak256(abi.encode(
signature.signer,
address(this),
signature.account,
tokenId,
nonces[signature.signer],
chainId
))
)
).toEthSignedMessageHash();
require(
signature.signer.isValidSignatureNow(hash, signature.signature),
'Invalid Signer'
);
_;
}
function _beforeTokenTransfer(
address from,
address to,
uint256 tokenId,
uint256 amount
) internal override {
require(
(from == address(0) && to != address(0)) || (from != address(0) && to == address(0)),
'Only mint or burn transfers are allowed'
);
super._beforeTokenTransfer(from, to, tokenId, amount);
}
function supportsInterface(
bytes4 interfaceId
) public view override(ERC721Upgradeable, AccessControlUpgradeable) returns (bool) {
return super.supportsInterface(interfaceId);
}
}