-
Notifications
You must be signed in to change notification settings - Fork 36
/
Copy pathKYC.sol
90 lines (76 loc) · 3.14 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
// SPDX-License-Identifier: unlicenced
pragma solidity 0.8.4;
import "@openzeppelin/contracts/access/Ownable.sol";
interface IKYCApp {
function owner() external returns (address);
}
contract KYC is Ownable {
mapping(address => address) public whitelistedOwners;
mapping(address => bool) public onboardedApps;
function applyFor(address tokenAddr) external {
require(tokenAddr != address(0), "KYC: token address must not be empty");
require(IKYCApp(tokenAddr).owner() == msg.sender, "KYC: only owner of token can apply");
whitelistedOwners[tokenAddr] = msg.sender;
}
function onboard(address tokenAddr) external {
require(!onboardedApps[tokenAddr], "KYC: already onboarded");
require(tokenAddr != address(0), "KYC: token address must not be empty");
require(msg.sender == whitelistedOwners[tokenAddr], "KYC: only owner can onboard");
onboardedApps[tokenAddr] = true;
}
function onboardWithSig(
address tokenAddr,
bytes32 msgHash,
string memory description,
bytes memory signature
) external {
require(!onboardedApps[tokenAddr], "KYC: already onboarded");
require(tokenAddr != address(0), "KYC: token address must not be empty");
bytes32 payloadHash = keccak256(abi.encode(msgHash, description));
bytes32 messageHash = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", payloadHash));
_checkWhitelisted(tokenAddr, messageHash, signature);
onboardedApps[tokenAddr] = true;
}
function removeApp(address tokenAddr) external onlyOwner {
delete whitelistedOwners[tokenAddr];
delete onboardedApps[tokenAddr];
}
function _checkWhitelisted(
address _tokenAddr,
bytes32 _messageHash,
bytes memory _signature
) internal view {
(bool status, address signer) = recoverSigner(_messageHash, _signature);
if (signer == address(0) && !status) {
revert("KYC: signature is malformed");
}
require(signer == whitelistedOwners[_tokenAddr], "KYC: only owner can onboard");
}
function recoverSigner(bytes32 hash, bytes memory signature) internal pure returns (bool, address) {
if (signature.length == 65) {
bytes32 r;
bytes32 s;
uint8 v;
assembly {
r := mload(add(signature, 0x20))
s := mload(add(signature, 0x40))
v := byte(0, mload(add(signature, 0x60)))
}
address recovered = ecrecover(hash, v, r, s);
return (true, recovered);
} else if (signature.length == 64) {
bytes32 r;
bytes32 vs;
assembly {
r := mload(add(signature, 0x20))
vs := mload(add(signature, 0x40))
}
bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
uint8 v = uint8((uint256(vs) >> 255) + 27);
address recovered = ecrecover(hash, v, r, s);
return (true, recovered);
} else {
return (false, address(0));
}
}
}