// SPDX-License-Identifier: MIT pragma solidity ^0.8.21; import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/security/Pausable.sol"; // Multi-Factor Authentication (MFA) Contract contract MFA is Ownable, Pausable { using ECDSA for bytes32; mapping(address => string) public userSecrets; mapping(address => uint256) public lastVerificationTimestamp; event SecretSet(address indexed user, string secret); event VerificationAttempt(address indexed user, bool success); constructor() Ownable() Pausable() {} function setSecret(string memory secret) external onlyOwner whenNotPaused { userSecrets[msg.sender] = secret; emit SecretSet(msg.sender, secret); } function generateTOTPCode(uint256 timestamp) internal view returns (uint256) { require(bytes(userSecrets[msg.sender]).length > 0, "MFA secret not set"); bytes32 key = keccak256(abi.encodePacked(userSecrets[msg.sender])); bytes32 data = keccak256(abi.encodePacked(timestamp / 30)); // 30 seconds interval bytes memory signature = ECDSA.toEthSignedMessageHash(data).recover(key); uint256 totpCode = uint256(uint8(signature[19])) & 0x0F; totpCode = (totpCode << 8) | uint256(uint8(signature[20])); totpCode = (totpCode << 8) | uint256(uint8(signature[21])); totpCode = (totpCode << 8) | uint256(uint8(signature[22])); totpCode = totpCode % 1000000; // 6-digit code return totpCode; } function verifyCode(uint256 code) external view returns (bool) { uint256 currentTimestamp = block.timestamp; uint256 previousTimestamp = currentTimestamp - 30; // Consider a 30-second window // Verify the current and previous TOTP codes bool success = (code == generateTOTPCode(currentTimestamp) || code == generateTOTPCode(previousTimestamp)); emit VerificationAttempt(msg.sender, success); // Update last verification timestamp lastVerificationTimestamp[msg.sender] = currentTimestamp; return success; } // Additional functions can be added for enhanced MFA features // Pause and unpause functions for emergency situations function pauseContract() external onlyOwner { _pause(); } function unpauseContract() external onlyOwner { _unpause(); } }