-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathstandard-input2.json
More file actions
1 lines (1 loc) · 121 KB
/
standard-input2.json
File metadata and controls
1 lines (1 loc) · 121 KB
1
{"language":"Solidity","sources":{"src/VotsEngine.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.21;\n\nimport {IElection} from \"./interfaces/IElection.sol\";\nimport {ICreateElection} from \"./interfaces/ICreateElection.sol\";\nimport {CreateElection} from \"./CreateElection.sol\";\nimport {VotsEngineLib} from \"./libraries/VotsEngineLib.sol\";\n\nimport {Ownable} from \"@openzeppelin/contracts/access/Ownable.sol\";\nimport {IVotsEngineFunctionClient} from \"./interfaces/IVotsEngineFunctionClient.sol\";\nimport {IVotsEngine} from \"./interfaces/IVotsEngine.sol\";\nimport {IVotsElectionNft} from \"./interfaces/IVotsElectionNft.sol\";\n\n/**\n * @title VotsEngine\n * @author Ayeni-yeniyan\n * @notice This is the core of the voting system.\n * This contract creates the election contract and tokenises the created contract address.\n * Only this contract has access to interact with the election contracts.\n * When an election is created, it gets a unique election id which identifies it.\n * An election contract is created with a unique name that is stored in memory and can be used to get the election address.\n * Each election is tokenised and the address is stored on chain to enable future access and reference.\n */\ncontract VotsEngine is IVotsEngine, Ownable {\n using VotsEngineLib for mapping(uint256 => address);\n\n // ====================================================================\n // State Variables\n // ====================================================================\n address private immutable electionCreator;\n address private immutable nftAddress;\n address public functionClient;\n uint256 private tokenIdCount;\n\n mapping(uint256 tokenId => address electionAddress) s_tokenToAddress;\n mapping(string electionName => uint256 tokenId) electionNameToTokenId;\n\n modifier validElection(uint256 electionTokenId) {\n if (s_tokenToAddress[electionTokenId] == address(0)) {\n revert IVotsEngine.VotsEngine__ElectionNotFound();\n }\n _;\n }\n\n modifier onlyFunctionClient() {\n if (msg.sender != functionClient) {\n revert IVotsEngine.VotsEngine__OnlyFunctionClient();\n }\n _;\n }\n\n // ====================================================================\n // Modifiers\n // ====================================================================\n\n constructor(\n address _electionCreator,\n address _nftAddress\n ) Ownable(msg.sender) {\n electionCreator = _electionCreator;\n nftAddress = _nftAddress;\n }\n\n /**\n * @dev Sets the function client address (only owner)\n * @param _functionClient Address of the VotsEngineFunctionClient contract\n */\n function setFunctionClient(address _functionClient) external onlyOwner {\n address oldClient = functionClient;\n functionClient = _functionClient;\n emit FunctionClientUpdated(oldClient, _functionClient);\n }\n\n function createElection(IElection.ElectionParams calldata params) external {\n // Check that electionName is not duplicate\n uint256 tokenId = electionNameToTokenId[params.electionName];\n if (bytes(params.electionName).length == 0) {\n revert IVotsEngine.VotsEngine__ElectionNameCannotBeEmpty();\n }\n if (tokenId > 0) {\n revert IVotsEngine.VotsEngine__DuplicateElectionName();\n }\n // Generate tokenId for election\n uint256 newElectionTokenId = ++tokenIdCount;\n address electionAddress = ICreateElection(electionCreator)\n .createElection({\n createdBy: msg.sender,\n electionUniqueTokenId: newElectionTokenId,\n params: params\n });\n // Store election address\n s_tokenToAddress[newElectionTokenId] = electionAddress;\n // Store election name\n electionNameToTokenId[params.electionName] = newElectionTokenId;\n\n // mint nft to user\n IVotsElectionNft(nftAddress).mintElectionNft(\n msg.sender,\n newElectionTokenId,\n params.electionName,\n params.description,\n params.startTimeStamp,\n params.endTimeStamp\n );\n // Emit creation event\n emit ElectionContractedCreated(newElectionTokenId, params.electionName);\n }\n\n function accrediteVoter(\n string calldata voterMatricNo,\n uint256 electionTokenId\n ) external validElection(electionTokenId) {\n // Call accredite function\n IElection(s_tokenToAddress[electionTokenId]).accrediteVoter(\n voterMatricNo,\n msg.sender\n );\n }\n\n /**\n * @dev Called by VotsEngineFunctionClient to fulfill voter accreditation\n * @param voterMatricNo The voter's matriculation number\n * @param electionTokenId The election token ID\n * @param messageSender The original message sender who initiated the request\n */\n function fulfillVoterAccreditation(\n string calldata voterMatricNo,\n uint256 electionTokenId,\n address messageSender\n ) external onlyFunctionClient validElection(electionTokenId) {\n IElection(s_tokenToAddress[electionTokenId]).accrediteVoter(\n voterMatricNo,\n messageSender\n );\n }\n\n /**\n * @dev Sends a verification request through the function client\n * @param ninNumber National identification number\n * @param firstName First name of the voter\n * @param lastName Last name of the voter\n * @param voterMatricNo Voter's matriculation number\n * @param slotId DON-hosted secrets slot ID\n * @param version DON-hosted secrets version\n * @param electionTokenId Token ID of the election\n * @param subscriptionId Chainlink Functions subscription ID\n * @return requestId The ID of the request\n */\n function sendVerificationRequestForElection(\n string calldata ninNumber,\n string calldata firstName,\n string calldata lastName,\n string calldata voterMatricNo,\n uint256 slotId,\n uint256 version,\n uint256 electionTokenId,\n uint64 subscriptionId\n ) external validElection(electionTokenId) returns (bytes32 requestId) {\n if (functionClient == address(0)) {\n revert IVotsEngine.VotsEngine__FunctionClientNotSet();\n }\n\n requestId = IVotsEngineFunctionClient(functionClient)\n .sendVerificationRequestForElection(\n ninNumber,\n firstName,\n lastName,\n voterMatricNo,\n slotId,\n version,\n electionTokenId,\n subscriptionId,\n msg.sender\n );\n\n emit VerificationRequestSent(requestId, voterMatricNo, electionTokenId);\n }\n\n function voteCandidates(\n string calldata voterMatricNo,\n string calldata voterName,\n IElection.CandidateInfoDTO[] calldata candidatesList,\n uint256 electionTokenId\n ) external validElection(electionTokenId) {\n // Call vote function\n IElection(s_tokenToAddress[electionTokenId]).voteCandidates(\n voterMatricNo,\n voterName,\n msg.sender,\n candidatesList\n );\n }\n\n function validateVoterForVoting(\n string memory voterMatricNo,\n string memory voterName,\n uint256 electionTokenId\n ) external validElection(electionTokenId) returns (bool) {\n return\n s_tokenToAddress.validateVoterForVoting(\n voterMatricNo,\n voterName,\n electionTokenId,\n msg.sender\n );\n }\n\n function validateAddressAsPollingUnit(\n uint256 electionTokenId\n ) external validElection(electionTokenId) returns (bool) {\n return\n s_tokenToAddress.validateAddressAsPollingUnit(\n electionTokenId,\n msg.sender\n );\n }\n\n function validateAddressAsPollingOfficer(\n uint256 electionTokenId\n ) external validElection(electionTokenId) returns (bool) {\n return\n s_tokenToAddress.validateAddressAsPollingOfficer(\n electionTokenId,\n msg.sender\n );\n }\n\n // ====================================================================\n // Getter Functions - Engine Level\n // ====================================================================\n\n /**\n * @dev Returns the total number of elections created\n * @return uint256 Total election count\n */\n function getTotalElectionsCount() public view returns (uint256) {\n return tokenIdCount;\n }\n\n /**\n * @dev Returns the election contract address for a given token ID\n * @param electionTokenId The token ID of the election\n * @return address Election contract address\n */\n function getElectionAddress(\n uint256 electionTokenId\n ) public view validElection(electionTokenId) returns (address) {\n return s_tokenToAddress[electionTokenId];\n }\n\n /**\n * @dev Returns the token ID for a given election name\n * @param electionName The name of the election\n * @return uint256 Token ID (returns 0 if not found)\n */\n function getElectionTokenId(\n string calldata electionName\n ) public view returns (uint256) {\n return electionNameToTokenId[electionName];\n }\n\n /**\n * @dev Checks if an election exists by token ID\n * @param electionTokenId The token ID of the election\n * @return bool True if election exists\n */\n function electionExistsByTokenId(\n uint256 electionTokenId\n ) public view returns (bool) {\n return s_tokenToAddress[electionTokenId] != address(0);\n }\n\n // ====================================================================\n // Getter Functions - Election Data Forwarding\n // ====================================================================\n\n /**\n * @dev Returns basic election information\n * @param electionTokenId The token ID of the election\n */\n function getElectionInfo(\n uint256 electionTokenId\n ) public view validElection(electionTokenId) returns (ElectionInfo memory) {\n IElection election = s_tokenToAddress.validateAndGetElection(\n electionTokenId\n );\n return VotsEngineLib.createElectionInfo(election);\n }\n\n /**\n * @dev Returns election statistics (original combined function)\n * @param electionTokenId The token ID of the election\n */\n function getElectionStats(\n uint256 electionTokenId\n )\n public\n view\n validElection(electionTokenId)\n returns (\n uint256 registeredVotersCount,\n uint256 accreditedVotersCount,\n uint256 votedVotersCount,\n uint256 registeredCandidatesCount,\n uint256 pollingOfficerCount,\n uint256 pollingUnitCount\n )\n {\n return s_tokenToAddress.getElectionStats(electionTokenId);\n }\n\n /**\n * @dev Returns all voters for an election\n * @param electionTokenId The token ID of the election\n */\n function getAllVoters(\n uint256 electionTokenId\n )\n public\n view\n validElection(electionTokenId)\n returns (IElection.ElectionVoter[] memory)\n {\n return IElection(s_tokenToAddress[electionTokenId]).getAllVoters();\n }\n\n /**\n * @dev Returns all accredited voters for an election\n * @param electionTokenId The token ID of the election\n */\n function getAllAccreditedVoters(\n uint256 electionTokenId\n )\n external\n view\n validElection(electionTokenId)\n returns (IElection.ElectionVoter[] memory)\n {\n return\n IElection(s_tokenToAddress[electionTokenId])\n .getAllAccreditedVoters();\n }\n\n /**\n * @dev Returns all voters who have voted for an election\n * @param electionTokenId The token ID of the election\n */\n function getAllVotedVoters(\n uint256 electionTokenId\n )\n external\n view\n validElection(electionTokenId)\n returns (IElection.ElectionVoter[] memory)\n {\n return IElection(s_tokenToAddress[electionTokenId]).getAllVotedVoters();\n }\n\n /**\n * @dev Returns all candidates for an election (as DTOs)\n * @param electionTokenId The token ID of the election\n */\n function getAllCandidatesInDto(\n uint256 electionTokenId\n )\n external\n view\n validElection(electionTokenId)\n returns (IElection.CandidateInfoDTO[] memory)\n {\n return\n IElection(s_tokenToAddress[electionTokenId])\n .getAllCandidatesInDto();\n }\n\n /**\n * @dev Returns all candidates with vote counts (only after election ends)\n * @param electionTokenId The token ID of the election\n */\n function getAllCandidates(\n uint256 electionTokenId\n )\n external\n view\n validElection(electionTokenId)\n returns (IElection.ElectionCandidate[] memory)\n {\n IElection election = IElection(s_tokenToAddress[electionTokenId]);\n return election.getAllCandidates();\n }\n\n /**\n * @dev Returns winners for each category (handles ties)\n * @param electionTokenId The token ID of the election\n */\n function getEachCategoryWinner(\n uint256 electionTokenId\n )\n external\n view\n validElection(electionTokenId)\n returns (IElection.ElectionWinner[][] memory)\n {\n IElection election = IElection(s_tokenToAddress[electionTokenId]);\n return election.getEachCategoryWinner();\n }\n\n // ====================================================================\n // Utility Functions\n // ====================================================================\n\n /**\n * @dev Updates election state for a specific election\n * @param electionTokenId The token ID of the election\n */\n function updateElectionState(\n uint256 electionTokenId\n ) external validElection(electionTokenId) {\n IElection(s_tokenToAddress[electionTokenId]).updateElectionState();\n }\n\n /**\n * @dev Returns a summary of all elections (basic info only)\n * @return electionsSummaryList Array of the election summary\n */\n function getAllElectionsSummary()\n external\n view\n returns (ElectionSummary[] memory electionsSummaryList)\n {\n uint256 totalElections = tokenIdCount;\n electionsSummaryList = new ElectionSummary[](totalElections);\n\n for (uint256 i = 1; i <= totalElections; i++) {\n address electionAddr = s_tokenToAddress[i];\n if (electionAddr != address(0)) {\n IElection election = IElection(electionAddr);\n electionsSummaryList[i - 1] = VotsEngineLib\n .createElectionSummary(election);\n }\n }\n }\n\n /**\n * @dev Returns the current owner of the contract\n */\n function getOwner() external view returns (address) {\n return owner();\n }\n\n /**\n * @dev Returns the current function client address\n */\n function getFunctionClient() external view returns (address) {\n return functionClient;\n }\n\n /**\n * @dev Returns the current function client address\n */\n function getNFTAddres() external view returns (address) {\n return nftAddress;\n }\n}\n"},"src/interfaces/IElection.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.21;\n\n/**\n * @title IElection\n * @dev Interface for the Election contract containing only functions called by VotsEngine\n * @author Ayeni-yeniyan\n * @notice Interface for individual election contracts managed by VotsEngine\n */\ninterface IElection {\n // ====================================================================\n // Structs (Referenced by VotsEngine)\n // ====================================================================\n\n enum ElectionState {\n OPENED,\n STARTED,\n ENDED\n }\n\n enum CandidateState {\n UNKNOWN,\n REGISTERED\n }\n\n /**\n * @dev Voters state Enum\n */\n enum VoterState {\n UNKNOWN,\n REGISTERED,\n ACCREDITED,\n VOTED\n }\n\n struct ElectionParams {\n uint256 startTimeStamp;\n uint256 endTimeStamp;\n string electionName;\n string description;\n CandidateInfoDTO[] candidatesList;\n VoterInfoDTO[] votersList;\n address[] pollingUnitAddresses;\n address[] pollingOfficerAddresses;\n string[] electionCategories;\n }\n\n /**\n * @dev This is for storing the unregistered candidates only\n */\n struct CandidateInfoDTO {\n string name;\n string matricNo;\n string category;\n uint256 voteFor;\n uint256 voteAgainst;\n }\n\n /**\n * @dev This structure is for registering voters only\n */\n struct VoterInfoDTO {\n string name;\n string matricNo;\n }\n\n /**\n * @dev Defines the structure of our voter\n */\n struct ElectionVoter {\n string name;\n VoterState voterState;\n }\n\n /**\n * @dev Structure for election candidates\n */\n struct ElectionCandidate {\n string name;\n uint256 votes;\n uint256 votesAgainst;\n CandidateState state;\n }\n\n /**\n * @dev Winner of each election category\n */\n struct ElectionWinner {\n string matricNo;\n ElectionCandidate electionCandidate;\n string category;\n }\n\n // ====================================================================\n // Voter Management Functions\n // ====================================================================\n\n /**\n * @dev Accredits a voter for this election\n * @param voterMatricNo The voter's matriculation number\n * @param accreditedBy Address that accredited the voter\n */\n function accrediteVoter(\n string calldata voterMatricNo,\n address accreditedBy\n ) external;\n\n /**\n * @dev Validates if a voter can vote in this election\n * @param voterName The voter's name\n * @param voterMatricNo The voter's matriculation number\n * @param votedBy Address attempting to vote\n * @return bool True if voter is valid for voting\n */\n function validateVoterForVoting(\n string memory voterName,\n string memory voterMatricNo,\n address votedBy\n ) external returns (bool);\n\n /**\n * @dev Processes votes for candidates\n * @param voterMatricNo The voter's matriculation number\n * @param voterName The voter's name\n * @param votedBy Address that cast the vote\n * @param candidatesList List of candidates being voted for\n */\n function voteCandidates(\n string calldata voterMatricNo,\n string calldata voterName,\n address votedBy,\n CandidateInfoDTO[] calldata candidatesList\n ) external;\n\n // ====================================================================\n // Validation Functions\n // ====================================================================\n\n /**\n * @dev Validates if an address is a polling unit\n * @param pollingUnit Address to validate\n * @return bool True if address is a polling unit\n */\n function validateAddressAsPollingUnit(\n address pollingUnit\n ) external returns (bool);\n\n /**\n * @dev Validates if an address is a polling officer\n * @param pollingOfficer Address to validate\n * @return bool True if address is a polling officer\n */\n function validateAddressAsPollingOfficer(\n address pollingOfficer\n ) external returns (bool);\n\n // ====================================================================\n // Getter Functions - Basic Info\n // ====================================================================\n\n /**\n * @dev Returns the election's unique token ID\n * @return uint256 The election token ID\n */\n function getElectionUniqueTokenId() external view returns (uint256);\n\n /**\n * @dev Returns the address that created this election\n * @return address Creator's address\n */\n function getCreatedBy() external view returns (address);\n\n /**\n * @dev Returns the election name\n * @return string Election name\n */\n function getElectionName() external view returns (string memory);\n\n /**\n * @dev Returns the election description\n * @return string Election description\n */\n function getElectionDescription() external view returns (string memory);\n\n /**\n * @dev Returns the current election state\n * @return ElectionState Current state\n */\n function getElectionState() external view returns (ElectionState);\n\n /**\n * @dev Returns the election start timestamp\n * @return uint256 Start timestamp\n */\n function getStartTimeStamp() external view returns (uint256);\n\n /**\n * @dev Returns the election end timestamp\n * @return uint256 End timestamp\n */\n function getEndTimeStamp() external view returns (uint256);\n\n /**\n * @dev Returns the election categories\n * @return string[] Array of categories\n */\n function getElectionCategories() external view returns (string[] memory);\n\n // ====================================================================\n // Getter Functions - Counts\n // ====================================================================\n\n /**\n * @dev Returns the count of registered voters\n * @return uint256 Registered voters count\n */\n function getRegisteredVotersCount() external view returns (uint256);\n\n /**\n * @dev Returns the count of accredited voters\n * @return uint256 Accredited voters count\n */\n function getAccreditedVotersCount() external view returns (uint256);\n\n /**\n * @dev Returns the count of voters who have voted\n * @return uint256 Voted voters count\n */\n function getVotedVotersCount() external view returns (uint256);\n\n /**\n * @dev Returns the count of registered candidates\n * @return uint256 Candidates count\n */\n function getRegisteredCandidatesCount() external view returns (uint256);\n\n /**\n * @dev Returns the count of polling officers\n * @return uint256 Polling officers count\n */\n function getPollingOfficerCount() external view returns (uint256);\n\n /**\n * @dev Returns the count of polling units\n * @return uint256 Polling units count\n */\n function getPollingUnitCount() external view returns (uint256);\n\n // ====================================================================\n // Getter Functions - Arrays\n // ====================================================================\n\n /**\n * @dev Returns all voters in the election\n * @return ElectionVoter[] Array of all voters\n */\n function getAllVoters() external view returns (ElectionVoter[] memory);\n\n /**\n * @dev Returns all accredited voters\n * @return ElectionVoter[] Array of accredited voters\n */\n function getAllAccreditedVoters()\n external\n view\n returns (ElectionVoter[] memory);\n\n /**\n * @dev Returns all voters who have voted\n * @return ElectionVoter[] Array of voted voters\n */\n function getAllVotedVoters() external view returns (ElectionVoter[] memory);\n\n /**\n * @dev Returns all candidates as DTOs (without vote counts)\n * @return CandidateInfoDTO[] Array of candidate DTOs\n */\n function getAllCandidatesInDto()\n external\n view\n returns (CandidateInfoDTO[] memory);\n\n /**\n * @dev Returns all candidates with vote counts (only after election ends)\n * @return ElectionCandidate[] Array of candidates with vote counts\n */\n function getAllCandidates()\n external\n view\n returns (ElectionCandidate[] memory);\n\n /**\n * @dev Returns winners for each category (handles ties)\n * @return ElectionWinner[][] Array of winners per category\n */\n function getEachCategoryWinner()\n external\n view\n returns (ElectionWinner[][] memory);\n\n /**\n * @dev Returns polling officers addresses\n * @return address[] Array of polling officer addresses\n */\n function getPollingOfficersAddresses()\n external\n view\n returns (address[] memory);\n\n /**\n * @dev Returns polling units addresses\n * @return address[] Array of polling unit addresses\n */\n function getPollingUnitsAddresses()\n external\n view\n returns (address[] memory);\n\n // ====================================================================\n // State Management\n // ====================================================================\n\n /**\n * @dev Updates the election state based on current time\n */\n function updateElectionState() external;\n}\n"},"src/interfaces/ICreateElection.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.20;\n\nimport {IElection} from \"./IElection.sol\";\n\ninterface ICreateElection {\n function createElection(address createdBy, uint256 electionUniqueTokenId, IElection.ElectionParams calldata params)\n external\n returns (address);\n}\n"},"src/CreateElection.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.20;\n\nimport {Election} from \"../src/Election.sol\";\nimport {ICreateElection} from \"../src/interfaces/ICreateElection.sol\";\nimport {IElection} from \"../src/interfaces/IElection.sol\";\nimport {Ownable} from \"@openzeppelin/contracts/access/Ownable.sol\";\n\ncontract CreateElection is ICreateElection, Ownable {\n constructor() Ownable(msg.sender) {}\n\n function createElection(address createdBy, uint256 electionUniqueTokenId, IElection.ElectionParams calldata params)\n public\n returns (address)\n {\n Election newElection =\n new Election({createdBy: createdBy, electionUniqueTokenId: electionUniqueTokenId, params: params});\n newElection.transferOwnership(owner());\n return address(newElection);\n }\n}\n"},"src/libraries/VotsEngineLib.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.21;\n\nimport {IElection} from \"../interfaces/IElection.sol\";\nimport {IVotsEngine} from \"../interfaces/IVotsEngine.sol\";\n\n/**\n * @title VotsEngineLib\n * @notice Library containing helper functions for VotsEngine\n */\nlibrary VotsEngineLib {\n // Custom errors\n error VotsEngine__ElectionNotFound();\n\n /**\n * @dev Validates election exists and returns the election contract instance\n * @param tokenToAddress Mapping from token ID to election address\n * @param electionTokenId The token ID of the election\n * @return election The IElection contract instance\n */\n function validateAndGetElection(mapping(uint256 => address) storage tokenToAddress, uint256 electionTokenId)\n internal\n view\n returns (IElection election)\n {\n address electionAddr = tokenToAddress[electionTokenId];\n if (electionAddr == address(0)) revert VotsEngine__ElectionNotFound();\n return IElection(electionAddr);\n }\n\n /**\n * @dev Gets election stats from the election contract\n * @param tokenToAddress Mapping from token ID to election address\n * @param electionTokenId The token ID of the election\n */\n function getElectionStats(mapping(uint256 => address) storage tokenToAddress, uint256 electionTokenId)\n internal\n view\n returns (\n uint256 registeredVotersCount,\n uint256 accreditedVotersCount,\n uint256 votedVotersCount,\n uint256 registeredCandidatesCount,\n uint256 pollingOfficerCount,\n uint256 pollingUnitCount\n )\n {\n IElection election = validateAndGetElection(tokenToAddress, electionTokenId);\n return (\n election.getRegisteredVotersCount(),\n election.getAccreditedVotersCount(),\n election.getVotedVotersCount(),\n election.getRegisteredCandidatesCount(),\n election.getPollingOfficerCount(),\n election.getPollingUnitCount()\n );\n }\n\n /**\n * @dev Creates election summary from election contract data\n * @param election The election contract instance\n * @return summary The election summary struct\n */\n function createElectionSummary(IElection election)\n internal\n view\n returns (IVotsEngine.ElectionSummary memory summary)\n {\n return IVotsEngine.ElectionSummary({\n electionId: election.getElectionUniqueTokenId(),\n electionName: election.getElectionName(),\n electionDescription: election.getElectionDescription(),\n state: election.getElectionState(),\n startTimestamp: election.getStartTimeStamp(),\n endTimestamp: election.getEndTimeStamp(),\n registeredVotersCount: election.getRegisteredVotersCount()\n });\n }\n\n /**\n * @dev Creates detailed election info from election contract data\n * @param election The election contract instance\n * @return info The detailed election information struct\n */\n function createElectionInfo(IElection election) internal view returns (IVotsEngine.ElectionInfo memory info) {\n return IVotsEngine.ElectionInfo({\n electionId: election.getElectionUniqueTokenId(),\n createdBy: election.getCreatedBy(),\n electionName: election.getElectionName(),\n electionDescription: election.getElectionDescription(),\n state: election.getElectionState(),\n startTimestamp: election.getStartTimeStamp(),\n endTimestamp: election.getEndTimeStamp(),\n registeredVotersCount: election.getRegisteredVotersCount(),\n accreditedVotersCount: election.getAccreditedVotersCount(),\n votedVotersCount: election.getVotedVotersCount(),\n electionCategories: election.getElectionCategories(),\n candidatesList: election.getAllCandidatesInDto(),\n pollingOfficers: election.getPollingOfficersAddresses(),\n pollingUnits: election.getPollingUnitsAddresses()\n });\n }\n\n /**\n * @dev Validates voter for voting through election contract\n * @param tokenToAddress Mapping from token ID to election address\n * @param voterMatricNo Voter's matriculation number\n * @param voterName Voter's name\n * @param electionTokenId The token ID of the election\n * @param sender The message sender address\n * @return isValid Whether the voter is valid for voting\n */\n function validateVoterForVoting(\n mapping(uint256 => address) storage tokenToAddress,\n string memory voterMatricNo,\n string memory voterName,\n uint256 electionTokenId,\n address sender\n ) internal returns (bool isValid) {\n IElection election = validateAndGetElection(tokenToAddress, electionTokenId);\n return election.validateVoterForVoting(voterName, voterMatricNo, sender);\n }\n\n /**\n * @dev Validates address as polling unit through election contract\n * @param tokenToAddress Mapping from token ID to election address\n * @param electionTokenId The token ID of the election\n * @param sender The message sender address\n * @return isValid Whether the address is a valid polling unit\n */\n function validateAddressAsPollingUnit(\n mapping(uint256 => address) storage tokenToAddress,\n uint256 electionTokenId,\n address sender\n ) internal returns (bool isValid) {\n IElection election = validateAndGetElection(tokenToAddress, electionTokenId);\n return election.validateAddressAsPollingUnit(sender);\n }\n\n /**\n * @dev Validates address as polling officer through election contract\n * @param tokenToAddress Mapping from token ID to election address\n * @param electionTokenId The token ID of the election\n * @param sender The message sender address\n * @return isValid Whether the address is a valid polling officer\n */\n function validateAddressAsPollingOfficer(\n mapping(uint256 => address) storage tokenToAddress,\n uint256 electionTokenId,\n address sender\n ) internal returns (bool isValid) {\n IElection election = validateAndGetElection(tokenToAddress, electionTokenId);\n return election.validateAddressAsPollingOfficer(sender);\n }\n}\n"},"lib/openzeppelin-contracts/contracts/access/Ownable.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)\n\npragma solidity ^0.8.20;\n\nimport {Context} from \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * The initial owner is set to the address provided by the deployer. This can\n * later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n address private _owner;\n\n /**\n * @dev The caller account is not authorized to perform an operation.\n */\n error OwnableUnauthorizedAccount(address account);\n\n /**\n * @dev The owner is not a valid owner account. (eg. `address(0)`)\n */\n error OwnableInvalidOwner(address owner);\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the address provided by the deployer as the initial owner.\n */\n constructor(address initialOwner) {\n if (initialOwner == address(0)) {\n revert OwnableInvalidOwner(address(0));\n }\n _transferOwnership(initialOwner);\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n _checkOwner();\n _;\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if the sender is not the owner.\n */\n function _checkOwner() internal view virtual {\n if (owner() != _msgSender()) {\n revert OwnableUnauthorizedAccount(_msgSender());\n }\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby disabling any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n _transferOwnership(address(0));\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n if (newOwner == address(0)) {\n revert OwnableInvalidOwner(address(0));\n }\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual {\n address oldOwner = _owner;\n _owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n}\n"},"src/interfaces/IVotsEngineFunctionClient.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.21;\n\n/**\n * @title IVotsEngineFunctionClient\n * @author Ayeni-yeniyan\n * @notice Interface for the VotsEngineFunctionClient contract\n * Defines the contract that handles Chainlink Functions requests for voter verification\n */\ninterface IVotsEngineFunctionClient {\n // ====================================================================\n // Errors\n // ====================================================================\n error VotsEngineFunctionClient__OnlyVotsEngine();\n error VotsEngineFunctionClient__InvalidRequestId();\n\n // ====================================================================\n // Events\n // ====================================================================\n event VerificationRequestSent(bytes32 indexed requestId, string voterMatricNo, uint256 electionTokenId);\n\n event VerificationRequestFulfilled(bytes32 indexed requestId, string voterMatricNo, uint256 electionTokenId);\n\n // ====================================================================\n // Structs\n // ====================================================================\n struct RequestInfo {\n uint256 electionTokenId;\n address messageSender;\n string voterMatricNo;\n bool exists;\n }\n\n // ====================================================================\n // Functions\n // ====================================================================\n\n /**\n * @dev Sends an HTTP request to an ID verification portal\n * @param ninNumber National identification number\n * @param firstName First name of the voter\n * @param lastName Last name of the voter\n * @param voterMatricNo Voter's matriculation number\n * @param slotId DON-hosted secrets slot ID\n * @param version DON-hosted secrets version\n * @param electionTokenId Token ID of the election\n * @param subscriptionId Chainlink Functions subscription ID\n * @param messageSender Original message sender who initiated the request\n * @return requestId The ID of the request\n */\n function sendVerificationRequestForElection(\n string calldata ninNumber,\n string calldata firstName,\n string calldata lastName,\n string calldata voterMatricNo,\n uint256 slotId,\n uint256 version,\n uint256 electionTokenId,\n uint64 subscriptionId,\n address messageSender\n ) external returns (bytes32 requestId);\n\n /**\n * @dev Returns the DON ID used by this contract\n * @return bytes32 The DON ID\n */\n function getDonId() external view returns (bytes32);\n\n /**\n * @dev Returns the VotsEngine contract address\n * @return address The VotsEngine contract address\n */\n function votsEngine() external view returns (address);\n\n /**\n * @dev Returns request information for a given request ID\n * @param requestId The request ID to query\n * @return RequestInfo The request information\n */\n function getRequestInfo(bytes32 requestId) external view returns (RequestInfo memory);\n\n /**\n * @dev Checks if a request exists\n * @param requestId The request ID to check\n * @return bool True if the request exists\n */\n function requestExists(bytes32 requestId) external view returns (bool);\n}\n"},"src/interfaces/IVotsEngine.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.21;\n\nimport {IElection} from \"./IElection.sol\";\n\n/**\n * @title IVotsEngine\n * @author Ayeni-yeniyan\n * @notice Interface for the VotsEngine contract\n * Defines the core voting system functionality\n */\ninterface IVotsEngine {\n // ====================================================================\n // Errors\n // ====================================================================\n error VotsEngine__DuplicateElectionName();\n error VotsEngine__ElectionNotFound();\n error VotsEngine__ElectionNameCannotBeEmpty();\n error VotsEngine__OnlyFunctionClient();\n error VotsEngine__FunctionClientNotSet();\n error VotsEngine__VaultAddressNotSet();\n\n // ====================================================================\n // Events\n // ====================================================================\n event ElectionContractedCreated(uint256 newElectionTokenId, string electionName);\n\n event FunctionClientUpdated(address indexed oldClient, address indexed newClient);\n event VaultAddressUpdated(address indexed oldVaultAddress, address indexed newVaultAddress);\n\n event VerificationRequestSent(bytes32 indexed requestId, string voterMatricNo, uint256 electionTokenId);\n\n // ====================================================================\n // Structs\n // ====================================================================\n struct ElectionSummary {\n uint256 electionId;\n string electionName;\n string electionDescription;\n IElection.ElectionState state;\n uint256 startTimestamp;\n uint256 endTimestamp;\n uint256 registeredVotersCount;\n }\n\n struct ElectionInfo {\n uint256 electionId;\n address createdBy;\n string electionName;\n string electionDescription;\n IElection.ElectionState state;\n uint256 startTimestamp;\n uint256 endTimestamp;\n uint256 registeredVotersCount;\n uint256 accreditedVotersCount;\n uint256 votedVotersCount;\n string[] electionCategories;\n address[] pollingOfficers;\n address[] pollingUnits;\n IElection.CandidateInfoDTO[] candidatesList;\n }\n\n // ====================================================================\n // Core Functions\n // ====================================================================\n\n /**\n * @dev Sets the function client address (only owner)\n * @param _functionClient Address of the VotsEngineFunctionClient contract\n */\n function setFunctionClient(address _functionClient) external;\n\n /**\n * @dev Creates a new election\n * @param params Election parameters\n */\n function createElection(IElection.ElectionParams calldata params) external;\n\n /**\n * @dev Accredits a voter for an election\n * @param voterMatricNo Voter's matriculation number\n * @param electionTokenId Token ID of the election\n */\n function accrediteVoter(string calldata voterMatricNo, uint256 electionTokenId) external;\n\n /**\n * @dev Called by VotsEngineFunctionClient to fulfill voter accreditation\n * @param voterMatricNo The voter's matriculation number\n * @param electionTokenId The election token ID\n * @param messageSender The original message sender who initiated the request\n */\n function fulfillVoterAccreditation(string calldata voterMatricNo, uint256 electionTokenId, address messageSender)\n external;\n\n /**\n * @dev Sends a verification request through the function client\n * @param ninNumber National identification number\n * @param firstName First name of the voter\n * @param lastName Last name of the voter\n * @param voterMatricNo Voter's matriculation number\n * @param slotId DON-hosted secrets slot ID\n * @param version DON-hosted secrets version\n * @param electionTokenId Token ID of the election\n * @param subscriptionId Chainlink Functions subscription ID\n * @return requestId The ID of the request\n */\n function sendVerificationRequestForElection(\n string calldata ninNumber,\n string calldata firstName,\n string calldata lastName,\n string calldata voterMatricNo,\n uint256 slotId,\n uint256 version,\n uint256 electionTokenId,\n uint64 subscriptionId\n ) external returns (bytes32 requestId);\n\n /**\n * @dev Allows a voter to vote for candidates\n * @param voterMatricNo Voter's matriculation number\n * @param voterName Voter's name\n * @param candidatesList List of candidates to vote for\n * @param electionTokenId Token ID of the election\n */\n function voteCandidates(\n string calldata voterMatricNo,\n string calldata voterName,\n IElection.CandidateInfoDTO[] calldata candidatesList,\n uint256 electionTokenId\n ) external;\n\n // ====================================================================\n // Validation Functions\n // ====================================================================\n\n /**\n * @dev Validates a voter for voting\n * @param voterMatricNo Voter's matriculation number\n * @param voterName Voter's name\n * @param electionTokenId Token ID of the election\n * @return bool True if voter is valid for voting\n */\n function validateVoterForVoting(string memory voterMatricNo, string memory voterName, uint256 electionTokenId)\n external\n returns (bool);\n\n /**\n * @dev Validates an address as a polling unit\n * @param electionTokenId Token ID of the election\n * @return bool True if address is a valid polling unit\n */\n function validateAddressAsPollingUnit(uint256 electionTokenId) external returns (bool);\n\n /**\n * @dev Validates an address as a polling officer\n * @param electionTokenId Token ID of the election\n * @return bool True if address is a valid polling officer\n */\n function validateAddressAsPollingOfficer(uint256 electionTokenId) external returns (bool);\n\n // ====================================================================\n // Getter Functions - Engine Level\n // ====================================================================\n\n /**\n * @dev Returns the total number of elections created\n * @return uint256 Total election count\n */\n function getTotalElectionsCount() external view returns (uint256);\n\n /**\n * @dev Returns the election contract address for a given token ID\n * @param electionTokenId The token ID of the election\n * @return address Election contract address\n */\n function getElectionAddress(uint256 electionTokenId) external view returns (address);\n\n /**\n * @dev Returns the token ID for a given election name\n * @param electionName The name of the election\n * @return uint256 Token ID (returns 0 if not found)\n */\n function getElectionTokenId(string calldata electionName) external view returns (uint256);\n\n /**\n * @dev Checks if an election exists by token ID\n * @param electionTokenId The token ID of the election\n * @return bool True if election exists\n */\n function electionExistsByTokenId(uint256 electionTokenId) external view returns (bool);\n\n /**\n * @dev Returns the current owner of the contract\n * @return address The owner address\n */\n function getOwner() external view returns (address);\n\n /**\n * @dev Returns the current function client address\n * @return address The function client address\n */\n function getFunctionClient() external view returns (address);\n\n // ====================================================================\n // Getter Functions - Election Data Forwarding\n // ====================================================================\n\n /**\n * @dev Returns basic election information\n * @param electionTokenId The token ID of the election\n * @return ElectionInfo Election information\n */\n function getElectionInfo(uint256 electionTokenId) external view returns (ElectionInfo memory);\n\n /**\n * @dev Returns election statistics\n * @param electionTokenId The token ID of the election\n * @return registeredVotersCount Number of registered voters\n * @return accreditedVotersCount Number of accredited voters\n * @return votedVotersCount Number of voters who have voted\n * @return registeredCandidatesCount Number of registered candidates\n * @return pollingOfficerCount Number of polling officers\n * @return pollingUnitCount Number of polling units\n */\n function getElectionStats(uint256 electionTokenId)\n external\n view\n returns (\n uint256 registeredVotersCount,\n uint256 accreditedVotersCount,\n uint256 votedVotersCount,\n uint256 registeredCandidatesCount,\n uint256 pollingOfficerCount,\n uint256 pollingUnitCount\n );\n\n /**\n * @dev Returns all voters for an election\n * @param electionTokenId The token ID of the election\n * @return IElection.ElectionVoter[] Array of voters\n */\n function getAllVoters(uint256 electionTokenId) external view returns (IElection.ElectionVoter[] memory);\n\n /**\n * @dev Returns all accredited voters for an election\n * @param electionTokenId The token ID of the election\n * @return IElection.ElectionVoter[] Array of accredited voters\n */\n function getAllAccreditedVoters(uint256 electionTokenId) external view returns (IElection.ElectionVoter[] memory);\n\n /**\n * @dev Returns all voters who have voted for an election\n * @param electionTokenId The token ID of the election\n * @return IElection.ElectionVoter[] Array of voters who have voted\n */\n function getAllVotedVoters(uint256 electionTokenId) external view returns (IElection.ElectionVoter[] memory);\n\n /**\n * @dev Returns all candidates for an election (as DTOs)\n * @param electionTokenId The token ID of the election\n * @return IElection.CandidateInfoDTO[] Array of candidate DTOs\n */\n function getAllCandidatesInDto(uint256 electionTokenId)\n external\n view\n returns (IElection.CandidateInfoDTO[] memory);\n\n /**\n * @dev Returns all candidates with vote counts (only after election ends)\n * @param electionTokenId The token ID of the election\n * @return IElection.ElectionCandidate[] Array of candidates with vote counts\n */\n function getAllCandidates(uint256 electionTokenId) external returns (IElection.ElectionCandidate[] memory);\n\n /**\n * @dev Returns winners for each category (handles ties)\n * @param electionTokenId The token ID of the election\n * @return IElection.ElectionWinner[][] Array of winners for each category\n */\n function getEachCategoryWinner(uint256 electionTokenId) external returns (IElection.ElectionWinner[][] memory);\n\n // ====================================================================\n // Utility Functions\n // ====================================================================\n\n /**\n * @dev Updates election state for a specific election\n * @param electionTokenId The token ID of the election\n */\n function updateElectionState(uint256 electionTokenId) external;\n\n /**\n * @dev Returns a summary of all elections (basic info only)\n * @return electionsSummaryList Array of election summaries\n */\n function getAllElectionsSummary() external view returns (ElectionSummary[] memory electionsSummaryList);\n}\n"},"src/interfaces/IVotsElectionNft.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.24;\n\n/**\n * @title IVotsElectionNft\n * @notice Interface for the VotsElectionNft contract\n */\ninterface IVotsElectionNft {\n /**\n * @dev Struct to store election NFT data\n */\n struct ElectionNftData {\n uint256 electionTokenId;\n string electionName;\n address creator;\n uint256 creationTimestamp;\n string electionDescription;\n uint256 startTime;\n uint256 endTime;\n }\n\n /**\n * @dev Event emitted when an election NFT is minted\n */\n event ElectionNftMinted(\n uint256 indexed nftTokenId, uint256 indexed electionTokenId, address indexed creator, string electionName\n );\n\n /**\n * @dev Mints an NFT to the election creator\n */\n function mintElectionNft(\n address creator,\n uint256 electionTokenId,\n string calldata electionName,\n string calldata electionDescription,\n uint256 startTime,\n uint256 endTime\n ) external returns (uint256 nftTokenId);\n\n /**\n * @dev Returns the total number of NFTs minted\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns election data for a given NFT token ID\n */\n function getElectionData(uint256 nftTokenId) external view returns (ElectionNftData memory);\n\n /**\n * @dev Returns NFT token ID for a given election token ID\n */\n function getNftTokenByElectionId(uint256 electionTokenId) external view returns (uint256);\n\n /**\n * @dev Returns all NFTs owned by an address\n */\n function getOwnedTokens(address owner) external view returns (uint256[] memory);\n\n /**\n * @dev Checks if an NFT exists for a given election\n */\n function electionNftExists(uint256 electionTokenId) external view returns (bool);\n}\n"},"src/Election.sol":{"content":"// Layout of Contract:\n// version\n// imports\n// errors\n// interfaces, libraries, contracts\n// Type declarations\n// State variables\n// Events\n// Modifiers\n// Functions\n\n// Layout of Functions:\n// constructor\n// receive function (if exists)\n// fallback function (if exists)\n// external\n// public\n// internal\n// private\n// view & pure functions\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.21;\n\n// Imports\nimport {Ownable} from \"@openzeppelin/contracts/access/Ownable.sol\";\nimport {IElection} from \"./interfaces/IElection.sol\";\nimport {FunctionsClient} from \"chainlink/contracts/src/v0.8/functions/v1_3_0/FunctionsClient.sol\";\n\n/**\n * @title Election\n * @author Ayeni-yeniyan\n * @notice This election contract stores the election information for an election in the VotsEngine.\n * Each election is owned by the VotsEngine. It holds a createdBy field which keeps the information of the election creator\n */\ncontract Election is IElection, Ownable {\n // ====================================================================\n // Errors\n // ====================================================================\n error Election__VoterInfoDTOCannotBeEmpty();\n error Election__UnregisteredVoterCannotBeAccredited();\n error Election__OnlyPollingUnitAllowed(address errorAddress);\n error Election__OnlyPollingOfficerAllowed(address errorAddress);\n error Election__AddressCanOnlyHaveOneRole();\n error Election__CandidatesInfoDTOCannotBeEmpty();\n error Election__AllCategoriesMustHaveOnlyOneVotedCandidate();\n error Election__InvalidStartTimeStamp();\n error Election__InvalidEndTimeStamp();\n error Election__InvalidElectionState(\n ElectionState expected,\n ElectionState actual\n );\n error Election__UnauthorizedAccountOnlyVotsEngineCanCallContract(\n address account\n );\n error Election__VoterCannotBeValidated();\n error Election__VoterAlreadyVoted();\n error Election__VoterAlreadyAccredited();\n error Election__UnknownVoter(string matricNo);\n error Election__UnaccreditedVoter(string matricNo);\n error Election__PollingOfficerAndUnitCannotBeEmpty();\n error Election__DuplicateVoter(string matricNo);\n error Election__DuplicateCandidate(string matricNo);\n error Election__DuplicateCategory();\n error Election__InvalidVote();\n error Election__RegisterCategoriesMustBeCalledBeforeRegisterVoters();\n error Election__InvalidCategory(string categoryName);\n\n // ====================================================================\n // State variables\n // ====================================================================\n /// @dev Creator of the election\n address private immutable _createdBy;\n\n /// @dev The unique token identifier for this election\n uint256 private immutable _electionUniqueTokenId;\n\n /// @dev The startDate for this election\n uint256 private immutable _startTimeStamp;\n\n /// @dev The end date for this election\n uint256 private immutable _endTimeStamp;\n\n /// @dev The total number of registered voters\n string[] private _registeredVotersList;\n\n /// @dev The total number of accredited voters\n uint256 private _accreditedVotersCount;\n\n /// @dev The total number of voters who have voted\n uint256 private _votedVotersCount;\n\n /// @dev List of registered candidates\n string[] private _registeredCandidatesList;\n\n /// @dev The unique election name for this election\n string private _electionName;\n\n /// @dev mapping of matric number(Unique identifier) to voter\n mapping(string matricNo => ElectionVoter voter) private _votersMap;\n\n /// @dev map of category to candidatenames to candidate\n mapping(string categoryName => mapping(string candidateMatricNo => ElectionCandidate electionCandidates))\n private _candidatesMap;\n\n /// @dev mapping of valid polling addresses\n mapping(address pollingAddress => bool isValid)\n private _allowedPollingUnits;\n\n /// Store polling officer addresses\n address[] private _pollingOfficersAddressList;\n\n /// Store polling unit addresses\n address[] private _pollingUnitsAddressList;\n\n /// @dev mapping of valid polling officer addresses\n mapping(address pollingOfficerAddress => bool isValid)\n private _allowedPollingOfficers;\n\n /// @dev List of all the categories in this election\n string[] private _electionCategories;\n\n /// @dev Election state\n ElectionState private _electionState;\n\n string private _description;\n\n // ====================================================================\n // Events\n // ====================================================================\n event AccreditedVoter(string matricNo);\n event VoterVoted();\n event ValidateAddressResult(bool result);\n\n // ====================================================================\n // Modifiers\n // ====================================================================\n\n /**\n * @dev Ensures the function is only called when the election is started\n */\n modifier onElectionStarted() {\n _updateElectionState();\n if (_electionState != ElectionState.STARTED) {\n revert Election__InvalidElectionState(\n ElectionState.STARTED,\n _electionState\n );\n }\n _;\n }\n\n /**\n * @dev Ensures the function is only called when the election has ended\n */\n modifier onElectionEnded() {\n // _updateElectionState();\n if (block.timestamp < _endTimeStamp) {\n revert Election__InvalidElectionState(\n ElectionState.ENDED,\n _electionState\n );\n }\n _;\n }\n\n modifier pollingUnitOnly(address pollingUnitAddress) {\n if (!_allowedPollingUnits[pollingUnitAddress]) {\n revert Election__OnlyPollingUnitAllowed(pollingUnitAddress);\n }\n _;\n }\n\n modifier pollingOfficerOnly(address pollingOfficerAddress) {\n if (!_allowedPollingOfficers[pollingOfficerAddress]) {\n revert Election__OnlyPollingOfficerAllowed(pollingOfficerAddress);\n }\n _;\n }\n\n modifier noUnknown(string memory matricNo) {\n if (_votersMap[matricNo].voterState == VoterState.UNKNOWN) {\n revert Election__UnknownVoter(matricNo);\n }\n _;\n }\n\n modifier accreditedVoterOnly(string memory matricNo) {\n if (_votersMap[matricNo].voterState == VoterState.VOTED) {\n revert Election__VoterAlreadyVoted();\n }\n if (_votersMap[matricNo].voterState != VoterState.ACCREDITED) {\n revert Election__UnaccreditedVoter(matricNo);\n }\n _;\n }\n\n // ====================================================================\n // Functions\n // ====================================================================\n\n /**\n * @dev Constructor to create a new election\n * @param createdBy Address of the creator\n * @param electionUniqueTokenId Unique identifier for this election\n * @param params Election params\n */\n constructor(\n address createdBy,\n uint256 electionUniqueTokenId,\n ElectionParams memory params\n ) Ownable(msg.sender) {\n if (block.timestamp >= params.startTimeStamp) {\n revert Election__InvalidStartTimeStamp();\n }\n if (params.startTimeStamp >= params.endTimeStamp) {\n revert Election__InvalidEndTimeStamp();\n }\n _createdBy = createdBy;\n _electionUniqueTokenId = electionUniqueTokenId;\n _electionName = params.electionName;\n _description = params.description;\n\n _startTimeStamp = params.startTimeStamp;\n _endTimeStamp = params.endTimeStamp;\n\n _electionState = ElectionState.OPENED;\n\n _validateCategories(params.electionCategories);\n _registerCandidates(params.candidatesList);\n _registerVoters(params.votersList);\n _registerOfficersAndUnits({\n pollingOfficerAddresses: params.pollingOfficerAddresses,\n pollingUnitAddresses: params.pollingUnitAddresses\n });\n }\n\n // ====================================================================\n // Public functions\n // ====================================================================\n function validateVoterForVoting(\n string memory name,\n string memory matricNo,\n address pollingUnitAddress\n )\n public\n pollingUnitOnly(pollingUnitAddress)\n noUnknown(matricNo)\n returns (bool validAddress)\n {\n ElectionVoter memory voter = _votersMap[matricNo];\n emit ValidateAddressResult(validAddress);\n return\n compareStrings(voter.name, name) &&\n voter.voterState == VoterState.ACCREDITED;\n }\n\n function validateAddressAsPollingUnit(\n address pollingUnitAddress\n ) public pollingUnitOnly(pollingUnitAddress) returns (bool validAddress) {\n validAddress = _allowedPollingUnits[pollingUnitAddress];\n emit ValidateAddressResult(validAddress);\n }\n\n function validateAddressAsPollingOfficer(\n address pollingUnitAddress\n )\n public\n pollingOfficerOnly(pollingUnitAddress)\n returns (bool validAddress)\n {\n validAddress = _allowedPollingOfficers[pollingUnitAddress];\n emit ValidateAddressResult(validAddress);\n }\n\n /**\n * @dev Returns Returns a list of all voters\n */\n function getAllVoters() public view returns (ElectionVoter[] memory) {\n ElectionVoter[] memory all = new ElectionVoter[](\n _registeredVotersList.length\n );\n for (uint256 i = 0; i < _registeredVotersList.length; i++) {\n all[i] = _votersMap[_registeredVotersList[i]];\n }\n return all;\n }\n\n /**\n * @dev Returns Returns a list of all accredited voters\n */\n function getAllAccreditedVoters()\n public\n view\n returns (ElectionVoter[] memory)\n {\n uint256 voterCount;\n ElectionVoter[] memory all = new ElectionVoter[](\n _accreditedVotersCount\n );\n for (uint256 i = 0; i < _registeredVotersList.length; i++) {\n ElectionVoter memory voter = _votersMap[_registeredVotersList[i]];\n if (voter.voterState == VoterState.ACCREDITED) {\n all[voterCount] = voter;\n voterCount++;\n }\n }\n return all;\n }\n\n /**\n * @dev Returns Returns a list of all Voted voters\n */\n function getAllVotedVoters() public view returns (ElectionVoter[] memory) {\n uint256 voterCount;\n ElectionVoter[] memory all = new ElectionVoter[](_votedVotersCount);\n for (uint256 i = 0; i < _registeredVotersList.length; i++) {\n ElectionVoter memory voter = _votersMap[_registeredVotersList[i]];\n if (voter.voterState == VoterState.VOTED) {\n all[voterCount] = voter;\n voterCount++;\n }\n }\n return all;\n }\n\n /**\n * @dev Returns Returns a list of all Candidates\n */\n function getAllCandidatesInDto()\n public\n view\n returns (CandidateInfoDTO[] memory)\n {\n uint256 candidateCount;\n CandidateInfoDTO[] memory all = new CandidateInfoDTO[](\n _registeredCandidatesList.length\n );\n for (uint256 i = 0; i < _electionCategories.length; i++) {\n for (uint256 j = 0; j < _registeredCandidatesList.length; j++) {\n ElectionCandidate memory candidate = _candidatesMap[\n _electionCategories[i]\n ][_registeredCandidatesList[j]];\n if (candidate.state == CandidateState.REGISTERED) {\n all[candidateCount] = CandidateInfoDTO({\n name: candidate.name,\n matricNo: _registeredCandidatesList[j],\n category: _electionCategories[i],\n voteFor: 0,\n voteAgainst: 0\n });\n candidateCount++;\n }\n }\n }\n return all;\n }\n\n /**\n * @dev Returns Returns a list of all Candidates\n */\n function getAllCandidates()\n public\n view\n onElectionEnded\n returns (ElectionCandidate[] memory)\n {\n uint256 candidateCount;\n ElectionCandidate[] memory all = new ElectionCandidate[](\n _registeredCandidatesList.length\n );\n for (uint256 i = 0; i < _electionCategories.length; i++) {\n for (uint256 j = 0; j < _registeredCandidatesList.length; j++) {\n ElectionCandidate memory candidate = _candidatesMap[\n _electionCategories[i]\n ][_registeredCandidatesList[j]];\n if (candidate.state == CandidateState.REGISTERED) {\n all[candidateCount] = candidate;\n candidateCount++;\n }\n }\n }\n return all;\n }\n\n /**\n * @dev Returns Returns a list of all Candidates\n */\n function getEachCategoryWinner()\n public\n view\n onElectionEnded\n returns (ElectionWinner[][] memory)\n {\n // Assign to _electionCategories.length.\n // We will be returning a list containing a list\n // that holds the candidate that won since it is possible to tie\n ElectionWinner[][] memory allWinners = new ElectionWinner[][](\n _electionCategories.length\n );\n for (uint256 i = 0; i < _electionCategories.length; i++) {\n string memory category = _electionCategories[i];\n uint256 maxVotes;\n uint256 winnerCount;\n\n // Find the maxVote for this category\n for (uint256 j = 0; j < _registeredCandidatesList.length; j++) {\n ElectionCandidate memory candidate = _candidatesMap[category][\n _registeredCandidatesList[j]\n ];\n if (\n candidate.state == CandidateState.REGISTERED &&\n candidate.votes > maxVotes\n ) {\n maxVotes = candidate.votes;\n }\n }\n // Count winners with max votes\n if (maxVotes > 0) {\n for (uint256 j = 0; j < _registeredCandidatesList.length; j++) {\n ElectionCandidate memory candidate = _candidatesMap[\n category\n ][_registeredCandidatesList[j]];\n if (\n candidate.state == CandidateState.REGISTERED &&\n candidate.votes == maxVotes\n ) {\n winnerCount++;\n }\n }\n // Collect all winners\n ElectionWinner[] memory categoryWinners = new ElectionWinner[](\n winnerCount\n );\n uint256 currentWinnerIndex;\n for (uint256 j = 0; j < _registeredCandidatesList.length; j++) {\n string memory candidateMatricNo = _registeredCandidatesList[\n j\n ];\n ElectionCandidate memory candidate = _candidatesMap[\n category\n ][candidateMatricNo];\n\n if (\n candidate.state == CandidateState.REGISTERED &&\n candidate.votes == maxVotes\n ) {\n categoryWinners[currentWinnerIndex] = ElectionWinner({\n matricNo: candidateMatricNo,\n electionCandidate: candidate,\n category: category\n });\n currentWinnerIndex++;\n }\n }\n allWinners[i] = categoryWinners;\n } else {\n // No votes cast in this category\n allWinners[i] = new ElectionWinner[](0);\n }\n }\n return allWinners;\n }\n\n /**\n * @dev Returns the address of the election creator\n * @return address Creator's address\n */\n function getCreatedBy() public view returns (address) {\n return _createdBy;\n }\n\n /**\n * @dev Returns the description of the election\n * @return Election description\n */\n function getElectionDescription() public view returns (string memory) {\n return _description;\n }\n\n /**\n * @dev Returns the unique token identifier for this election\n * @return uint256 Election unique token ID\n */\n function getElectionUniqueTokenId() public view returns (uint256) {\n return _electionUniqueTokenId;\n }\n\n /**\n * @dev Returns the start timestamp for this election\n * @return uint256 Start timestamp\n */\n function getStartTimeStamp() public view returns (uint256) {\n return _startTimeStamp;\n }\n\n /**\n * @dev Returns the end timestamp for this election\n * @return uint256 End timestamp\n */\n function getEndTimeStamp() public view returns (uint256) {\n return _endTimeStamp;\n }\n\n /**\n * @dev Returns the name of this election\n * @return string Election name\n */\n function getElectionName() public view returns (string memory) {\n return _electionName;\n }\n\n /**\n * @dev Returns the current state of the election\n * @return ElectionState Current election state\n */\n function getElectionState() public view returns (ElectionState) {\n // Create a storage variable to hold the current state\n ElectionState currentState = _electionState;\n\n // Check if state needs updating based on current time\n uint256 currentTs = block.timestamp;\n if (\n currentTs >= _startTimeStamp &&\n currentTs < _endTimeStamp &&\n currentState != ElectionState.STARTED\n ) {\n currentState = ElectionState.STARTED;\n }\n if (currentTs >= _endTimeStamp) {\n currentState = ElectionState.ENDED;\n }\n\n return currentState;\n }\n\n /**\n * @dev Returns the total number of registered voters\n * @return uint256 Number of registered voters\n */\n function getRegisteredVotersCount() public view returns (uint256) {\n return _registeredVotersList.length;\n }\n\n /**\n * @dev Returns the total number of accredited voters\n * @return uint256 Number of accredited voters\n */\n function getAccreditedVotersCount() public view returns (uint256) {\n return _accreditedVotersCount;\n }\n\n /**\n * @dev Returns the total number of voters who have voted\n * @return uint256 Number of voters who have voted\n */\n function getVotedVotersCount() public view returns (uint256) {\n return _votedVotersCount;\n }\n\n /**\n * @dev Returns the total number of polling officers\n * @return uint256 Number of polling officers\n */\n function getPollingOfficerCount() public view returns (uint256) {\n return _pollingOfficersAddressList.length;\n }\n\n /**\n * @dev Returns the total number of polling units\n * @return uint256 Number of polling units\n */\n function getPollingUnitCount() public view returns (uint256) {\n return _pollingUnitsAddressList.length;\n }\n\n /**\n * @dev Returns the address of polling officers\n * @return uint256 Number of polling officers\n */\n function getPollingOfficersAddresses()\n public\n view\n returns (address[] memory)\n {\n return _pollingOfficersAddressList;\n }\n\n /**\n * @dev Returns the address of polling units\n * @return uint256 Number of polling units\n */\n function getPollingUnitsAddresses() public view returns (address[] memory) {\n return _pollingUnitsAddressList;\n }\n\n /**\n * @dev Returns the total number of registered candidates\n * @return uint256 Number of registered candidates\n */\n function getRegisteredCandidatesCount() public view returns (uint256) {\n return _registeredCandidatesList.length;\n }\n\n function getElectionCategories() public view returns (string[] memory) {\n return _electionCategories;\n }\n\n /**\n * @dev Accredits a voter with valid matric number\n * @param voterMatricNo The matric number of the voter\n * @param pollingOfficerAddress Address of the polling officer\n */\n function accrediteVoter(\n string memory voterMatricNo,\n address pollingOfficerAddress\n )\n public\n onlyOwner\n pollingOfficerOnly(pollingOfficerAddress)\n onElectionStarted\n noUnknown(voterMatricNo)\n {\n if (_votersMap[voterMatricNo].voterState == VoterState.ACCREDITED) {\n revert Election__VoterAlreadyAccredited();\n }\n _votersMap[voterMatricNo].voterState = VoterState.ACCREDITED;\n _accreditedVotersCount++;\n emit AccreditedVoter(voterMatricNo);\n }\n\n /**\n * @dev Allows an accredited voter to vote for candidates\n * @param voterMatricNo The matric number of the voter\n * @param voterName The name of the voter for validation\n * @param pollingUnitAddress Address of the polling unit\n * @param candidatesList List of candidates being voted for\n */\n function voteCandidates(\n string memory voterMatricNo,\n string memory voterName,\n address pollingUnitAddress,\n CandidateInfoDTO[] memory candidatesList\n )\n public\n onlyOwner\n pollingUnitOnly(pollingUnitAddress)\n onElectionStarted\n noUnknown(voterMatricNo)\n accreditedVoterOnly(voterMatricNo)\n {\n if (candidatesList.length < 1) {\n revert Election__CandidatesInfoDTOCannotBeEmpty();\n }\n if (candidatesList.length != _electionCategories.length) {\n revert Election__AllCategoriesMustHaveOnlyOneVotedCandidate();\n }\n if (!compareStrings(voterName, _votersMap[voterMatricNo].name)) {\n revert Election__VoterCannotBeValidated();\n }\n for (uint256 i = 0; i < candidatesList.length; i++) {\n CandidateInfoDTO memory candidate = candidatesList[i];\n if (!_isValidCategory(candidate.category)) {\n revert Election__InvalidCategory(candidate.category);\n }\n if (candidate.voteFor == candidate.voteAgainst) {\n revert Election__InvalidVote();\n }\n if (candidate.voteFor > candidate.voteAgainst) {\n _candidatesMap[candidate.category][candidate.matricNo].votes++;\n } else {\n _candidatesMap[candidate.category][candidate.matricNo]\n .votesAgainst++;\n }\n }\n _votersMap[voterMatricNo].voterState = VoterState.VOTED;\n _votedVotersCount++;\n emit VoterVoted();\n }\n\n /**\n * @dev Updates the election state based on current time\n */\n function updateElectionState() public {\n _updateElectionState();\n }\n\n // ====================================================================\n // Internal functions\n // ====================================================================\n\n /**\n * @dev Checks if the categoryName is valid\n */\n function _isValidCategory(\n string memory categoryName\n ) internal view returns (bool) {\n for (uint256 i = 0; i < _electionCategories.length; i++) {\n if (compareStrings(categoryName, _electionCategories[i])) {\n return true;\n }\n }\n return false;\n }\n\n function _containsDuplicateCategory(\n string[] memory votedCategories,\n string memory newCategory\n ) internal pure returns (bool) {\n for (uint256 i = 0; i < votedCategories.length; i++) {\n if (compareStrings(newCategory, votedCategories[i])) {\n return true;\n }\n }\n return false;\n }\n\n function _validateCategories(string[] memory votedCategories) internal {\n for (uint256 i = 0; i < votedCategories.length; i++) {\n if (\n _containsDuplicateCategory(\n _electionCategories,\n votedCategories[i]\n )\n ) {\n revert Election__DuplicateCategory();\n } else {\n _electionCategories.push(votedCategories[i]);\n }\n }\n }\n\n /**\n * @dev Updates the election state based on current timestamp\n */\n function _updateElectionState() internal {\n uint256 currentTs = block.timestamp;\n if (\n currentTs >= _startTimeStamp &&\n currentTs < _endTimeStamp &&\n _electionState != ElectionState.STARTED\n ) {\n _electionState = ElectionState.STARTED;\n }\n if (currentTs >= _endTimeStamp) {\n _electionState = ElectionState.ENDED;\n }\n }\n\n /**\n * @dev Override function to check owner with custom error\n */\n function _checkOwner() internal view override {\n if (owner() != _msgSender()) {\n revert Election__UnauthorizedAccountOnlyVotsEngineCanCallContract(\n _msgSender()\n );\n }\n }\n\n /**\n * @dev Registers voters from the provided list\n * @param votersList Array of unregistered voters to register\n */\n function _registerVoters(\n VoterInfoDTO[] memory votersList\n ) internal onlyOwner {\n if (votersList.length < 1) {\n revert Election__VoterInfoDTOCannotBeEmpty();\n }\n // add all voters to votersList\n for (uint256 i = 0; i < votersList.length; i++) {\n VoterInfoDTO memory voter = votersList[i];\n // create an electionVoter from voter\n ElectionVoter memory registeredVoter = ElectionVoter({\n name: voter.name,\n voterState: VoterState.REGISTERED\n });\n // add to votersList if the state is unknown\n if (_votersMap[voter.matricNo].voterState == VoterState.UNKNOWN) {\n _votersMap[voter.matricNo] = registeredVoter;\n } else {\n revert Election__DuplicateVoter(voter.matricNo);\n }\n _registeredVotersList.push(voter.matricNo);\n }\n }\n\n /**\n * @dev Registers candidates from the provided list\n * @param candidatesList Array of unregistered candidates to register\n */\n function _registerCandidates(\n CandidateInfoDTO[] memory candidatesList\n ) internal onlyOwner {\n if (candidatesList.length < 1) {\n revert Election__CandidatesInfoDTOCannotBeEmpty();\n }\n // add all Candidates to _candidateMap\n for (uint256 i = 0; i < candidatesList.length; i++) {\n CandidateInfoDTO memory candidate = candidatesList[i];\n // create an ElectionCandidate from candidate\n ElectionCandidate memory registeredCandidate = ElectionCandidate({\n name: candidate.name,\n votes: 0,\n votesAgainst: 0,\n state: CandidateState.REGISTERED\n });\n if (_electionCategories.length == 0) {\n revert Election__RegisterCategoriesMustBeCalledBeforeRegisterVoters();\n }\n // Check that it is a valid election category\n for (uint256 j = 0; j < _electionCategories.length; j++) {\n if (\n compareStrings(_electionCategories[j], candidate.category)\n ) {\n if (\n _candidatesMap[candidate.category][candidate.matricNo]\n .state == CandidateState.UNKNOWN\n ) {\n // add to votersList\n _candidatesMap[candidate.category][\n candidate.matricNo\n ] = registeredCandidate;\n } else {\n revert Election__DuplicateCandidate(candidate.matricNo);\n }\n _registeredCandidatesList.push(candidate.matricNo);\n break;\n }\n if (j + 1 == _electionCategories.length) {\n revert Election__InvalidCategory(candidate.category);\n }\n }\n }\n }\n\n /**\n * @dev Registers polling officers and polling units\n * @param pollingOfficerAddresses Array of polling officer addresses\n * @param pollingUnitAddresses Array of polling unit addresses\n */\n function _registerOfficersAndUnits(\n address[] memory pollingOfficerAddresses,\n address[] memory pollingUnitAddresses\n ) internal onlyOwner {\n if (\n pollingOfficerAddresses.length < 1 ||\n pollingUnitAddresses.length < 1\n ) {\n revert Election__PollingOfficerAndUnitCannotBeEmpty();\n }\n\n for (uint256 i = 0; i < pollingOfficerAddresses.length; i++) {\n address officerAddress = pollingOfficerAddresses[i];\n if (officerAddress == _createdBy) {\n revert Election__AddressCanOnlyHaveOneRole();\n }\n _allowedPollingOfficers[officerAddress] = true;\n }\n for (uint256 i = 0; i < pollingUnitAddresses.length; i++) {\n address unitAddress = pollingUnitAddresses[i];\n if (\n unitAddress == _createdBy ||\n _allowedPollingOfficers[unitAddress]\n ) {\n revert Election__AddressCanOnlyHaveOneRole();\n }\n _allowedPollingUnits[unitAddress] = true;\n }\n\n _pollingOfficersAddressList = pollingOfficerAddresses;\n _pollingUnitsAddressList = pollingUnitAddresses;\n }\n\n /**\n * @dev Compares two strings by comparing their keccak256 hashes\n * @param first First string to compare\n * @param second Second string to compare\n * @return bool True if strings are equal, false otherwise\n */\n function compareStrings(\n string memory first,\n string memory second\n ) public pure returns (bool) {\n return\n keccak256(abi.encodePacked(first)) ==\n keccak256(abi.encodePacked(second));\n }\n}\n"},"lib/openzeppelin-contracts/contracts/utils/Context.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n"},"lib/chainlink/contracts/src/v0.8/functions/v1_3_0/FunctionsClient.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.19;\n\nimport {IFunctionsRouter} from \"../v1_0_0/interfaces/IFunctionsRouter.sol\";\nimport {IFunctionsClient} from \"../v1_0_0/interfaces/IFunctionsClient.sol\";\n\nimport {FunctionsRequest} from \"../v1_0_0/libraries/FunctionsRequest.sol\";\n\n/// @title The Chainlink Functions client contract\n/// @notice Contract developers can inherit this contract in order to make Chainlink Functions requests\nabstract contract FunctionsClient is IFunctionsClient {\n using FunctionsRequest for FunctionsRequest.Request;\n\n IFunctionsRouter internal immutable i_functionsRouter;\n\n event RequestSent(bytes32 indexed id);\n event RequestFulfilled(bytes32 indexed id);\n\n error OnlyRouterCanFulfill();\n\n constructor(address router) {\n i_functionsRouter = IFunctionsRouter(router);\n }\n\n /// @notice Sends a Chainlink Functions request\n /// @param data The CBOR encoded bytes data for a Functions request\n /// @param subscriptionId The subscription ID that will be charged to service the request\n /// @param callbackGasLimit the amount of gas that will be available for the fulfillment callback\n /// @return requestId The generated request ID for this request\n function _sendRequest(\n bytes memory data,\n uint64 subscriptionId,\n uint32 callbackGasLimit,\n bytes32 donId\n ) internal returns (bytes32) {\n bytes32 requestId = i_functionsRouter.sendRequest(\n subscriptionId,\n data,\n FunctionsRequest.REQUEST_DATA_VERSION,\n callbackGasLimit,\n donId\n );\n emit RequestSent(requestId);\n return requestId;\n }\n\n /// @notice User defined function to handle a response from the DON\n /// @param requestId The request ID, returned by sendRequest()\n /// @param response Aggregated response from the execution of the user's source code\n /// @param err Aggregated error from the execution of the user code or from the execution pipeline\n /// @dev Either response or error parameter will be set, but never both\n function _fulfillRequest(bytes32 requestId, bytes memory response, bytes memory err) internal virtual;\n\n /// @inheritdoc IFunctionsClient\n function handleOracleFulfillment(bytes32 requestId, bytes memory response, bytes memory err) external override {\n if (msg.sender != address(i_functionsRouter)) {\n revert OnlyRouterCanFulfill();\n }\n _fulfillRequest(requestId, response, err);\n emit RequestFulfilled(requestId);\n }\n}\n"},"lib/chainlink/contracts/src/v0.8/functions/v1_0_0/interfaces/IFunctionsRouter.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.19;\n\nimport {FunctionsResponse} from \"../libraries/FunctionsResponse.sol\";\n\n/// @title Chainlink Functions Router interface.\ninterface IFunctionsRouter {\n /// @notice The identifier of the route to retrieve the address of the access control contract\n /// The access control contract controls which accounts can manage subscriptions\n /// @return id - bytes32 id that can be passed to the \"getContractById\" of the Router\n function getAllowListId() external view returns (bytes32);\n\n /// @notice Set the identifier of the route to retrieve the address of the access control contract\n /// The access control contract controls which accounts can manage subscriptions\n function setAllowListId(bytes32 allowListId) external;\n\n /// @notice Get the flat fee (in Juels of LINK) that will be paid to the Router owner for operation of the network\n /// @return adminFee\n function getAdminFee() external view returns (uint72 adminFee);\n\n /// @notice Sends a request using the provided subscriptionId\n /// @param subscriptionId - A unique subscription ID allocated by billing system,\n /// a client can make requests from different contracts referencing the same subscription\n /// @param data - CBOR encoded Chainlink Functions request data, use FunctionsClient API to encode a request\n /// @param dataVersion - Gas limit for the fulfillment callback\n /// @param callbackGasLimit - Gas limit for the fulfillment callback\n /// @param donId - An identifier used to determine which route to send the request along\n /// @return requestId - A unique request identifier\n function sendRequest(\n uint64 subscriptionId,\n bytes calldata data,\n uint16 dataVersion,\n uint32 callbackGasLimit,\n bytes32 donId\n ) external returns (bytes32);\n\n /// @notice Sends a request to the proposed contracts\n /// @param subscriptionId - A unique subscription ID allocated by billing system,\n /// a client can make requests from different contracts referencing the same subscription\n /// @param data - CBOR encoded Chainlink Functions request data, use FunctionsClient API to encode a request\n /// @param dataVersion - Gas limit for the fulfillment callback\n /// @param callbackGasLimit - Gas limit for the fulfillment callback\n /// @param donId - An identifier used to determine which route to send the request along\n /// @return requestId - A unique request identifier\n function sendRequestToProposed(\n uint64 subscriptionId,\n bytes calldata data,\n uint16 dataVersion,\n uint32 callbackGasLimit,\n bytes32 donId\n ) external returns (bytes32);\n\n /// @notice Fulfill the request by:\n /// - calling back the data that the Oracle returned to the client contract\n /// - pay the DON for processing the request\n /// @dev Only callable by the Coordinator contract that is saved in the commitment\n /// @param response response data from DON consensus\n /// @param err error from DON consensus\n /// @param juelsPerGas - current rate of juels/gas\n /// @param costWithoutFulfillment - The cost of processing the request (in Juels of LINK ), without fulfillment\n /// @param transmitter - The Node that transmitted the OCR report\n /// @param commitment - The parameters of the request that must be held consistent between request and response time\n /// @return fulfillResult -\n /// @return callbackGasCostJuels -\n function fulfill(\n bytes memory response,\n bytes memory err,\n uint96 juelsPerGas,\n uint96 costWithoutFulfillment,\n address transmitter,\n FunctionsResponse.Commitment memory commitment\n ) external returns (FunctionsResponse.FulfillResult, uint96);\n\n /// @notice Validate requested gas limit is below the subscription max.\n /// @param subscriptionId subscription ID\n /// @param callbackGasLimit desired callback gas limit\n function isValidCallbackGasLimit(uint64 subscriptionId, uint32 callbackGasLimit) external view;\n\n /// @notice Get the current contract given an ID\n /// @param id A bytes32 identifier for the route\n /// @return contract The current contract address\n function getContractById(bytes32 id) external view returns (address);\n\n /// @notice Get the proposed next contract given an ID\n /// @param id A bytes32 identifier for the route\n /// @return contract The current or proposed contract address\n function getProposedContractById(bytes32 id) external view returns (address);\n\n /// @notice Return the latest proprosal set\n /// @return ids The identifiers of the contracts to update\n /// @return to The addresses of the contracts that will be updated to\n function getProposedContractSet() external view returns (bytes32[] memory, address[] memory);\n\n /// @notice Proposes one or more updates to the contract routes\n /// @dev Only callable by owner\n function proposeContractsUpdate(bytes32[] memory proposalSetIds, address[] memory proposalSetAddresses) external;\n\n /// @notice Updates the current contract routes to the proposed contracts\n /// @dev Only callable by owner\n function updateContracts() external;\n\n /// @dev Puts the system into an emergency stopped state.\n /// @dev Only callable by owner\n function pause() external;\n\n /// @dev Takes the system out of an emergency stopped state.\n /// @dev Only callable by owner\n function unpause() external;\n}\n"},"lib/chainlink/contracts/src/v0.8/functions/v1_0_0/interfaces/IFunctionsClient.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.19;\n\n/// @title Chainlink Functions client interface.\ninterface IFunctionsClient {\n /// @notice Chainlink Functions response handler called by the Functions Router\n /// during fullilment from the designated transmitter node in an OCR round.\n /// @param requestId The requestId returned by FunctionsClient.sendRequest().\n /// @param response Aggregated response from the request's source code.\n /// @param err Aggregated error either from the request's source code or from the execution pipeline.\n /// @dev Either response or error parameter will be set, but never both.\n function handleOracleFulfillment(bytes32 requestId, bytes memory response, bytes memory err) external;\n}\n"},"lib/chainlink/contracts/src/v0.8/functions/v1_0_0/libraries/FunctionsRequest.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.19;\n\nimport {CBOR} from \"../../../vendor/solidity-cborutils/v2.0.0/CBOR.sol\";\n\n/// @title Library for encoding the input data of a Functions request into CBOR\nlibrary FunctionsRequest {\n using CBOR for CBOR.CBORBuffer;\n\n uint16 public constant REQUEST_DATA_VERSION = 1;\n uint256 internal constant DEFAULT_BUFFER_SIZE = 256;\n\n enum Location {\n Inline, // Provided within the Request\n Remote, // Hosted through remote location that can be accessed through a provided URL\n DONHosted // Hosted on the DON's storage\n }\n\n enum CodeLanguage {\n JavaScript\n // In future version we may add other languages\n }\n\n struct Request {\n Location codeLocation; // ════════════╸ The location of the source code that will be executed on each node in the DON\n Location secretsLocation; // ═════════╸ The location of secrets that will be passed into the source code. *Only Remote secrets are supported\n CodeLanguage language; // ════════════╸ The coding language that the source code is written in\n string source; // ════════════════════╸ Raw source code for Request.codeLocation of Location.Inline, URL for Request.codeLocation of Location.Remote, or slot decimal number for Request.codeLocation of Location.DONHosted\n bytes encryptedSecretsReference; // ══╸ Encrypted URLs for Request.secretsLocation of Location.Remote (use addSecretsReference()), or CBOR encoded slotid+version for Request.secretsLocation of Location.DONHosted (use addDONHostedSecrets())\n string[] args; // ════════════════════╸ String arguments that will be passed into the source code\n bytes[] bytesArgs; // ════════════════╸ Bytes arguments that will be passed into the source code\n }\n\n error EmptySource();\n error EmptySecrets();\n error EmptyArgs();\n error NoInlineSecrets();\n\n /// @notice Encodes a Request to CBOR encoded bytes\n /// @param self The request to encode\n /// @return CBOR encoded bytes\n function encodeCBOR(Request memory self) internal pure returns (bytes memory) {\n CBOR.CBORBuffer memory buffer = CBOR.create(DEFAULT_BUFFER_SIZE);\n\n buffer.writeString(\"codeLocation\");\n buffer.writeUInt256(uint256(self.codeLocation));\n\n buffer.writeString(\"language\");\n buffer.writeUInt256(uint256(self.language));\n\n buffer.writeString(\"source\");\n buffer.writeString(self.source);\n\n if (self.args.length > 0) {\n buffer.writeString(\"args\");\n buffer.startArray();\n for (uint256 i = 0; i < self.args.length; ++i) {\n buffer.writeString(self.args[i]);\n }\n buffer.endSequence();\n }\n\n if (self.encryptedSecretsReference.length > 0) {\n if (self.secretsLocation == Location.Inline) {\n revert NoInlineSecrets();\n }\n buffer.writeString(\"secretsLocation\");\n buffer.writeUInt256(uint256(self.secretsLocation));\n buffer.writeString(\"secrets\");\n buffer.writeBytes(self.encryptedSecretsReference);\n }\n\n if (self.bytesArgs.length > 0) {\n buffer.writeString(\"bytesArgs\");\n buffer.startArray();\n for (uint256 i = 0; i < self.bytesArgs.length; ++i) {\n buffer.writeBytes(self.bytesArgs[i]);\n }\n buffer.endSequence();\n }\n\n return buffer.buf.buf;\n }\n\n /// @notice Initializes a Chainlink Functions Request\n /// @dev Sets the codeLocation and code on the request\n /// @param self The uninitialized request\n /// @param codeLocation The user provided source code location\n /// @param language The programming language of the user code\n /// @param source The user provided source code or a url\n function initializeRequest(\n Request memory self,\n Location codeLocation,\n CodeLanguage language,\n string memory source\n ) internal pure {\n if (bytes(source).length == 0) revert EmptySource();\n\n self.codeLocation = codeLocation;\n self.language = language;\n self.source = source;\n }\n\n /// @notice Initializes a Chainlink Functions Request\n /// @dev Simplified version of initializeRequest for PoC\n /// @param self The uninitialized request\n /// @param javaScriptSource The user provided JS code (must not be empty)\n function initializeRequestForInlineJavaScript(Request memory self, string memory javaScriptSource) internal pure {\n initializeRequest(self, Location.Inline, CodeLanguage.JavaScript, javaScriptSource);\n }\n\n /// @notice Adds Remote user encrypted secrets to a Request\n /// @param self The initialized request\n /// @param encryptedSecretsReference Encrypted comma-separated string of URLs pointing to off-chain secrets\n function addSecretsReference(Request memory self, bytes memory encryptedSecretsReference) internal pure {\n if (encryptedSecretsReference.length == 0) revert EmptySecrets();\n\n self.secretsLocation = Location.Remote;\n self.encryptedSecretsReference = encryptedSecretsReference;\n }\n\n /// @notice Adds DON-hosted secrets reference to a Request\n /// @param self The initialized request\n /// @param slotID Slot ID of the user's secrets hosted on DON\n /// @param version User data version (for the slotID)\n function addDONHostedSecrets(Request memory self, uint8 slotID, uint64 version) internal pure {\n CBOR.CBORBuffer memory buffer = CBOR.create(DEFAULT_BUFFER_SIZE);\n\n buffer.writeString(\"slotID\");\n buffer.writeUInt64(slotID);\n buffer.writeString(\"version\");\n buffer.writeUInt64(version);\n\n self.secretsLocation = Location.DONHosted;\n self.encryptedSecretsReference = buffer.buf.buf;\n }\n\n /// @notice Sets args for the user run function\n /// @param self The initialized request\n /// @param args The array of string args (must not be empty)\n function setArgs(Request memory self, string[] memory args) internal pure {\n if (args.length == 0) revert EmptyArgs();\n\n self.args = args;\n }\n\n /// @notice Sets bytes args for the user run function\n /// @param self The initialized request\n /// @param args The array of bytes args (must not be empty)\n function setBytesArgs(Request memory self, bytes[] memory args) internal pure {\n if (args.length == 0) revert EmptyArgs();\n\n self.bytesArgs = args;\n }\n}\n"},"lib/chainlink/contracts/src/v0.8/functions/v1_0_0/libraries/FunctionsResponse.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.19;\n\n/// @title Library of types that are used for fulfillment of a Functions request\nlibrary FunctionsResponse {\n // Used to send request information from the Router to the Coordinator\n struct RequestMeta {\n bytes data; // ══════════════════╸ CBOR encoded Chainlink Functions request data, use FunctionsRequest library to encode a request\n bytes32 flags; // ═══════════════╸ Per-subscription flags\n address requestingContract; // ══╗ The client contract that is sending the request\n uint96 availableBalance; // ═════╝ Common LINK balance of the subscription that is controlled by the Router to be used for all consumer requests.\n uint72 adminFee; // ═════════════╗ Flat fee (in Juels of LINK) that will be paid to the Router Owner for operation of the network\n uint64 subscriptionId; // ║ Identifier of the billing subscription that will be charged for the request\n uint64 initiatedRequests; // ║ The number of requests that have been started\n uint32 callbackGasLimit; // ║ The amount of gas that the callback to the consuming contract will be given\n uint16 dataVersion; // ══════════╝ The version of the structure of the CBOR encoded request data\n uint64 completedRequests; // ════╗ The number of requests that have successfully completed or timed out\n address subscriptionOwner; // ═══╝ The owner of the billing subscription\n }\n\n enum FulfillResult {\n FULFILLED, // 0\n USER_CALLBACK_ERROR, // 1\n INVALID_REQUEST_ID, // 2\n COST_EXCEEDS_COMMITMENT, // 3\n INSUFFICIENT_GAS_PROVIDED, // 4\n SUBSCRIPTION_BALANCE_INVARIANT_VIOLATION, // 5\n INVALID_COMMITMENT // 6\n }\n\n struct Commitment {\n bytes32 requestId; // ═════════════════╸ A unique identifier for a Chainlink Functions request\n address coordinator; // ═══════════════╗ The Coordinator contract that manages the DON that is servicing a request\n uint96 estimatedTotalCostJuels; // ════╝ The maximum cost in Juels (1e18) of LINK that will be charged to fulfill a request\n address client; // ════════════════════╗ The client contract that sent the request\n uint64 subscriptionId; // ║ Identifier of the billing subscription that will be charged for the request\n uint32 callbackGasLimit; // ═══════════╝ The amount of gas that the callback to the consuming contract will be given\n uint72 adminFee; // ═══════════════════╗ Flat fee (in Juels of LINK) that will be paid to the Router Owner for operation of the network\n uint72 donFee; // ║ Fee (in Juels of LINK) that will be split between Node Operators for servicing a request\n uint40 gasOverheadBeforeCallback; // ║ Represents the average gas execution cost before the fulfillment callback.\n uint40 gasOverheadAfterCallback; // ║ Represents the average gas execution cost after the fulfillment callback.\n uint32 timeoutTimestamp; // ═══════════╝ The timestamp at which a request will be eligible to be timed out\n }\n}\n"},"lib/chainlink/contracts/src/v0.8/vendor/solidity-cborutils/v2.0.0/CBOR.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\nimport \"../../@ensdomains/buffer/v0.1.0/Buffer.sol\";\n\n/**\n* @dev A library for populating CBOR encoded payload in Solidity.\n*\n* https://datatracker.ietf.org/doc/html/rfc7049\n*\n* The library offers various write* and start* methods to encode values of different types.\n* The resulted buffer can be obtained with data() method.\n* Encoding of primitive types is staightforward, whereas encoding of sequences can result\n* in an invalid CBOR if start/write/end flow is violated.\n* For the purpose of gas saving, the library does not verify start/write/end flow internally,\n* except for nested start/end pairs.\n*/\n\nlibrary CBOR {\n using Buffer for Buffer.buffer;\n\n struct CBORBuffer {\n Buffer.buffer buf;\n uint256 depth;\n }\n\n uint8 private constant MAJOR_TYPE_INT = 0;\n uint8 private constant MAJOR_TYPE_NEGATIVE_INT = 1;\n uint8 private constant MAJOR_TYPE_BYTES = 2;\n uint8 private constant MAJOR_TYPE_STRING = 3;\n uint8 private constant MAJOR_TYPE_ARRAY = 4;\n uint8 private constant MAJOR_TYPE_MAP = 5;\n uint8 private constant MAJOR_TYPE_TAG = 6;\n uint8 private constant MAJOR_TYPE_CONTENT_FREE = 7;\n\n uint8 private constant TAG_TYPE_BIGNUM = 2;\n uint8 private constant TAG_TYPE_NEGATIVE_BIGNUM = 3;\n\n uint8 private constant CBOR_FALSE = 20;\n uint8 private constant CBOR_TRUE = 21;\n uint8 private constant CBOR_NULL = 22;\n uint8 private constant CBOR_UNDEFINED = 23;\n\n function create(uint256 capacity) internal pure returns(CBORBuffer memory cbor) {\n Buffer.init(cbor.buf, capacity);\n cbor.depth = 0;\n return cbor;\n }\n\n function data(CBORBuffer memory buf) internal pure returns(bytes memory) {\n require(buf.depth == 0, \"Invalid CBOR\");\n return buf.buf.buf;\n }\n\n function writeUInt256(CBORBuffer memory buf, uint256 value) internal pure {\n buf.buf.appendUint8(uint8((MAJOR_TYPE_TAG << 5) | TAG_TYPE_BIGNUM));\n writeBytes(buf, abi.encode(value));\n }\n\n function writeInt256(CBORBuffer memory buf, int256 value) internal pure {\n if (value < 0) {\n buf.buf.appendUint8(\n uint8((MAJOR_TYPE_TAG << 5) | TAG_TYPE_NEGATIVE_BIGNUM)\n );\n writeBytes(buf, abi.encode(uint256(-1 - value)));\n } else {\n writeUInt256(buf, uint256(value));\n }\n }\n\n function writeUInt64(CBORBuffer memory buf, uint64 value) internal pure {\n writeFixedNumeric(buf, MAJOR_TYPE_INT, value);\n }\n\n function writeInt64(CBORBuffer memory buf, int64 value) internal pure {\n if(value >= 0) {\n writeFixedNumeric(buf, MAJOR_TYPE_INT, uint64(value));\n } else{\n writeFixedNumeric(buf, MAJOR_TYPE_NEGATIVE_INT, uint64(-1 - value));\n }\n }\n\n function writeBytes(CBORBuffer memory buf, bytes memory value) internal pure {\n writeFixedNumeric(buf, MAJOR_TYPE_BYTES, uint64(value.length));\n buf.buf.append(value);\n }\n\n function writeString(CBORBuffer memory buf, string memory value) internal pure {\n writeFixedNumeric(buf, MAJOR_TYPE_STRING, uint64(bytes(value).length));\n buf.buf.append(bytes(value));\n }\n\n function writeBool(CBORBuffer memory buf, bool value) internal pure {\n writeContentFree(buf, value ? CBOR_TRUE : CBOR_FALSE);\n }\n\n function writeNull(CBORBuffer memory buf) internal pure {\n writeContentFree(buf, CBOR_NULL);\n }\n\n function writeUndefined(CBORBuffer memory buf) internal pure {\n writeContentFree(buf, CBOR_UNDEFINED);\n }\n\n function startArray(CBORBuffer memory buf) internal pure {\n writeIndefiniteLengthType(buf, MAJOR_TYPE_ARRAY);\n buf.depth += 1;\n }\n\n function startFixedArray(CBORBuffer memory buf, uint64 length) internal pure {\n writeDefiniteLengthType(buf, MAJOR_TYPE_ARRAY, length);\n }\n\n function startMap(CBORBuffer memory buf) internal pure {\n writeIndefiniteLengthType(buf, MAJOR_TYPE_MAP);\n buf.depth += 1;\n }\n\n function startFixedMap(CBORBuffer memory buf, uint64 length) internal pure {\n writeDefiniteLengthType(buf, MAJOR_TYPE_MAP, length);\n }\n\n function endSequence(CBORBuffer memory buf) internal pure {\n writeIndefiniteLengthType(buf, MAJOR_TYPE_CONTENT_FREE);\n buf.depth -= 1;\n }\n\n function writeKVString(CBORBuffer memory buf, string memory key, string memory value) internal pure {\n writeString(buf, key);\n writeString(buf, value);\n }\n\n function writeKVBytes(CBORBuffer memory buf, string memory key, bytes memory value) internal pure {\n writeString(buf, key);\n writeBytes(buf, value);\n }\n\n function writeKVUInt256(CBORBuffer memory buf, string memory key, uint256 value) internal pure {\n writeString(buf, key);\n writeUInt256(buf, value);\n }\n\n function writeKVInt256(CBORBuffer memory buf, string memory key, int256 value) internal pure {\n writeString(buf, key);\n writeInt256(buf, value);\n }\n\n function writeKVUInt64(CBORBuffer memory buf, string memory key, uint64 value) internal pure {\n writeString(buf, key);\n writeUInt64(buf, value);\n }\n\n function writeKVInt64(CBORBuffer memory buf, string memory key, int64 value) internal pure {\n writeString(buf, key);\n writeInt64(buf, value);\n }\n\n function writeKVBool(CBORBuffer memory buf, string memory key, bool value) internal pure {\n writeString(buf, key);\n writeBool(buf, value);\n }\n\n function writeKVNull(CBORBuffer memory buf, string memory key) internal pure {\n writeString(buf, key);\n writeNull(buf);\n }\n\n function writeKVUndefined(CBORBuffer memory buf, string memory key) internal pure {\n writeString(buf, key);\n writeUndefined(buf);\n }\n\n function writeKVMap(CBORBuffer memory buf, string memory key) internal pure {\n writeString(buf, key);\n startMap(buf);\n }\n\n function writeKVArray(CBORBuffer memory buf, string memory key) internal pure {\n writeString(buf, key);\n startArray(buf);\n }\n\n function writeFixedNumeric(\n CBORBuffer memory buf,\n uint8 major,\n uint64 value\n ) private pure {\n if (value <= 23) {\n buf.buf.appendUint8(uint8((major << 5) | value));\n } else if (value <= 0xFF) {\n buf.buf.appendUint8(uint8((major << 5) | 24));\n buf.buf.appendInt(value, 1);\n } else if (value <= 0xFFFF) {\n buf.buf.appendUint8(uint8((major << 5) | 25));\n buf.buf.appendInt(value, 2);\n } else if (value <= 0xFFFFFFFF) {\n buf.buf.appendUint8(uint8((major << 5) | 26));\n buf.buf.appendInt(value, 4);\n } else {\n buf.buf.appendUint8(uint8((major << 5) | 27));\n buf.buf.appendInt(value, 8);\n }\n }\n\n function writeIndefiniteLengthType(CBORBuffer memory buf, uint8 major)\n private\n pure\n {\n buf.buf.appendUint8(uint8((major << 5) | 31));\n }\n\n function writeDefiniteLengthType(CBORBuffer memory buf, uint8 major, uint64 length)\n private\n pure\n {\n writeFixedNumeric(buf, major, length);\n }\n\n function writeContentFree(CBORBuffer memory buf, uint8 value) private pure {\n buf.buf.appendUint8(uint8((MAJOR_TYPE_CONTENT_FREE << 5) | value));\n }\n}"},"lib/chainlink/contracts/src/v0.8/vendor/@ensdomains/buffer/v0.1.0/Buffer.sol":{"content":"// SPDX-License-Identifier: BSD-2-Clause\npragma solidity ^0.8.4;\n\n/**\n* @dev A library for working with mutable byte buffers in Solidity.\n*\n* Byte buffers are mutable and expandable, and provide a variety of primitives\n* for appending to them. At any time you can fetch a bytes object containing the\n* current contents of the buffer. The bytes object should not be stored between\n* operations, as it may change due to resizing of the buffer.\n*/\nlibrary Buffer {\n /**\n * @dev Represents a mutable buffer. Buffers have a current value (buf) and\n * a capacity. The capacity may be longer than the current value, in\n * which case it can be extended without the need to allocate more memory.\n */\n struct buffer {\n bytes buf;\n uint capacity;\n }\n\n /**\n * @dev Initializes a buffer with an initial capacity.\n * @param buf The buffer to initialize.\n * @param capacity The number of bytes of space to allocate the buffer.\n * @return The buffer, for chaining.\n */\n function init(buffer memory buf, uint capacity) internal pure returns(buffer memory) {\n if (capacity % 32 != 0) {\n capacity += 32 - (capacity % 32);\n }\n // Allocate space for the buffer data\n buf.capacity = capacity;\n assembly {\n let ptr := mload(0x40)\n mstore(buf, ptr)\n mstore(ptr, 0)\n let fpm := add(32, add(ptr, capacity))\n if lt(fpm, ptr) {\n revert(0, 0)\n }\n mstore(0x40, fpm)\n }\n return buf;\n }\n\n /**\n * @dev Initializes a new buffer from an existing bytes object.\n * Changes to the buffer may mutate the original value.\n * @param b The bytes object to initialize the buffer with.\n * @return A new buffer.\n */\n function fromBytes(bytes memory b) internal pure returns(buffer memory) {\n buffer memory buf;\n buf.buf = b;\n buf.capacity = b.length;\n return buf;\n }\n\n function resize(buffer memory buf, uint capacity) private pure {\n bytes memory oldbuf = buf.buf;\n init(buf, capacity);\n append(buf, oldbuf);\n }\n\n /**\n * @dev Sets buffer length to 0.\n * @param buf The buffer to truncate.\n * @return The original buffer, for chaining..\n */\n function truncate(buffer memory buf) internal pure returns (buffer memory) {\n assembly {\n let bufptr := mload(buf)\n mstore(bufptr, 0)\n }\n return buf;\n }\n\n /**\n * @dev Appends len bytes of a byte string to a buffer. Resizes if doing so would exceed\n * the capacity of the buffer.\n * @param buf The buffer to append to.\n * @param data The data to append.\n * @param len The number of bytes to copy.\n * @return The original buffer, for chaining.\n */\n function append(buffer memory buf, bytes memory data, uint len) internal pure returns(buffer memory) {\n require(len <= data.length);\n\n uint off = buf.buf.length;\n uint newCapacity = off + len;\n if (newCapacity > buf.capacity) {\n resize(buf, newCapacity * 2);\n }\n\n uint dest;\n uint src;\n assembly {\n // Memory address of the buffer data\n let bufptr := mload(buf)\n // Length of existing buffer data\n let buflen := mload(bufptr)\n // Start address = buffer address + offset + sizeof(buffer length)\n dest := add(add(bufptr, 32), off)\n // Update buffer length if we're extending it\n if gt(newCapacity, buflen) {\n mstore(bufptr, newCapacity)\n }\n src := add(data, 32)\n }\n\n // Copy word-length chunks while possible\n for (; len >= 32; len -= 32) {\n assembly {\n mstore(dest, mload(src))\n }\n dest += 32;\n src += 32;\n }\n\n // Copy remaining bytes\n unchecked {\n uint mask = (256 ** (32 - len)) - 1;\n assembly {\n let srcpart := and(mload(src), not(mask))\n let destpart := and(mload(dest), mask)\n mstore(dest, or(destpart, srcpart))\n }\n }\n\n return buf;\n }\n\n /**\n * @dev Appends a byte string to a buffer. Resizes if doing so would exceed\n * the capacity of the buffer.\n * @param buf The buffer to append to.\n * @param data The data to append.\n * @return The original buffer, for chaining.\n */\n function append(buffer memory buf, bytes memory data) internal pure returns (buffer memory) {\n return append(buf, data, data.length);\n }\n\n /**\n * @dev Appends a byte to the buffer. Resizes if doing so would exceed the\n * capacity of the buffer.\n * @param buf The buffer to append to.\n * @param data The data to append.\n * @return The original buffer, for chaining.\n */\n function appendUint8(buffer memory buf, uint8 data) internal pure returns(buffer memory) {\n uint off = buf.buf.length;\n uint offPlusOne = off + 1;\n if (off >= buf.capacity) {\n resize(buf, offPlusOne * 2);\n }\n\n assembly {\n // Memory address of the buffer data\n let bufptr := mload(buf)\n // Address = buffer address + sizeof(buffer length) + off\n let dest := add(add(bufptr, off), 32)\n mstore8(dest, data)\n // Update buffer length if we extended it\n if gt(offPlusOne, mload(bufptr)) {\n mstore(bufptr, offPlusOne)\n }\n }\n\n return buf;\n }\n\n /**\n * @dev Appends len bytes of bytes32 to a buffer. Resizes if doing so would\n * exceed the capacity of the buffer.\n * @param buf The buffer to append to.\n * @param data The data to append.\n * @param len The number of bytes to write (left-aligned).\n * @return The original buffer, for chaining.\n */\n function append(buffer memory buf, bytes32 data, uint len) private pure returns(buffer memory) {\n uint off = buf.buf.length;\n uint newCapacity = len + off;\n if (newCapacity > buf.capacity) {\n resize(buf, newCapacity * 2);\n }\n\n unchecked {\n uint mask = (256 ** len) - 1;\n // Right-align data\n data = data >> (8 * (32 - len));\n assembly {\n // Memory address of the buffer data\n let bufptr := mload(buf)\n // Address = buffer address + sizeof(buffer length) + newCapacity\n let dest := add(bufptr, newCapacity)\n mstore(dest, or(and(mload(dest), not(mask)), data))\n // Update buffer length if we extended it\n if gt(newCapacity, mload(bufptr)) {\n mstore(bufptr, newCapacity)\n }\n }\n }\n return buf;\n }\n\n /**\n * @dev Appends a bytes20 to the buffer. Resizes if doing so would exceed\n * the capacity of the buffer.\n * @param buf The buffer to append to.\n * @param data The data to append.\n * @return The original buffer, for chhaining.\n */\n function appendBytes20(buffer memory buf, bytes20 data) internal pure returns (buffer memory) {\n return append(buf, bytes32(data), 20);\n }\n\n /**\n * @dev Appends a bytes32 to the buffer. Resizes if doing so would exceed\n * the capacity of the buffer.\n * @param buf The buffer to append to.\n * @param data The data to append.\n * @return The original buffer, for chaining.\n */\n function appendBytes32(buffer memory buf, bytes32 data) internal pure returns (buffer memory) {\n return append(buf, data, 32);\n }\n\n /**\n * @dev Appends a byte to the end of the buffer. Resizes if doing so would\n * exceed the capacity of the buffer.\n * @param buf The buffer to append to.\n * @param data The data to append.\n * @param len The number of bytes to write (right-aligned).\n * @return The original buffer.\n */\n function appendInt(buffer memory buf, uint data, uint len) internal pure returns(buffer memory) {\n uint off = buf.buf.length;\n uint newCapacity = len + off;\n if (newCapacity > buf.capacity) {\n resize(buf, newCapacity * 2);\n }\n\n uint mask = (256 ** len) - 1;\n assembly {\n // Memory address of the buffer data\n let bufptr := mload(buf)\n // Address = buffer address + sizeof(buffer length) + newCapacity\n let dest := add(bufptr, newCapacity)\n mstore(dest, or(and(mload(dest), not(mask)), data))\n // Update buffer length if we extended it\n if gt(newCapacity, mload(bufptr)) {\n mstore(bufptr, newCapacity)\n }\n }\n return buf;\n }\n}"}},"settings":{"remappings":["@openzeppelin/=lib/openzeppelin-contracts/","@chainlink/=lib/chainlink/","chainlink/=lib/chainlink/","erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/","forge-std/=lib/forge-std/src/","halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/","openzeppelin-contracts/=lib/openzeppelin-contracts/"],"optimizer":{"enabled":true,"runs":200},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"*":["abi","evm.bytecode.object","evm.bytecode.sourceMap","evm.bytecode.linkReferences","evm.deployedBytecode.object","evm.deployedBytecode.sourceMap","evm.deployedBytecode.linkReferences","evm.deployedBytecode.immutableReferences","evm.methodIdentifiers","metadata"]}},"evmVersion":"cancun","viaIR":true,"libraries":{}}}