// SPDX-License-Identifier: MIT pragma solidity >=0.8.0; import "@openzeppelin/contracts-upgradeable/utils/cryptography/ECDSAUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/utils/cryptography/EIP712Upgradeable.sol"; /** * @title Validator */ contract Validator is EIP712Upgradeable { string internal constant _ACTION_ADD_BLOCKCHAIN = 'addBlockchain'; string internal constant _ACTION_PROPOSE_CHANGES_BLOCKCHAIN = 'proposeChangesBlockchain'; string internal constant _ACTION_VALIDATE_BLOCKCHAIN = 'validateBlockchain'; string internal constant _ACTION_UPDATE_BLOCKCHAIN = 'updateBlockchain'; string internal constant _ACTION_DELETE_BLOCKCHAIN = 'deleteBlockchain'; string internal constant _ACTION_ADD_RPC = 'addRpc'; string internal constant _ACTION_PROPOSE_CHANGES_RPC = 'proposeChangesRpc'; string internal constant _ACTION_VALIDATE_RPC = 'validateRpc'; string internal constant _ACTION_UPDATE_RPC = 'updateRpc'; string internal constant _ACTION_DELETE_RPC = 'deleteRpc'; string internal constant _ACTION_ADD_FAUCET = 'addFaucet'; string internal constant _ACTION_PROPOSE_CHANGES_FAUCET = 'proposeChangesFaucet'; string internal constant _ACTION_VALIDATE_FAUCET = 'validateFaucet'; string internal constant _ACTION_UPDATE_FAUCET = 'updateFaucet'; string internal constant _ACTION_DELETE_FAUCET = 'deleteFaucet'; string internal constant _ACTION_ADD_TOKEN = 'addToken'; string internal constant _ACTION_PROPOSE_CHANGES_TOKEN = 'proposeChangesToken'; string internal constant _ACTION_VALIDATE_TOKEN = 'validateToken'; string internal constant _ACTION_UPDATE_TOKEN = 'updateToken'; string internal constant _ACTION_DELETE_TOKEN = 'deleteToken'; uint256 private constant _MAX_ACTION_ID = 34; uint256 private constant _MAX_SIGNATURE_EXPIRY = 1_000; bytes32 private constant _VALIDATE_ACTION_TYPEHASH = keccak256( "validateAction(string action,string details,string dbRef,uint256 signatureExpiry)" ); function __Validator_init(string memory name, string memory version) internal onlyInitializing { __Validator_init_unchained(name, version); } function __Validator_init_unchained(string memory name, string memory version) internal onlyInitializing { __EIP712_init(name, version); } /** * @dev External function to validate an action * @param action - Action to verify */ function isActionValid(string calldata action) external view virtual returns (bool) { return _isActionValid(action); } /** * @dev Validate string match a other string (A==B) * @param strA - String A * @param strB - String B */ function _validateString(string calldata strA, string memory strB) internal pure virtual returns (bool) { return keccak256(abi.encodePacked(strA)) == keccak256(abi.encodePacked(strB)); } /** * @dev Validate the action is part of the contract actions * @param action - Action to verify */ function _isActionValid(string calldata action) internal view virtual returns (bool) { return _validateString(action, _ACTION_ADD_BLOCKCHAIN) || _validateString(action, _ACTION_PROPOSE_CHANGES_BLOCKCHAIN) || _validateString(action, _ACTION_VALIDATE_BLOCKCHAIN) || _validateString(action, _ACTION_UPDATE_BLOCKCHAIN) || _validateString(action, _ACTION_DELETE_BLOCKCHAIN) || _validateString(action, _ACTION_ADD_RPC) || _validateString(action, _ACTION_PROPOSE_CHANGES_RPC) || _validateString(action, _ACTION_VALIDATE_RPC) || _validateString(action, _ACTION_UPDATE_RPC) || _validateString(action, _ACTION_DELETE_RPC) || _validateString(action, _ACTION_ADD_FAUCET) || _validateString(action, _ACTION_PROPOSE_CHANGES_FAUCET) || _validateString(action, _ACTION_VALIDATE_FAUCET) || _validateString(action, _ACTION_UPDATE_FAUCET) || _validateString(action, _ACTION_DELETE_FAUCET) || _validateString(action, _ACTION_ADD_TOKEN) || _validateString(action, _ACTION_PROPOSE_CHANGES_TOKEN) || _validateString(action, _ACTION_VALIDATE_TOKEN) || _validateString(action, _ACTION_UPDATE_TOKEN) || _validateString(action, _ACTION_DELETE_TOKEN); } /** * @dev Validate the expiration of the signature * @param signatureExpiry - Expiration timestamp of the signature */ function _validateSignatureExpiry(uint256 signatureExpiry) internal view virtual returns (bool) { require(signatureExpiry > block.number, "Validator: Signature expired"); require(signatureExpiry < block.number + _MAX_SIGNATURE_EXPIRY, "Validator: Signature expiration invalid"); return true; } /** * @dev Retrieve the signer of the signature * @param action - Action to perform * @param details - Extra details of the action (to explain the signature) * @param dbRef - Database reference * @param signatureExpiry - Signatura expiration timestamp * @param v - Split signature.v * @param r - Split signature.r * @param s - Split signature.s */ function _getValidateActionSigner( string calldata action, string calldata details, string calldata dbRef, uint256 signatureExpiry, uint8 v, bytes32 r, bytes32 s ) internal view virtual returns (address) { return ECDSAUpgradeable.recover( _hashTypedDataV4( keccak256( abi.encode( _VALIDATE_ACTION_TYPEHASH, action, details, dbRef, signatureExpiry ) ) ), v, r, s ); } /** * @dev Allow a validate API action to be performed by the user or the API * @param account - Suposed signer * @param action - Action to perform * @param details - Extra details of the action (to explain the signature) * @param dbRef - Database reference * @param signatureExpiry - Signatura expiration timestamp * @param v - Split signature.v * @param r - Split signature.r * @param s - Split signature.s */ function _validateAction( address account, string calldata action, string calldata details, string calldata dbRef, uint256 signatureExpiry, uint8 v, bytes32 r, bytes32 s ) internal view virtual returns (bool success) { require(_isActionValid(action), "Validator: Invalid action"); _validateSignatureExpiry(signatureExpiry); if (account == _getValidateActionSigner( action, details, dbRef, signatureExpiry, v, r, s )) success = true; } uint256[50] private __gap; }