//SPDX-License-Identifier: Unlicense pragma solidity ^0.7.1; import "hardhat/console.sol"; contract KYC { struct Customer { string userName; string data; bool kycStatus; uint16 upVotes; uint16 downVotes; address bank; } struct Bank { string name; address ethAddress; uint16 complaintsReported; uint32 kycCount; bool isAllowedToVote; string regNumber; } struct KycRequest { string userName; address bank; string data; } mapping(string => Customer) customers; mapping(address => Bank) banks; uint32 registeredBankCount = 0; mapping(string => KycRequest) kycRequests; mapping(address => bool) adminAccounts; // Whoever deploys this code gets the admin priviledge constructor() { adminAccounts[msg.sender] = true; } // ** Bank Specific Functions ** function addCustomer(string memory _userName, string memory _customerData) private isBank { require( customers[_userName].bank == address(0), "Customer is already present, please call modifyCustomer to edit the customer data" ); customers[_userName].userName = _userName; customers[_userName].data = _customerData; customers[_userName].bank = msg.sender; } function modifyCustomer( string memory _userName, string memory _newcustomerData ) public isBank validCustomer(_userName) { customers[_userName].data = _newcustomerData; removeRequest(_userName); customers[_userName].kycStatus = false; customers[_userName].upVotes = 0; customers[_userName].downVotes = 0; } function upvoteCustomer(string memory _userName) public isBank isAuthorisedBank validCustomer(_userName) { customers[_userName].upVotes++; uint16 currentUpvotes = customers[_userName].upVotes; uint16 currentDownvotes = customers[_userName].downVotes; // If the customer has a pending KYC registry, approve the KYC using this upvote if(kycRequests[_userName].bank != address(0)) { removeRequest(_userName); } // If upvote>downvote set kycStatus to true. if ( (currentUpvotes > currentDownvotes) && customers[_userName].kycStatus == false ) { customers[_userName].kycStatus = true; console.log( "Customer got %d upvotes and %d downvotes, hence kycStatus set to active", currentUpvotes, currentDownvotes ); } console.log("Customer %s upvoted. New upvote(s): %d", currentUpvotes); } function downvoteCustomer(string memory _userName) public isBank isAuthorisedBank validCustomer(_userName) { customers[_userName].downVotes++; processDownvote(customers[_userName]); } function addRequest(string memory _userName, string memory _customerData) public isBank { // If customer is not present in the database, register if(customers[_userName].bank != address(0)) { addCustomer(_userName, _customerData); } kycRequests[_userName].userName = _userName; kycRequests[_userName].data = _customerData; kycRequests[_userName].bank = msg.sender; } function removeRequest(string memory _userName) public isBank validCustomer(_userName) { delete kycRequests[_userName]; } function viewCustomer(string memory _userName) public view isBank validCustomer(_userName) returns ( string memory, string memory, address ) { return ( customers[_userName].userName, customers[_userName].data, customers[_userName].bank ); } function viewBankDetails(address _bankAddress) public view isBank validBank(_bankAddress) returns (Bank memory bank) { return (banks[_bankAddress]); } function getBankComplaints(address _bankAddress) public view isBank validBank(_bankAddress) returns (uint16 complaintsReported) { return banks[_bankAddress].complaintsReported; } function reportBank(address _bankAddress) public isBank validBank(_bankAddress) { banks[_bankAddress].complaintsReported++; uint16 currentComplaints = banks[_bankAddress].complaintsReported; if(registeredBankCount>=5 && currentComplaints>=registeredBankCount/3) { banks[_bankAddress].isAllowedToVote = false; } } // ** Admin specific functions ** function addBank( string memory _bankName, address _bankAddress, string memory _registrationNumber ) public isAdmin { require( banks[_bankAddress].ethAddress == address(0), "Bank is already present" ); banks[_bankAddress].name = _bankName; banks[_bankAddress].ethAddress = _bankAddress; banks[_bankAddress].regNumber = _registrationNumber; banks[_bankAddress].complaintsReported = 0; banks[_bankAddress].isAllowedToVote = true; ++registeredBankCount; } function updateAllowedToVote(address _bankAddress, bool authority) public validBank(_bankAddress) isAdmin { banks[_bankAddress].isAllowedToVote = authority; } function removeBank(address _bankAddress) public validBank(_bankAddress) isAdmin { delete banks[_bankAddress]; --registeredBankCount; } // ** Modifiers ** /** * Only allow usernames which are registered as customer. */ modifier validCustomer(string memory _userName) { require( customers[_userName].bank != address(0), "No such customer is present in the database, try adding the customer using addCustomer function first" ); _; } /** * Only allow addresses which are registered as bank. */ modifier validBank(address _bankAddress) { require( banks[_bankAddress].ethAddress != address(0), "No bank is registered with this address" ); _; } /** * Only allow admin accounts to execute method. */ modifier isAdmin() { require( adminAccounts[msg.sender] != false, "Only admin can call this function" ); _; } /** * Only allow registered banks to execute method. */ modifier isBank() { require( banks[msg.sender].ethAddress != address(0), "Only banks can call this function" ); _; } /** * Only allow bank with KYC verification authority to validate KYC data. */ modifier isAuthorisedBank() { require( banks[msg.sender].isAllowedToVote != false, "Bank doen't have the permission to verify customer data" ); _; } // ** Internal Functions ** /** * If there are more than 5 banks and more than 1/3 of the bank downvoted, set kycStatus to false * Block the KYC issuer bank as well from validating further KYCs. */ function processDownvote(Customer storage _customer) private { uint16 currentDownvotes = _customer.downVotes; if ( registeredBankCount >= 5 && currentDownvotes >= registeredBankCount / 3 && (_customer.kycStatus == true) ) { _customer.kycStatus = false; banks[_customer.bank].isAllowedToVote = false; console.log( "Customer got %d downvotes, out of registered bank count of %d, hence kycStatus set to inactive", currentDownvotes, registeredBankCount ); } console.log( "Customer %s downvoted. New downvote(s): %d", _customer.userName, _customer.downVotes ); } /** * Delete the KYC request from the KYC stack and add the customer to registry. */ function processKycValidation(string memory _username, string memory _custData) private { removeRequest(_username); addCustomer(_username, _custData); } }
0.7.1